diff options
133 files changed, 5524 insertions, 4033 deletions
diff --git a/bin/tests/test_containers.cpp b/bin/tests/test_containers.cpp index f8cc8ccd41..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 72d5c0ff7a..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 616356077e..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 597e088caf..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 683191fba2..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/bin/tests/test_gdscript.h b/bin/tests/test_gdscript.h index 225654e2a8..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 cba488a3da..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/bin/tests/test_gui.h b/bin/tests/test_gui.h index 5526320b0c..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 bf9851cf01..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 09b33e799e..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 a1eb2be19b..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 c839590ab9..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 8143a95d66..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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.h b/bin/tests/test_main.h index c8d571a7dd..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 b5041b265f..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/bin/tests/test_math.h b/bin/tests/test_math.h index 492c3a1837..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 68564c62b0..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 55608f6a0e..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 bafd78eda0..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 e95637a4e6..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 ce96f37f3f..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/bin/tests/test_physics.h b/bin/tests/test_physics.h index 5b6a54f2d4..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 c5fb734999..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/bin/tests/test_physics_2d.h b/bin/tests/test_physics_2d.h index e2eb1f4023..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 575caf2513..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 77e9603fe2..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 568699e5e6..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/bin/tests/test_render.h b/bin/tests/test_render.h index 6993e75b9f..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 e55ad3074f..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 f129fb224a..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 44cc117e02..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 91b87a2261..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/bin/tests/test_string.cpp b/bin/tests/test_string.cpp index fe7bf4d9cf..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/bin/tests/test_string.h b/bin/tests/test_string.h index 7b3cd9a019..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-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* 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 84c3687b08..4fd33e3a55 100644 --- a/core/command_queue_mt.h +++ b/core/command_queue_mt.h @@ -983,7 +983,7 @@ public: void flush_all() { - ERR_FAIL_COND(sync); + //ERR_FAIL_COND(sync); lock(); while (true) { bool exit = !flush_one(); diff --git a/core/globals.cpp b/core/globals.cpp index 17b139d1ad..1e60854f28 100644 --- a/core/globals.cpp +++ b/core/globals.cpp @@ -638,7 +638,9 @@ static Variant _decode_variant(const String& p_string) { InputEvent ie; ie.type=InputEvent::JOYSTICK_MOTION; ie.device=params[0].to_int(); - ie.joy_motion.axis=params[1].to_int(); + int axis = params[1].to_int();; + ie.joy_motion.axis=axis>>1; + ie.joy_motion.axis_value=axis&1?1:-1; return ie; } @@ -1029,7 +1031,7 @@ static String _encode_variant(const Variant& p_variant) { } break; case InputEvent::JOYSTICK_MOTION: { - return "jaxis("+itos(ev.device)+", "+itos(ev.joy_motion.axis)+")"; + return "jaxis("+itos(ev.device)+", "+itos(ev.joy_motion.axis * 2 + (ev.joy_motion.axis_value<0?0:1))+")"; } break; default: { diff --git a/core/input_map.cpp b/core/input_map.cpp index 6feec9af95..d4560a1e1b 100644 --- a/core/input_map.cpp +++ b/core/input_map.cpp @@ -204,6 +204,64 @@ bool InputMap::event_is_action(const InputEvent& p_event, const StringName& p_ac return _find_event(E->get().inputs,p_event)!=NULL; } +bool InputMap::event_is_joy_motion_action_pressed(const InputEvent& p_event) const { + + ERR_FAIL_COND_V(p_event.type!=InputEvent::JOYSTICK_MOTION,false); + bool pressed=false; + + //this could be optimized by having a separate list of joymotions? + + for (Map<StringName, Action>::Element *A=input_map.front();A;A=A->next()) { + + for (List<InputEvent>::Element *E=A->get().inputs.front();E;E=E->next()) { + + const InputEvent& e=E->get(); + if(e.type!=p_event.type) + continue; + if (e.type!=InputEvent::KEY && e.device!=p_event.device) + continue; + + switch(p_event.type) { + + case InputEvent::KEY: { + + if (e.key.scancode==p_event.key.scancode && e.key.mod == p_event.key.mod) + return e.key.pressed; + + } break; + case InputEvent::JOYSTICK_BUTTON: { + + if (e.joy_button.button_index==p_event.joy_button.button_index) { + return e.joy_button.pressed; + } + + } break; + case InputEvent::MOUSE_BUTTON: { + + if (e.mouse_button.button_index==p_event.mouse_button.button_index) { + return e.mouse_button.pressed; + } + + } break; + case InputEvent::JOYSTICK_MOTION: { + + if (e.joy_motion.axis==p_event.joy_motion.axis) { + if ( + (e.joy_motion.axis_value * p_event.joy_motion.axis_value >0) && //same axis + ABS(e.joy_motion.axis_value)>0.5 && ABS(p_event.joy_motion.axis_value)>0.5 ) + pressed=true; + } + + } break; + } + + } + } + + return pressed; + +} + void InputMap::load_from_globals() { input_map.clear();; diff --git a/core/input_map.h b/core/input_map.h index c803d5bf04..5cd1e41922 100644 --- a/core/input_map.h +++ b/core/input_map.h @@ -68,6 +68,7 @@ public: const List<InputEvent> *get_action_list(const StringName& p_action); bool event_is_action(const InputEvent& p_event, const StringName& p_action) const; + bool event_is_joy_motion_action_pressed(const InputEvent& p_event) const; void load_from_globals(); diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp index 2f0c1a6512..20d9db3375 100644 --- a/core/math/math_funcs.cpp +++ b/core/math/math_funcs.cpp @@ -207,9 +207,15 @@ double Math::ceil(double p_x) { int Math::decimals(double p_step) { int max=4; + double llimit = Math::pow(0.1,max); + double ulimit = 1.0-llimit; int i=0; - while( (p_step - Math::floor(p_step)) != 0.0 && max) { - + while( max) { + + float d = absf(p_step) - Math::floor(absf(p_step)); + + if (d<llimit || d>ulimit) + break; p_step*=10.0; max--; i++; diff --git a/core/message_queue.cpp b/core/message_queue.cpp index 8f2dd622ad..c69021f4f0 100644 --- a/core/message_queue.cpp +++ b/core/message_queue.cpp @@ -28,7 +28,7 @@ /*************************************************************************/ #include "message_queue.h" #include "globals.h" - +#include "script_language.h" MessageQueue *MessageQueue::singleton=NULL; MessageQueue *MessageQueue::get_singleton() { @@ -36,26 +36,11 @@ MessageQueue *MessageQueue::get_singleton() { return singleton; } -Error MessageQueue::push_call(ObjectID p_id, const StringName& p_method, VARIANT_ARG_DECLARE) { +Error MessageQueue::push_call(ObjectID p_id,const StringName& p_method,const Variant** p_args,int p_argcount,bool p_show_error) { _THREAD_SAFE_METHOD_ - uint8_t room_needed=sizeof(Message); - int args=0; - if (p_arg5.get_type()!=Variant::NIL) - args=5; - else if (p_arg4.get_type()!=Variant::NIL) - args=4; - else if (p_arg3.get_type()!=Variant::NIL) - args=3; - else if (p_arg2.get_type()!=Variant::NIL) - args=2; - else if (p_arg1.get_type()!=Variant::NIL) - args=1; - else - args=0; - - room_needed+=sizeof(Variant)*args; + int room_needed=sizeof(Message)+sizeof(Variant)*p_argcount; if ((buffer_end+room_needed) >= buffer_size) { String type; @@ -65,53 +50,43 @@ Error MessageQueue::push_call(ObjectID p_id, const StringName& p_method, VARIANT statistics(); } + ERR_FAIL_COND_V( (buffer_end+room_needed) >= buffer_size , ERR_OUT_OF_MEMORY ); Message * msg = memnew_placement( &buffer[ buffer_end ], Message ); - msg->args=args; + msg->args=p_argcount; msg->instance_ID=p_id; msg->target=p_method; msg->type=TYPE_CALL; - buffer_end+=sizeof(Message); + if (p_show_error) + msg->type|=FLAG_SHOW_ERROR; + buffer_end+=sizeof(Message); - if (args>=1) { + for(int i=0;i<p_argcount;i++) { Variant * v = memnew_placement( &buffer[ buffer_end ], Variant ); buffer_end+=sizeof(Variant); - *v=p_arg1; - } - - if (args>=2) { + *v=*p_args[i]; - Variant * v = memnew_placement( &buffer[ buffer_end ], Variant ); - buffer_end+=sizeof(Variant); - *v=p_arg2; } - if (args>=3) { + return OK; +} - Variant * v = memnew_placement( &buffer[ buffer_end ], Variant ); - buffer_end+=sizeof(Variant); - *v=p_arg3; +Error MessageQueue::push_call(ObjectID p_id, const StringName& p_method, VARIANT_ARG_DECLARE) { - } + VARIANT_ARGPTRS; - if (args>=4) { + int argc=0; - Variant * v = memnew_placement( &buffer[ buffer_end ], Variant ); - buffer_end+=sizeof(Variant); - *v=p_arg4; + for(int i=0;i<VARIANT_ARG_MAX;i++) { + if (argptr[i]->get_type()==Variant::NIL) + break; + argc++; } - if (args>=5) { + return push_call(p_id,p_method,argptr,argc,false); - Variant * v = memnew_placement( &buffer[ buffer_end ], Variant ); - buffer_end+=sizeof(Variant); - *v=p_arg5; - } - - - return OK; } Error MessageQueue::push_set(ObjectID p_id, const StringName& p_prop, const Variant& p_value) { @@ -212,7 +187,7 @@ void MessageQueue::statistics() { if (target!=NULL) { - switch(message->type) { + switch(message->type&FLAG_MASK) { case TYPE_CALL: { @@ -251,7 +226,7 @@ void MessageQueue::statistics() { read_pos+=sizeof(Message); - if (message->type!=TYPE_NOTIFICATION) + if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION) read_pos+=sizeof(Variant)*message->args; } @@ -322,6 +297,26 @@ int MessageQueue::get_max_buffer_usage() const { return buffer_max_used; } + +void MessageQueue::_call_function(Object* p_target, const StringName& p_func, const Variant *p_args, int p_argcount,bool p_show_error) { + + const Variant **argptrs=NULL; + if (p_argcount) { + argptrs = (const Variant**)alloca(sizeof(Variant*)*p_argcount); + for(int i=0;i<p_argcount;i++) { + argptrs[i]=&p_args[i]; + } + } + + Variant::CallError ce; + p_target->call(p_func,argptrs,p_argcount,ce); + if (p_show_error && ce.error!=Variant::CallError::CALL_OK) { + + ERR_PRINTS("Error calling deferred method: "+Variant::get_call_error_text(p_target,p_func,argptrs,p_argcount,ce)); + + } +} + void MessageQueue::flush() { @@ -347,7 +342,7 @@ void MessageQueue::flush() { if (target!=NULL) { - switch(message->type) { + switch(message->type&FLAG_MASK) { case TYPE_CALL: { Variant *args= (Variant*)(message+1); @@ -355,12 +350,7 @@ void MessageQueue::flush() { // messages don't expect a return value - target->call( message->target, - (message->args>=1) ? args[0] : Variant(), - (message->args>=2) ? args[1] : Variant(), - (message->args>=3) ? args[2] : Variant(), - (message->args>=4) ? args[3] : Variant(), - (message->args>=5) ? args[4] : Variant() ); + _call_function(target,message->target,args,message->args,message->type&FLAG_SHOW_ERROR); for(int i=0;i<message->args;i++) { args[i].~Variant(); @@ -386,7 +376,7 @@ void MessageQueue::flush() { } uint32_t advance = sizeof(Message); - if (message->type!=TYPE_NOTIFICATION) + if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION) advance+=sizeof(Variant)*message->args; message->~Message(); @@ -423,14 +413,14 @@ MessageQueue::~MessageQueue() { Message *message = (Message*)&buffer[ read_pos ]; Variant *args= (Variant*)(message+1); int argc = message->args; - if (message->type!=TYPE_NOTIFICATION) { + if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION) { for (int i=0;i<argc;i++) args[i].~Variant(); } message->~Message(); read_pos+=sizeof(Message); - if (message->type!=TYPE_NOTIFICATION) + if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION) read_pos+=sizeof(Variant)*message->args; } diff --git a/core/message_queue.h b/core/message_queue.h index b6b74d2bd2..6a3ec79732 100644 --- a/core/message_queue.h +++ b/core/message_queue.h @@ -46,7 +46,10 @@ class MessageQueue { enum { TYPE_CALL, TYPE_NOTIFICATION, - TYPE_SET + TYPE_SET, + FLAG_SHOW_ERROR=1<<14, + FLAG_MASK=FLAG_SHOW_ERROR-1 + }; struct Message { @@ -65,12 +68,14 @@ class MessageQueue { uint32_t buffer_max_used; uint32_t buffer_size; + void _call_function(Object* p_target,const StringName& p_func,const Variant *p_args,int p_argcount,bool p_show_error); static MessageQueue *singleton; public: static MessageQueue *get_singleton(); + Error push_call(ObjectID p_id,const StringName& p_method,const Variant** p_args,int p_argcount,bool p_show_error=false); Error push_call(ObjectID p_id, const StringName& p_method, VARIANT_ARG_LIST); Error push_notification(ObjectID p_id, int p_notification); Error push_set(ObjectID p_id, const StringName& p_prop, const Variant& p_value); diff --git a/core/object.cpp b/core/object.cpp index ad9fdf73b9..c92fc35b24 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -512,17 +512,10 @@ Variant Object::_call_deferred_bind(const Variant** p_args, int p_argcount, Vari r_error.error=Variant::CallError::CALL_OK; - StringName signal = *p_args[0]; - - Variant v[VARIANT_ARG_MAX]; - - - for(int i=0;i<MIN(5,p_argcount-1);i++) { + StringName method = *p_args[0]; - v[i]=*p_args[i+1]; - } + MessageQueue::get_singleton()->push_call(get_instance_ID(),method,&p_args[1],p_argcount-1); - call_deferred(signal,v[0],v[1],v[2],v[3],v[4]); return Variant(); } @@ -839,6 +832,8 @@ void Object::call_multilevel(const StringName& p_name, VARIANT_ARG_DECLARE) { Variant Object::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) { + r_error.error=Variant::CallError::CALL_OK; + if (p_method==CoreStringNames::get_singleton()->_free) { //free must be here, before anything, always ready #ifdef DEBUG_ENABLED @@ -1130,21 +1125,22 @@ Variant Object::_emit_signal(const Variant** p_args, int p_argcount, Variant::Ca StringName signal = *p_args[0]; - Variant v[VARIANT_ARG_MAX]; - - for(int i=0;i<MIN(5,p_argcount-1);i++) { + const Variant**args=NULL; - v[i]=*p_args[i+1]; + int argc=p_argcount-1; + if (argc) { + args=&p_args[1]; } - emit_signal(signal,v[0],v[1],v[2],v[3],v[4]); + emit_signal(signal,args,argc); + return Variant(); -} +} -void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) { +void Object::emit_signal(const StringName& p_name,const Variant** p_args,int p_argcount) { if (_block_signals) return; //no emit, signals blocked @@ -1167,10 +1163,12 @@ void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) { OBJ_DEBUG_LOCK + Vector<const Variant*> bind_mem; + + for(int i=0;i<ssize;i++) { const Connection &c = slot_map.getv(i).conn; - VARIANT_ARGPTRS Object *target; #ifdef DEBUG_ENABLED @@ -1181,21 +1179,37 @@ void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) { #endif - int bind_count=c.binds.size(); - int bind=0; + const Variant **args=p_args; + int argc=p_argcount; - for(int i=0;bind < bind_count && i<VARIANT_ARG_MAX;i++) { + if (c.binds.size()) { + //handle binds + bind_mem.resize(p_argcount+c.binds.size()); - if (argptr[i]->get_type()==Variant::NIL) { - argptr[i]=&c.binds[bind]; - bind++; + for(int j=0;j<p_argcount;j++) { + bind_mem[j]=p_args[j]; + } + for(int j=0;j<c.binds.size();j++) { + bind_mem[p_argcount+j]=&c.binds[j]; } + + args=bind_mem.ptr(); + argc=bind_mem.size(); } if (c.flags&CONNECT_DEFERRED) { - MessageQueue::get_singleton()->push_call(target->get_instance_ID(),c.method,VARIANT_ARGPTRS_PASS); + MessageQueue::get_singleton()->push_call(target->get_instance_ID(),c.method,args,argc,true); } else { - target->call( c.method, VARIANT_ARGPTRS_PASS ); + Variant::CallError ce; + target->call( c.method, args, argc,ce ); + if (ce.error!=Variant::CallError::CALL_OK) { + + if (ce.error==Variant::CallError::CALL_ERROR_INVALID_METHOD && !ObjectTypeDB::type_exists( target->get_type_name() ) ) { + //most likely object is not initialized yet, do not throw error. + } else { + ERR_PRINTS("Error calling method from signal '"+String(p_name)+"': "+Variant::get_call_error_text(target,c.method,args,argc,ce)); + } + } } if (c.flags&CONNECT_ONESHOT) { @@ -1208,57 +1222,29 @@ void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) { } -#if 0 - - //old (deprecated and dangerous code) - s->lock++; - for( Map<Signal::Target,Signal::Slot>::Element *E = s->slot_map.front();E;E=E->next() ) { - - const Signal::Target& t = E->key(); - const Signal::Slot& s = E->get(); - const Connection &c = s.cE->get(); - VARIANT_ARGPTRS + while (!disconnect_data.empty()) { - int bind_count=c.binds.size(); - int bind=0; + const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get(); + disconnect(dd.signal,dd.target,dd.method); + disconnect_data.pop_front(); + } - for(int i=0;bind < bind_count && i<VARIANT_ARG_MAX;i++) { +} - if (argptr[i]->get_type()==Variant::NIL) { - argptr[i]=&c.binds[bind]; - bind++; - } - } +void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) { - if (c.flags&CONNECT_DEFERRED) { - MessageQueue::get_singleton()->push_call(t._id,t.method,VARIANT_ARGPTRS_PASS); - } else { - Object *obj = ObjectDB::get_instance(t._id); - ERR_CONTINUE(!obj); //yeah this should always be here - obj->call( t.method, VARIANT_ARGPTRS_PASS ); - } + VARIANT_ARGPTRS; - if (c.flags&CONNECT_ONESHOT) { - _ObjectSignalDisconnectData dd; - dd.signal=p_name; - dd.target=ObjectDB::get_instance(t._id); - dd.method=t.method; - disconnect_data.push_back(dd); - } + int argc=0; + for(int i=0;i<VARIANT_ARG_MAX;i++) { + if (argptr[i]->get_type()==Variant::NIL) + break; + argc++; } - - - s->lock--; -#endif - while (!disconnect_data.empty()) { - - const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get(); - disconnect(dd.signal,dd.target,dd.method); - disconnect_data.pop_front(); - } + emit_signal(p_name,argptr,argc); } diff --git a/core/object.h b/core/object.h index 38a91d7898..dcebf9b2a2 100644 --- a/core/object.h +++ b/core/object.h @@ -593,6 +593,7 @@ public: void add_user_signal(const MethodInfo& p_signal); void emit_signal(const StringName& p_name,VARIANT_ARG_LIST); + void emit_signal(const StringName& p_name, const Variant** p_args, int p_argcount); void get_signal_list(List<MethodInfo> *p_signals ) const; void get_signal_connection_list(const StringName& p_signal,List<Connection> *p_connections) const; void get_all_signal_connections(List<Connection> *p_connections) const; diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 25b10a76d3..2f39567a7e 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -156,6 +156,7 @@ bool InputEvent::is_pressed() const { case MOUSE_BUTTON: return mouse_button.pressed; case JOYSTICK_BUTTON: return joy_button.pressed; case SCREEN_TOUCH: return screen_touch.pressed; + case JOYSTICK_MOTION: return InputMap::get_singleton()->event_is_joy_motion_action_pressed(*this); case ACTION: return action.pressed; default: {} } diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 299572fbff..b56ff4c0e1 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -30,7 +30,7 @@ #include "os/os.h" #include "io/ip.h" #include "globals.h" - +#include "os/input.h" void ScriptDebuggerRemote::_send_video_memory() { List<ResourceUsage> usage; @@ -135,6 +135,10 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) { packet_peer_stream->put_var(p_can_continue); packet_peer_stream->put_var(p_script->debug_get_error()); + Input::MouseMode mouse_mode=Input::get_singleton()->get_mouse_mode(); + if (mouse_mode!=Input::MOUSE_MODE_VISIBLE) + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + while(true) { @@ -296,6 +300,9 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) { packet_peer_stream->put_var("debug_exit"); packet_peer_stream->put_var(0); + if (mouse_mode!=Input::MOUSE_MODE_VISIBLE) + Input::get_singleton()->set_mouse_mode(mouse_mode); + } diff --git a/core/script_language.h b/core/script_language.h index a179949c19..3138c88e8e 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -98,6 +98,7 @@ public: virtual bool has_script_signal(const StringName& p_signal) const=0; virtual void get_script_signal_list(List<MethodInfo> *r_signals) const=0; + virtual bool get_property_default_value(const StringName& p_property,Variant& r_value) const=0; virtual void update_exports() {} //editor tool diff --git a/core/ustring.cpp b/core/ustring.cpp index c93fb80ca8..21c0d78fdb 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -1636,12 +1636,16 @@ int64_t String::to_int64() const { return integer*sign; } -int String::to_int(const char* p_str) { +int String::to_int(const char* p_str,int p_len) { int to=0; - while(p_str[to]!=0 && p_str[to]!='.') - to++; + if (p_len>=0) + to=p_len; + else { + while(p_str[to]!=0 && p_str[to]!='.') + to++; + } int integer=0; diff --git a/core/ustring.h b/core/ustring.h index 4c76b8e863..2b967d368a 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -144,7 +144,7 @@ public: int to_int() const; int64_t to_int64() const; - static int to_int(const char* p_str); + static int to_int(const char* p_str, int p_len=-1); static double to_double(const char* p_str); static double to_double(const CharType* p_str, const CharType **r_end=NULL); static int64_t to_int(const CharType* p_str,int p_len=-1); diff --git a/core/variant.cpp b/core/variant.cpp index ab560e0d45..3bd8d80528 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -706,6 +706,17 @@ bool Variant::operator==(const Variant& p_variant) const { } +bool Variant::operator!=(const Variant& p_variant) const { + + if (type!=p_variant.type) //evaluation of operator== needs to be more strict + return true; + bool v; + Variant r; + evaluate(OP_NOT_EQUAL,*this,p_variant,r,v); + return r; + +} + bool Variant::operator<(const Variant& p_variant) const { if (type!=p_variant.type) //if types differ, then order by type first return type<p_variant.type; @@ -2981,3 +2992,32 @@ String Variant::get_construct_string() const { return vars; } + +String Variant::get_call_error_text(Object* p_base, const StringName& p_method,const Variant** p_argptrs,int p_argcount,const Variant::CallError &ce) { + + + String err_text; + + if (ce.error==Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) { + int errorarg=ce.argument; + err_text="Cannot convert argument "+itos(errorarg+1)+" from "+Variant::get_type_name(p_argptrs[errorarg]->get_type())+" to "+Variant::get_type_name(ce.expected)+"."; + } else if (ce.error==Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { + err_text="Expected "+itos(ce.argument)+" arguments."; + } else if (ce.error==Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { + err_text="Expected "+itos(ce.argument)+" arguments."; + } else if (ce.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) { + err_text="Method not found."; + } else if (ce.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) { + err_text="Instance is null"; + } else if (ce.error==Variant::CallError::CALL_OK){ + return "Call OK"; + } + + String class_name = p_base->get_type(); + Ref<Script> script = p_base->get_script(); + if (script.is_valid() && script->get_path().is_resource_file()) { + + class_name+="("+script->get_path().get_file()+")"; + } + return "'"+class_name+"::"+String(p_method)+"': "+err_text; +} diff --git a/core/variant.h b/core/variant.h index 05bb5a7328..b58c781bdd 100644 --- a/core/variant.h +++ b/core/variant.h @@ -390,6 +390,9 @@ 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 String get_call_error_text(Object* p_base, const StringName& p_method,const Variant** p_argptrs,int p_argcount,const Variant::CallError &ce); + static Variant construct(const Variant::Type,const Variant** p_args,int p_argcount,CallError &r_error,bool p_strict=true); void get_method_list(List<MethodInfo> *p_list) const; @@ -411,6 +414,7 @@ public: //argsVariant call() bool operator==(const Variant& p_variant) const; + bool operator!=(const Variant& p_variant) const; bool operator<(const Variant& p_variant) const; uint32_t hash() const; diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 9218406e0f..204a00e1d5 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -1003,7 +1003,7 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid) return; } - *str = str->substr(0,idx-1)+chr+str->substr(idx+1,str->length()); + *str = str->substr(0,idx)+chr+str->substr(idx+1,str->length()); valid=true; return; @@ -1364,7 +1364,7 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid) valid=true; v->b=float(p_value)/255.0; return; - } else if (*str=="a8" ) { + } else if (*str=="a8" ) {\ valid=true; v->a=float(p_value)/255.0; return; diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp index 3c8c43f5b3..9f2727d33d 100644 --- a/core/variant_parser.cpp +++ b/core/variant_parser.cpp @@ -1072,8 +1072,24 @@ Error VariantParser::parse_value(Token& token,Variant &value,Stream *p_stream,in ie.joy_motion.axis = token.value; get_token(p_stream,token,line,r_err_str); + + if (token.type!=TK_COMMA) { + r_err_str="Expected ',' after axis index"; + return ERR_PARSE_ERROR; + } + + get_token(p_stream,token,line,r_err_str); + if (token.type!=TK_NUMBER) { + r_err_str="Expected axis sign"; + return ERR_PARSE_ERROR; + } + + ie.joy_motion.axis_value = token.value; + + get_token(p_stream,token,line,r_err_str); + if (token.type!=TK_PARENTHESIS_CLOSE) { - r_err_str="Expected ')'"; + r_err_str="Expected ')' for jaxis"; return ERR_PARSE_ERROR; } @@ -1339,7 +1355,9 @@ Error VariantParser::parse_value(Token& token,Variant &value,Stream *p_stream,in InputEvent ie; ie.type=InputEvent::JOYSTICK_MOTION; ie.device=params[0].to_int(); - ie.joy_motion.axis=params[1].to_int(); + int axis=params[1].to_int(); + ie.joy_motion.axis=axis>>1; + ie.joy_motion.axis_value=axis&1?1:-1; value= ie; diff --git a/demos/misc/joysticks/diagram.png b/demos/misc/joysticks/diagram.png Binary files differnew file mode 100644 index 0000000000..3f8ba1f973 --- /dev/null +++ b/demos/misc/joysticks/diagram.png diff --git a/demos/misc/joysticks/engine.cfg b/demos/misc/joysticks/engine.cfg index 71ac91000e..79cda1eeb4 100644 --- a/demos/misc/joysticks/engine.cfg +++ b/demos/misc/joysticks/engine.cfg @@ -6,5 +6,5 @@ icon="res://icon.png" [display] -width=260 +width=550 height=300 diff --git a/demos/misc/joysticks/indicators.png b/demos/misc/joysticks/indicators.png Binary files differnew file mode 100644 index 0000000000..90fee48498 --- /dev/null +++ b/demos/misc/joysticks/indicators.png diff --git a/demos/misc/joysticks/joysticks.gd b/demos/misc/joysticks/joysticks.gd index 7add88573d..f5bc1bddad 100644 --- a/demos/misc/joysticks/joysticks.gd +++ b/demos/misc/joysticks/joysticks.gd @@ -14,8 +14,9 @@ var cur_joy var axis_value var btn_state +const DEADZONE = 0.2 -func _input(event): +func _fixed_process(delta): # Get the joystick device number from the spinbox joy_num = get_node("joy_num").get_value() @@ -29,15 +30,24 @@ func _input(event): axis_value = Input.get_joy_axis(joy_num, axis) get_node("axis_prog" + str(axis)).set_value(100*axis_value) get_node("axis_val" + str(axis)).set_text(str(axis_value)) + if (axis < 4): + if (abs(axis_value) < DEADZONE): + get_node("diagram/axes/" + str(axis) + "+").hide() + get_node("diagram/axes/" + str(axis) + "-").hide() + elif (axis_value > 0): + get_node("diagram/axes/" + str(axis) + "+").show() + else: + get_node("diagram/axes/" + str(axis) + "-").show() # Loop through the buttons and highlight the ones that are pressed - for btn in range(0, 17): + for btn in range(0, 16): btn_state = 1 if (Input.is_joy_button_pressed(joy_num, btn)): get_node("btn" + str(btn)).add_color_override("font_color", Color(1, 1, 1, 1)) + get_node("diagram/buttons/" + str(btn)).show() else: get_node("btn" + str(btn)).add_color_override("font_color", Color(0.2, 0.1, 0.3, 1)) - + get_node("diagram/buttons/" + str(btn)).hide() func _ready(): - set_process_input(true) + set_fixed_process(true) diff --git a/demos/misc/joysticks/joysticks.scn b/demos/misc/joysticks/joysticks.scn Binary files differindex b78bccbf33..3e0f326a0d 100644 --- a/demos/misc/joysticks/joysticks.scn +++ b/demos/misc/joysticks/joysticks.scn diff --git a/demos/misc/joysticks/jsdiagram.xscn b/demos/misc/joysticks/jsdiagram.xscn new file mode 100644 index 0000000000..537ad30278 --- /dev/null +++ b/demos/misc/joysticks/jsdiagram.xscn @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<resource_file type="PackedScene" subresource_count="3" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build"> + <ext_resource path="res://indicators.png" type="Texture" index="1"></ext_resource> + <ext_resource path="res://diagram.png" type="Texture" index="0"></ext_resource> + <main_resource> + <dictionary name="_bundled" shared="false"> + <string> "conn_count" </string> + <int> 0 </int> + <string> "conns" </string> + <int_array len="0"> </int_array> + <string> "editable_instances" </string> + <array len="0" shared="false"> + </array> + <string> "names" </string> + <string_array len="37"> + <string> "diagram" </string> + <string> "transform/pos" </string> + <string> "transform/scale" </string> + <string> "texture" </string> + <string> "__meta__" </string> + <string> "Sprite" </string> + <string> "buttons" </string> + <string> "Node2D" </string> + <string> "0" </string> + <string> "region" </string> + <string> "region_rect" </string> + <string> "1" </string> + <string> "2" </string> + <string> "3" </string> + <string> "4" </string> + <string> "5" </string> + <string> "6" </string> + <string> "flip_h" </string> + <string> "7" </string> + <string> "8" </string> + <string> "9" </string> + <string> "10" </string> + <string> "11" </string> + <string> "12" </string> + <string> "13" </string> + <string> "flip_v" </string> + <string> "14" </string> + <string> "15" </string> + <string> "axes" </string> + <string> "0-" </string> + <string> "0+" </string> + <string> "1-" </string> + <string> "1+" </string> + <string> "3-" </string> + <string> "3+" </string> + <string> "2-" </string> + <string> "2+" </string> + </string_array> + <string> "node_count" </string> + <int> 27 </int> + <string> "node_paths" </string> + <array len="0" shared="false"> + </array> + <string> "nodes" </string> + <int_array len="453"> -1, -1, 5, 0, -1, 4, 1, 0, 2, 1, 3, 2, 4, 3, 0, 0, 0, 7, 6, -1, 1, 4, 4, 0, 1, 0, 5, 8, -1, 5, 1, 5, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 11, -1, 5, 1, 10, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 12, -1, 5, 1, 11, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 13, -1, 5, 1, 12, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 14, -1, 5, 1, 13, 2, 14, 3, 7, 9, 8, 10, 15, 0, 1, 0, 5, 15, -1, 5, 1, 16, 2, 14, 3, 7, 9, 8, 10, 15, 0, 1, 0, 5, 16, -1, 6, 1, 17, 2, 18, 3, 7, 17, 8, 9, 8, 10, 19, 0, 1, 0, 5, 18, -1, 5, 1, 20, 2, 18, 3, 7, 9, 8, 10, 19, 0, 1, 0, 5, 19, -1, 5, 1, 21, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 20, -1, 5, 1, 22, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 21, -1, 5, 1, 23, 2, 24, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 22, -1, 5, 1, 25, 2, 24, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 23, -1, 5, 1, 26, 2, 6, 3, 7, 9, 8, 10, 27, 0, 1, 0, 5, 24, -1, 6, 1, 28, 2, 6, 3, 7, 25, 8, 9, 8, 10, 27, 0, 1, 0, 5, 26, -1, 5, 1, 29, 2, 6, 3, 7, 9, 8, 10, 30, 0, 1, 0, 5, 27, -1, 6, 1, 31, 2, 6, 3, 7, 17, 8, 9, 8, 10, 30, 0, 0, 0, 7, 28, -1, 0, 0, 18, 0, 5, 29, -1, 5, 1, 32, 2, 6, 3, 7, 9, 8, 10, 30, 0, 18, 0, 5, 30, -1, 6, 1, 33, 2, 6, 3, 7, 17, 8, 9, 8, 10, 30, 0, 18, 0, 5, 31, -1, 5, 1, 34, 2, 6, 3, 7, 9, 8, 10, 27, 0, 18, 0, 5, 32, -1, 6, 1, 35, 2, 6, 3, 7, 25, 8, 9, 8, 10, 27, 0, 18, 0, 5, 33, -1, 5, 1, 36, 2, 6, 3, 7, 9, 8, 10, 27, 0, 18, 0, 5, 34, -1, 6, 1, 37, 2, 6, 3, 7, 25, 8, 9, 8, 10, 27, 0, 18, 0, 5, 35, -1, 5, 1, 38, 2, 6, 3, 7, 9, 8, 10, 30, 0, 18, 0, 5, 36, -1, 6, 1, 39, 2, 6, 3, 7, 17, 8, 9, 8, 10, 30, 0 </int_array> + <string> "variants" </string> + <array len="40" shared="false"> + <vector2> 368.635, 155.289 </vector2> + <vector2> 0.432859, 0.446287 </vector2> + <resource external="0"> </resource> + <dictionary shared="false"> + <string> "__editor_plugin_screen__" </string> + <string> "2D" </string> + </dictionary> + <dictionary shared="false"> + <string> "_editor_collapsed" </string> + <bool> True </bool> + </dictionary> + <vector2> 147.73, 120.925 </vector2> + <vector2> 0.9, 0.9 </vector2> + <resource external="1"> </resource> + <bool> True </bool> + <rect2> 0, 0, 45, 45 </rect2> + <vector2> 185.769, 82.4874 </vector2> + <vector2> 112.377, 82.4874 </vector2> + <vector2> 149.073, 47.3293 </vector2> + <vector2> -161.038, -158.037 </vector2> + <vector2> 5.3348, 3.35512 </vector2> + <rect2> 10, 10, 10, 10 </rect2> + <vector2> 159.362, -156.977 </vector2> + <vector2> -159.349, -221.878 </vector2> + <vector2> 1.0458, 2.16952 </vector2> + <rect2> 0, 0, 45, 22 </rect2> + <vector2> 156.677, -220.11 </vector2> + <vector2> -67.5308, 164.422 </vector2> + <vector2> 75.8825, 167.363 </vector2> + <vector2> -46.6707, 52.702 </vector2> + <vector2> 0.810497, 0.57205 </vector2> + <vector2> 56.2581, 54.4382 </vector2> + <vector2> -139.402, 46.8295 </vector2> + <rect2> 50, 0, 54, 14 </rect2> + <vector2> -139.838, 115.789 </vector2> + <vector2> -172.262, 81.8793 </vector2> + <rect2> 50, 0, 14, 54 </rect2> + <vector2> -105.085, 81.0326 </vector2> + <vector2> -94.4295, 164.932 </vector2> + <vector2> -40.3475, 164.509 </vector2> + <vector2> -67.6802, 137.926 </vector2> + <vector2> -67.4618, 192.915 </vector2> + <vector2> 76.6557, 140.986 </vector2> + <vector2> 76.0009, 195.339 </vector2> + <vector2> 48.8152, 167.145 </vector2> + <vector2> 102.899, 167.857 </vector2> + </array> + <string> "version" </string> + <int> 2 </int> + </dictionary> + + </main_resource> +</resource_file>
\ No newline at end of file diff --git a/drivers/SCsub b/drivers/SCsub index e52d6538e5..a00d7fc3f9 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -12,11 +12,13 @@ SConscript('windows/SCsub'); SConscript('gles2/SCsub'); SConscript('gl_context/SCsub'); SConscript('openssl/SCsub'); +SConscript('pnm/SCsub'); if (env["png"]=="yes"): SConscript("png/SCsub"); if (env["jpg"]=="yes"): - SConscript("jpg/SCsub"); + #SConscript("jpg/SCsub"); + SConscript("jpegd/SCsub"); if (env["webp"]=="yes"): SConscript("webp/SCsub"); SConscript("dds/SCsub"); diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index a3c0bd344c..9b26cbfc7c 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -10306,6 +10306,8 @@ void RasterizerGLES2::_update_framebuffer() { return; int scale = GLOBAL_DEF("rasterizer/framebuffer_shrink",1); + if (scale<1) + scale=1; int dwidth = OS::get_singleton()->get_video_mode().width/scale; int dheight = OS::get_singleton()->get_video_mode().height/scale; diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index 259e82d704..285abd30ff 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -196,7 +196,7 @@ void main() { #ifdef USE_DISTANCE_FIELD const float smoothing = 1.0/32.0; float distance = texture2D(texture, uv_interp).a; - color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance); + color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance) * color.a; #else color *= texture2D( texture, uv_interp ); diff --git a/drivers/jpg/SCsub b/drivers/jpegd/SCsub index df91b10a02..dfdb19402e 100644 --- a/drivers/jpg/SCsub +++ b/drivers/jpegd/SCsub @@ -2,9 +2,8 @@ Import('env') jpg_sources = [ - "jpg/tinyjpeg.c", - "jpg/jidctflt.c", - "jpg/image_loader_jpg.cpp" + "jpegd/jpgd.cpp", + "jpegd/image_loader_jpegd.cpp" ] env.drivers_sources+=jpg_sources diff --git a/drivers/jpegd/image_loader_jpegd.cpp b/drivers/jpegd/image_loader_jpegd.cpp new file mode 100644 index 0000000000..9d1263b81b --- /dev/null +++ b/drivers/jpegd/image_loader_jpegd.cpp @@ -0,0 +1,108 @@ +/*************************************************/ +/* image_loader_jpg.cpp */ +/*************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/*************************************************/ +/* Source code within this file is: */ +/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */ +/* All Rights Reserved. */ +/*************************************************/ + +#include "image_loader_jpegd.h" + +#include "print_string.h" +#include "os/os.h" +#include "jpgd.h" +#include <string.h> + + +Error ImageLoaderJPG::load_image(Image *p_image,FileAccess *f) { + + + DVector<uint8_t> src_image; + int src_image_len = f->get_len(); + ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); + src_image.resize(src_image_len); + + DVector<uint8_t>::Write w = src_image.write(); + + f->get_buffer(&w[0],src_image_len); + + f->close(); + + + + jpgd::jpeg_decoder_mem_stream mem_stream(w.ptr(),src_image_len); + + jpgd::jpeg_decoder decoder(&mem_stream); + + if (decoder.get_error_code() != jpgd::JPGD_SUCCESS) { + return ERR_CANT_OPEN; + } + + const int image_width = decoder.get_width(); + const int image_height = decoder.get_height(); + int comps = decoder.get_num_components(); + if (comps==3) + comps=4; //weird + + if (decoder.begin_decoding() != jpgd::JPGD_SUCCESS) + return ERR_FILE_CORRUPT; + + const int dst_bpl = image_width * comps; + + DVector<uint8_t> data; + + data.resize(dst_bpl * image_height); + + DVector<uint8_t>::Write dw = data.write(); + + jpgd::uint8 *pImage_data = (jpgd::uint8*)dw.ptr(); + + for (int y = 0; y < image_height; y++) + { + const jpgd::uint8* pScan_line; + jpgd::uint scan_line_len; + if (decoder.decode((const void**)&pScan_line, &scan_line_len) != jpgd::JPGD_SUCCESS) + { + return ERR_FILE_CORRUPT; + } + + jpgd::uint8 *pDst = pImage_data + y * dst_bpl; + memcpy(pDst, pScan_line, dst_bpl); + + + } + + + //all good + + Image::Format fmt; + if (comps==1) + fmt=Image::FORMAT_GRAYSCALE; + else + fmt=Image::FORMAT_RGBA; + + dw = DVector<uint8_t>::Write(); + w = DVector<uint8_t>::Write(); + + p_image->create(image_width,image_height,0,fmt,data); + + return OK; + +} + +void ImageLoaderJPG::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("jpg"); + p_extensions->push_back("jpeg"); +} + + +ImageLoaderJPG::ImageLoaderJPG() { + + +} + + diff --git a/drivers/jpg/image_loader_jpg.h b/drivers/jpegd/image_loader_jpegd.h index 1b2165ab47..1b2165ab47 100644 --- a/drivers/jpg/image_loader_jpg.h +++ b/drivers/jpegd/image_loader_jpegd.h diff --git a/drivers/jpegd/jpgd.cpp b/drivers/jpegd/jpgd.cpp new file mode 100644 index 0000000000..fad9a37a9a --- /dev/null +++ b/drivers/jpegd/jpgd.cpp @@ -0,0 +1,3172 @@ +// jpgd.cpp - C++ class for JPEG decompression. +// Public domain, Rich Geldreich <richgel99@gmail.com> +// Alex Evans: Linear memory allocator (taken from jpge.h). +// v1.04, May. 19, 2012: Code tweaks to fix VS2008 static code analysis warnings (all looked harmless) +// +// Supports progressive and baseline sequential JPEG image files, and the most common chroma subsampling factors: Y, H1V1, H2V1, H1V2, and H2V2. +// +// Chroma upsampling quality: H2V2 is upsampled in the frequency domain, H2V1 and H1V2 are upsampled using point sampling. +// Chroma upsampling reference: "Fast Scheme for Image Size Change in the Compressed Domain" +// http://vision.ai.uiuc.edu/~dugad/research/dct/index.html + +#include "jpgd.h" +#include <string.h> + +#include <assert.h> +#define JPGD_ASSERT(x) assert(x) + +#ifdef _MSC_VER +#pragma warning (disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable +#endif + +// Set to 1 to enable freq. domain chroma upsampling on images using H2V2 subsampling (0=faster nearest neighbor sampling). +// This is slower, but results in higher quality on images with highly saturated colors. +#define JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING 1 + +#define JPGD_TRUE (1) +#define JPGD_FALSE (0) + +#define JPGD_MAX(a,b) (((a)>(b)) ? (a) : (b)) +#define JPGD_MIN(a,b) (((a)<(b)) ? (a) : (b)) + +namespace jpgd { + +static inline void *jpgd_malloc(size_t nSize) { return malloc(nSize); } +static inline void jpgd_free(void *p) { free(p); } + +// DCT coefficients are stored in this sequence. +static int g_ZAG[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 }; + +enum JPEG_MARKER +{ + M_SOF0 = 0xC0, M_SOF1 = 0xC1, M_SOF2 = 0xC2, M_SOF3 = 0xC3, M_SOF5 = 0xC5, M_SOF6 = 0xC6, M_SOF7 = 0xC7, M_JPG = 0xC8, + M_SOF9 = 0xC9, M_SOF10 = 0xCA, M_SOF11 = 0xCB, M_SOF13 = 0xCD, M_SOF14 = 0xCE, M_SOF15 = 0xCF, M_DHT = 0xC4, M_DAC = 0xCC, + M_RST0 = 0xD0, M_RST1 = 0xD1, M_RST2 = 0xD2, M_RST3 = 0xD3, M_RST4 = 0xD4, M_RST5 = 0xD5, M_RST6 = 0xD6, M_RST7 = 0xD7, + M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_DNL = 0xDC, M_DRI = 0xDD, M_DHP = 0xDE, M_EXP = 0xDF, + M_APP0 = 0xE0, M_APP15 = 0xEF, M_JPG0 = 0xF0, M_JPG13 = 0xFD, M_COM = 0xFE, M_TEM = 0x01, M_ERROR = 0x100, RST0 = 0xD0 +}; + +enum JPEG_SUBSAMPLING { JPGD_GRAYSCALE = 0, JPGD_YH1V1, JPGD_YH2V1, JPGD_YH1V2, JPGD_YH2V2 }; + +#define CONST_BITS 13 +#define PASS1_BITS 2 +#define SCALEDONE ((int32)1) + +#define FIX_0_298631336 ((int32)2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((int32)3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((int32)4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((int32)6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((int32)7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((int32)9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((int32)12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((int32)15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((int32)16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((int32)16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((int32)20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((int32)25172) /* FIX(3.072711026) */ + +#define DESCALE(x,n) (((x) + (SCALEDONE << ((n)-1))) >> (n)) +#define DESCALE_ZEROSHIFT(x,n) (((x) + (128 << (n)) + (SCALEDONE << ((n)-1))) >> (n)) + +#define MULTIPLY(var, cnst) ((var) * (cnst)) + +#define CLAMP(i) ((static_cast<uint>(i) > 255) ? (((~i) >> 31) & 0xFF) : (i)) + +// Compiler creates a fast path 1D IDCT for X non-zero columns +template <int NONZERO_COLS> +struct Row +{ + static void idct(int* pTemp, const jpgd_block_t* pSrc) + { + // ACCESS_COL() will be optimized at compile time to either an array access, or 0. + #define ACCESS_COL(x) (((x) < NONZERO_COLS) ? (int)pSrc[x] : 0) + + const int z2 = ACCESS_COL(2), z3 = ACCESS_COL(6); + + const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + const int tmp0 = (ACCESS_COL(0) + ACCESS_COL(4)) << CONST_BITS; + const int tmp1 = (ACCESS_COL(0) - ACCESS_COL(4)) << CONST_BITS; + + const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2; + + const int atmp0 = ACCESS_COL(7), atmp1 = ACCESS_COL(5), atmp2 = ACCESS_COL(3), atmp3 = ACCESS_COL(1); + + const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3; + const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602); + + const int az1 = MULTIPLY(bz1, - FIX_0_899976223); + const int az2 = MULTIPLY(bz2, - FIX_2_562915447); + const int az3 = MULTIPLY(bz3, - FIX_1_961570560) + bz5; + const int az4 = MULTIPLY(bz4, - FIX_0_390180644) + bz5; + + const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3; + const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4; + const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3; + const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4; + + pTemp[0] = DESCALE(tmp10 + btmp3, CONST_BITS-PASS1_BITS); + pTemp[7] = DESCALE(tmp10 - btmp3, CONST_BITS-PASS1_BITS); + pTemp[1] = DESCALE(tmp11 + btmp2, CONST_BITS-PASS1_BITS); + pTemp[6] = DESCALE(tmp11 - btmp2, CONST_BITS-PASS1_BITS); + pTemp[2] = DESCALE(tmp12 + btmp1, CONST_BITS-PASS1_BITS); + pTemp[5] = DESCALE(tmp12 - btmp1, CONST_BITS-PASS1_BITS); + pTemp[3] = DESCALE(tmp13 + btmp0, CONST_BITS-PASS1_BITS); + pTemp[4] = DESCALE(tmp13 - btmp0, CONST_BITS-PASS1_BITS); + } +}; + +template <> +struct Row<0> +{ + static void idct(int* pTemp, const jpgd_block_t* pSrc) + { +#ifdef _MSC_VER + pTemp; pSrc; +#endif + } +}; + +template <> +struct Row<1> +{ + static void idct(int* pTemp, const jpgd_block_t* pSrc) + { + const int dcval = (pSrc[0] << PASS1_BITS); + + pTemp[0] = dcval; + pTemp[1] = dcval; + pTemp[2] = dcval; + pTemp[3] = dcval; + pTemp[4] = dcval; + pTemp[5] = dcval; + pTemp[6] = dcval; + pTemp[7] = dcval; + } +}; + +// Compiler creates a fast path 1D IDCT for X non-zero rows +template <int NONZERO_ROWS> +struct Col +{ + static void idct(uint8* pDst_ptr, const int* pTemp) + { + // ACCESS_ROW() will be optimized at compile time to either an array access, or 0. + #define ACCESS_ROW(x) (((x) < NONZERO_ROWS) ? pTemp[x * 8] : 0) + + const int z2 = ACCESS_ROW(2); + const int z3 = ACCESS_ROW(6); + + const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + const int tmp0 = (ACCESS_ROW(0) + ACCESS_ROW(4)) << CONST_BITS; + const int tmp1 = (ACCESS_ROW(0) - ACCESS_ROW(4)) << CONST_BITS; + + const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2; + + const int atmp0 = ACCESS_ROW(7), atmp1 = ACCESS_ROW(5), atmp2 = ACCESS_ROW(3), atmp3 = ACCESS_ROW(1); + + const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3; + const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602); + + const int az1 = MULTIPLY(bz1, - FIX_0_899976223); + const int az2 = MULTIPLY(bz2, - FIX_2_562915447); + const int az3 = MULTIPLY(bz3, - FIX_1_961570560) + bz5; + const int az4 = MULTIPLY(bz4, - FIX_0_390180644) + bz5; + + const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3; + const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4; + const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3; + const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4; + + int i = DESCALE_ZEROSHIFT(tmp10 + btmp3, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*0] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp10 - btmp3, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*7] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp11 + btmp2, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*1] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp11 - btmp2, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*6] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp12 + btmp1, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*2] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp12 - btmp1, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*5] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp13 + btmp0, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*3] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp13 - btmp0, CONST_BITS+PASS1_BITS+3); + pDst_ptr[8*4] = (uint8)CLAMP(i); + } +}; + +template <> +struct Col<1> +{ + static void idct(uint8* pDst_ptr, const int* pTemp) + { + int dcval = DESCALE_ZEROSHIFT(pTemp[0], PASS1_BITS+3); + const uint8 dcval_clamped = (uint8)CLAMP(dcval); + pDst_ptr[0*8] = dcval_clamped; + pDst_ptr[1*8] = dcval_clamped; + pDst_ptr[2*8] = dcval_clamped; + pDst_ptr[3*8] = dcval_clamped; + pDst_ptr[4*8] = dcval_clamped; + pDst_ptr[5*8] = dcval_clamped; + pDst_ptr[6*8] = dcval_clamped; + pDst_ptr[7*8] = dcval_clamped; + } +}; + +static const uint8 s_idct_row_table[] = +{ + 1,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0, 2,1,0,0,0,0,0,0, 2,1,1,0,0,0,0,0, 2,2,1,0,0,0,0,0, 3,2,1,0,0,0,0,0, 4,2,1,0,0,0,0,0, 4,3,1,0,0,0,0,0, + 4,3,2,0,0,0,0,0, 4,3,2,1,0,0,0,0, 4,3,2,1,1,0,0,0, 4,3,2,2,1,0,0,0, 4,3,3,2,1,0,0,0, 4,4,3,2,1,0,0,0, 5,4,3,2,1,0,0,0, 6,4,3,2,1,0,0,0, + 6,5,3,2,1,0,0,0, 6,5,4,2,1,0,0,0, 6,5,4,3,1,0,0,0, 6,5,4,3,2,0,0,0, 6,5,4,3,2,1,0,0, 6,5,4,3,2,1,1,0, 6,5,4,3,2,2,1,0, 6,5,4,3,3,2,1,0, + 6,5,4,4,3,2,1,0, 6,5,5,4,3,2,1,0, 6,6,5,4,3,2,1,0, 7,6,5,4,3,2,1,0, 8,6,5,4,3,2,1,0, 8,7,5,4,3,2,1,0, 8,7,6,4,3,2,1,0, 8,7,6,5,3,2,1,0, + 8,7,6,5,4,2,1,0, 8,7,6,5,4,3,1,0, 8,7,6,5,4,3,2,0, 8,7,6,5,4,3,2,1, 8,7,6,5,4,3,2,2, 8,7,6,5,4,3,3,2, 8,7,6,5,4,4,3,2, 8,7,6,5,5,4,3,2, + 8,7,6,6,5,4,3,2, 8,7,7,6,5,4,3,2, 8,8,7,6,5,4,3,2, 8,8,8,6,5,4,3,2, 8,8,8,7,5,4,3,2, 8,8,8,7,6,4,3,2, 8,8,8,7,6,5,3,2, 8,8,8,7,6,5,4,2, + 8,8,8,7,6,5,4,3, 8,8,8,7,6,5,4,4, 8,8,8,7,6,5,5,4, 8,8,8,7,6,6,5,4, 8,8,8,7,7,6,5,4, 8,8,8,8,7,6,5,4, 8,8,8,8,8,6,5,4, 8,8,8,8,8,7,5,4, + 8,8,8,8,8,7,6,4, 8,8,8,8,8,7,6,5, 8,8,8,8,8,7,6,6, 8,8,8,8,8,7,7,6, 8,8,8,8,8,8,7,6, 8,8,8,8,8,8,8,6, 8,8,8,8,8,8,8,7, 8,8,8,8,8,8,8,8, +}; + +static const uint8 s_idct_col_table[] = { 1, 1, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; + +void idct(const jpgd_block_t* pSrc_ptr, uint8* pDst_ptr, int block_max_zag) +{ + JPGD_ASSERT(block_max_zag >= 1); + JPGD_ASSERT(block_max_zag <= 64); + + if (block_max_zag <= 1) + { + int k = ((pSrc_ptr[0] + 4) >> 3) + 128; + k = CLAMP(k); + k = k | (k<<8); + k = k | (k<<16); + + for (int i = 8; i > 0; i--) + { + *(int*)&pDst_ptr[0] = k; + *(int*)&pDst_ptr[4] = k; + pDst_ptr += 8; + } + return; + } + + int temp[64]; + + const jpgd_block_t* pSrc = pSrc_ptr; + int* pTemp = temp; + + const uint8* pRow_tab = &s_idct_row_table[(block_max_zag - 1) * 8]; + int i; + for (i = 8; i > 0; i--, pRow_tab++) + { + switch (*pRow_tab) + { + case 0: Row<0>::idct(pTemp, pSrc); break; + case 1: Row<1>::idct(pTemp, pSrc); break; + case 2: Row<2>::idct(pTemp, pSrc); break; + case 3: Row<3>::idct(pTemp, pSrc); break; + case 4: Row<4>::idct(pTemp, pSrc); break; + case 5: Row<5>::idct(pTemp, pSrc); break; + case 6: Row<6>::idct(pTemp, pSrc); break; + case 7: Row<7>::idct(pTemp, pSrc); break; + case 8: Row<8>::idct(pTemp, pSrc); break; + } + + pSrc += 8; + pTemp += 8; + } + + pTemp = temp; + + const int nonzero_rows = s_idct_col_table[block_max_zag - 1]; + for (i = 8; i > 0; i--) + { + switch (nonzero_rows) + { + case 1: Col<1>::idct(pDst_ptr, pTemp); break; + case 2: Col<2>::idct(pDst_ptr, pTemp); break; + case 3: Col<3>::idct(pDst_ptr, pTemp); break; + case 4: Col<4>::idct(pDst_ptr, pTemp); break; + case 5: Col<5>::idct(pDst_ptr, pTemp); break; + case 6: Col<6>::idct(pDst_ptr, pTemp); break; + case 7: Col<7>::idct(pDst_ptr, pTemp); break; + case 8: Col<8>::idct(pDst_ptr, pTemp); break; + } + + pTemp++; + pDst_ptr++; + } +} + +void idct_4x4(const jpgd_block_t* pSrc_ptr, uint8* pDst_ptr) +{ + int temp[64]; + int* pTemp = temp; + const jpgd_block_t* pSrc = pSrc_ptr; + + for (int i = 4; i > 0; i--) + { + Row<4>::idct(pTemp, pSrc); + pSrc += 8; + pTemp += 8; + } + + pTemp = temp; + for (int i = 8; i > 0; i--) + { + Col<4>::idct(pDst_ptr, pTemp); + pTemp++; + pDst_ptr++; + } +} + +// Retrieve one character from the input stream. +inline uint jpeg_decoder::get_char() +{ + // Any bytes remaining in buffer? + if (!m_in_buf_left) + { + // Try to get more bytes. + prep_in_buffer(); + // Still nothing to get? + if (!m_in_buf_left) + { + // Pad the end of the stream with 0xFF 0xD9 (EOI marker) + int t = m_tem_flag; + m_tem_flag ^= 1; + if (t) + return 0xD9; + else + return 0xFF; + } + } + + uint c = *m_pIn_buf_ofs++; + m_in_buf_left--; + + return c; +} + +// Same as previous method, except can indicate if the character is a pad character or not. +inline uint jpeg_decoder::get_char(bool *pPadding_flag) +{ + if (!m_in_buf_left) + { + prep_in_buffer(); + if (!m_in_buf_left) + { + *pPadding_flag = true; + int t = m_tem_flag; + m_tem_flag ^= 1; + if (t) + return 0xD9; + else + return 0xFF; + } + } + + *pPadding_flag = false; + + uint c = *m_pIn_buf_ofs++; + m_in_buf_left--; + + return c; +} + +// Inserts a previously retrieved character back into the input buffer. +inline void jpeg_decoder::stuff_char(uint8 q) +{ + *(--m_pIn_buf_ofs) = q; + m_in_buf_left++; +} + +// Retrieves one character from the input stream, but does not read past markers. Will continue to return 0xFF when a marker is encountered. +inline uint8 jpeg_decoder::get_octet() +{ + bool padding_flag; + int c = get_char(&padding_flag); + + if (c == 0xFF) + { + if (padding_flag) + return 0xFF; + + c = get_char(&padding_flag); + if (padding_flag) + { + stuff_char(0xFF); + return 0xFF; + } + + if (c == 0x00) + return 0xFF; + else + { + stuff_char(static_cast<uint8>(c)); + stuff_char(0xFF); + return 0xFF; + } + } + + return static_cast<uint8>(c); +} + +// Retrieves a variable number of bits from the input stream. Does not recognize markers. +inline uint jpeg_decoder::get_bits(int num_bits) +{ + if (!num_bits) + return 0; + + uint i = m_bit_buf >> (32 - num_bits); + + if ((m_bits_left -= num_bits) <= 0) + { + m_bit_buf <<= (num_bits += m_bits_left); + + uint c1 = get_char(); + uint c2 = get_char(); + m_bit_buf = (m_bit_buf & 0xFFFF0000) | (c1 << 8) | c2; + + m_bit_buf <<= -m_bits_left; + + m_bits_left += 16; + + JPGD_ASSERT(m_bits_left >= 0); + } + else + m_bit_buf <<= num_bits; + + return i; +} + +// Retrieves a variable number of bits from the input stream. Markers will not be read into the input bit buffer. Instead, an infinite number of all 1's will be returned when a marker is encountered. +inline uint jpeg_decoder::get_bits_no_markers(int num_bits) +{ + if (!num_bits) + return 0; + + uint i = m_bit_buf >> (32 - num_bits); + + if ((m_bits_left -= num_bits) <= 0) + { + m_bit_buf <<= (num_bits += m_bits_left); + + if ((m_in_buf_left < 2) || (m_pIn_buf_ofs[0] == 0xFF) || (m_pIn_buf_ofs[1] == 0xFF)) + { + uint c1 = get_octet(); + uint c2 = get_octet(); + m_bit_buf |= (c1 << 8) | c2; + } + else + { + m_bit_buf |= ((uint)m_pIn_buf_ofs[0] << 8) | m_pIn_buf_ofs[1]; + m_in_buf_left -= 2; + m_pIn_buf_ofs += 2; + } + + m_bit_buf <<= -m_bits_left; + + m_bits_left += 16; + + JPGD_ASSERT(m_bits_left >= 0); + } + else + m_bit_buf <<= num_bits; + + return i; +} + +// Decodes a Huffman encoded symbol. +inline int jpeg_decoder::huff_decode(huff_tables *pH) +{ + int symbol; + + // Check first 8-bits: do we have a complete symbol? + if ((symbol = pH->look_up[m_bit_buf >> 24]) < 0) + { + // Decode more bits, use a tree traversal to find symbol. + int ofs = 23; + do + { + symbol = pH->tree[-(int)(symbol + ((m_bit_buf >> ofs) & 1))]; + ofs--; + } while (symbol < 0); + + get_bits_no_markers(8 + (23 - ofs)); + } + else + get_bits_no_markers(pH->code_size[symbol]); + + return symbol; +} + +// Decodes a Huffman encoded symbol. +inline int jpeg_decoder::huff_decode(huff_tables *pH, int& extra_bits) +{ + int symbol; + + // Check first 8-bits: do we have a complete symbol? + if ((symbol = pH->look_up2[m_bit_buf >> 24]) < 0) + { + // Use a tree traversal to find symbol. + int ofs = 23; + do + { + symbol = pH->tree[-(int)(symbol + ((m_bit_buf >> ofs) & 1))]; + ofs--; + } while (symbol < 0); + + get_bits_no_markers(8 + (23 - ofs)); + + extra_bits = get_bits_no_markers(symbol & 0xF); + } + else + { + JPGD_ASSERT(((symbol >> 8) & 31) == pH->code_size[symbol & 255] + ((symbol & 0x8000) ? (symbol & 15) : 0)); + + if (symbol & 0x8000) + { + get_bits_no_markers((symbol >> 8) & 31); + extra_bits = symbol >> 16; + } + else + { + int code_size = (symbol >> 8) & 31; + int num_extra_bits = symbol & 0xF; + int bits = code_size + num_extra_bits; + if (bits <= (m_bits_left + 16)) + extra_bits = get_bits_no_markers(bits) & ((1 << num_extra_bits) - 1); + else + { + get_bits_no_markers(code_size); + extra_bits = get_bits_no_markers(num_extra_bits); + } + } + + symbol &= 0xFF; + } + + return symbol; +} + +// Tables and macro used to fully decode the DPCM differences. +static const int s_extend_test[16] = { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; +static const int s_extend_offset[16] = { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; +static const int s_extend_mask[] = { 0, (1<<0), (1<<1), (1<<2), (1<<3), (1<<4), (1<<5), (1<<6), (1<<7), (1<<8), (1<<9), (1<<10), (1<<11), (1<<12), (1<<13), (1<<14), (1<<15), (1<<16) }; +// The logical AND's in this macro are to shut up static code analysis (aren't really necessary - couldn't find another way to do this) +#define JPGD_HUFF_EXTEND(x, s) (((x) < s_extend_test[s & 15]) ? ((x) + s_extend_offset[s & 15]) : (x)) + +// Clamps a value between 0-255. +inline uint8 jpeg_decoder::clamp(int i) +{ + if (static_cast<uint>(i) > 255) + i = (((~i) >> 31) & 0xFF); + + return static_cast<uint8>(i); +} + +namespace DCT_Upsample +{ + struct Matrix44 + { + typedef int Element_Type; + enum { NUM_ROWS = 4, NUM_COLS = 4 }; + + Element_Type v[NUM_ROWS][NUM_COLS]; + + inline int rows() const { return NUM_ROWS; } + inline int cols() const { return NUM_COLS; } + + inline const Element_Type & at(int r, int c) const { return v[r][c]; } + inline Element_Type & at(int r, int c) { return v[r][c]; } + + inline Matrix44() { } + + inline Matrix44& operator += (const Matrix44& a) + { + for (int r = 0; r < NUM_ROWS; r++) + { + at(r, 0) += a.at(r, 0); + at(r, 1) += a.at(r, 1); + at(r, 2) += a.at(r, 2); + at(r, 3) += a.at(r, 3); + } + return *this; + } + + inline Matrix44& operator -= (const Matrix44& a) + { + for (int r = 0; r < NUM_ROWS; r++) + { + at(r, 0) -= a.at(r, 0); + at(r, 1) -= a.at(r, 1); + at(r, 2) -= a.at(r, 2); + at(r, 3) -= a.at(r, 3); + } + return *this; + } + + friend inline Matrix44 operator + (const Matrix44& a, const Matrix44& b) + { + Matrix44 ret; + for (int r = 0; r < NUM_ROWS; r++) + { + ret.at(r, 0) = a.at(r, 0) + b.at(r, 0); + ret.at(r, 1) = a.at(r, 1) + b.at(r, 1); + ret.at(r, 2) = a.at(r, 2) + b.at(r, 2); + ret.at(r, 3) = a.at(r, 3) + b.at(r, 3); + } + return ret; + } + + friend inline Matrix44 operator - (const Matrix44& a, const Matrix44& b) + { + Matrix44 ret; + for (int r = 0; r < NUM_ROWS; r++) + { + ret.at(r, 0) = a.at(r, 0) - b.at(r, 0); + ret.at(r, 1) = a.at(r, 1) - b.at(r, 1); + ret.at(r, 2) = a.at(r, 2) - b.at(r, 2); + ret.at(r, 3) = a.at(r, 3) - b.at(r, 3); + } + return ret; + } + + static inline void add_and_store(jpgd_block_t* pDst, const Matrix44& a, const Matrix44& b) + { + for (int r = 0; r < 4; r++) + { + pDst[0*8 + r] = static_cast<jpgd_block_t>(a.at(r, 0) + b.at(r, 0)); + pDst[1*8 + r] = static_cast<jpgd_block_t>(a.at(r, 1) + b.at(r, 1)); + pDst[2*8 + r] = static_cast<jpgd_block_t>(a.at(r, 2) + b.at(r, 2)); + pDst[3*8 + r] = static_cast<jpgd_block_t>(a.at(r, 3) + b.at(r, 3)); + } + } + + static inline void sub_and_store(jpgd_block_t* pDst, const Matrix44& a, const Matrix44& b) + { + for (int r = 0; r < 4; r++) + { + pDst[0*8 + r] = static_cast<jpgd_block_t>(a.at(r, 0) - b.at(r, 0)); + pDst[1*8 + r] = static_cast<jpgd_block_t>(a.at(r, 1) - b.at(r, 1)); + pDst[2*8 + r] = static_cast<jpgd_block_t>(a.at(r, 2) - b.at(r, 2)); + pDst[3*8 + r] = static_cast<jpgd_block_t>(a.at(r, 3) - b.at(r, 3)); + } + } + }; + + const int FRACT_BITS = 10; + const int SCALE = 1 << FRACT_BITS; + + typedef int Temp_Type; + #define D(i) (((i) + (SCALE >> 1)) >> FRACT_BITS) + #define F(i) ((int)((i) * SCALE + .5f)) + + // Any decent C++ compiler will optimize this at compile time to a 0, or an array access. + #define AT(c, r) ((((c)>=NUM_COLS)||((r)>=NUM_ROWS)) ? 0 : pSrc[(c)+(r)*8]) + + // NUM_ROWS/NUM_COLS = # of non-zero rows/cols in input matrix + template<int NUM_ROWS, int NUM_COLS> + struct P_Q + { + static void calc(Matrix44& P, Matrix44& Q, const jpgd_block_t* pSrc) + { + // 4x8 = 4x8 times 8x8, matrix 0 is constant + const Temp_Type X000 = AT(0, 0); + const Temp_Type X001 = AT(0, 1); + const Temp_Type X002 = AT(0, 2); + const Temp_Type X003 = AT(0, 3); + const Temp_Type X004 = AT(0, 4); + const Temp_Type X005 = AT(0, 5); + const Temp_Type X006 = AT(0, 6); + const Temp_Type X007 = AT(0, 7); + const Temp_Type X010 = D(F(0.415735f) * AT(1, 0) + F(0.791065f) * AT(3, 0) + F(-0.352443f) * AT(5, 0) + F(0.277785f) * AT(7, 0)); + const Temp_Type X011 = D(F(0.415735f) * AT(1, 1) + F(0.791065f) * AT(3, 1) + F(-0.352443f) * AT(5, 1) + F(0.277785f) * AT(7, 1)); + const Temp_Type X012 = D(F(0.415735f) * AT(1, 2) + F(0.791065f) * AT(3, 2) + F(-0.352443f) * AT(5, 2) + F(0.277785f) * AT(7, 2)); + const Temp_Type X013 = D(F(0.415735f) * AT(1, 3) + F(0.791065f) * AT(3, 3) + F(-0.352443f) * AT(5, 3) + F(0.277785f) * AT(7, 3)); + const Temp_Type X014 = D(F(0.415735f) * AT(1, 4) + F(0.791065f) * AT(3, 4) + F(-0.352443f) * AT(5, 4) + F(0.277785f) * AT(7, 4)); + const Temp_Type X015 = D(F(0.415735f) * AT(1, 5) + F(0.791065f) * AT(3, 5) + F(-0.352443f) * AT(5, 5) + F(0.277785f) * AT(7, 5)); + const Temp_Type X016 = D(F(0.415735f) * AT(1, 6) + F(0.791065f) * AT(3, 6) + F(-0.352443f) * AT(5, 6) + F(0.277785f) * AT(7, 6)); + const Temp_Type X017 = D(F(0.415735f) * AT(1, 7) + F(0.791065f) * AT(3, 7) + F(-0.352443f) * AT(5, 7) + F(0.277785f) * AT(7, 7)); + const Temp_Type X020 = AT(4, 0); + const Temp_Type X021 = AT(4, 1); + const Temp_Type X022 = AT(4, 2); + const Temp_Type X023 = AT(4, 3); + const Temp_Type X024 = AT(4, 4); + const Temp_Type X025 = AT(4, 5); + const Temp_Type X026 = AT(4, 6); + const Temp_Type X027 = AT(4, 7); + const Temp_Type X030 = D(F(0.022887f) * AT(1, 0) + F(-0.097545f) * AT(3, 0) + F(0.490393f) * AT(5, 0) + F(0.865723f) * AT(7, 0)); + const Temp_Type X031 = D(F(0.022887f) * AT(1, 1) + F(-0.097545f) * AT(3, 1) + F(0.490393f) * AT(5, 1) + F(0.865723f) * AT(7, 1)); + const Temp_Type X032 = D(F(0.022887f) * AT(1, 2) + F(-0.097545f) * AT(3, 2) + F(0.490393f) * AT(5, 2) + F(0.865723f) * AT(7, 2)); + const Temp_Type X033 = D(F(0.022887f) * AT(1, 3) + F(-0.097545f) * AT(3, 3) + F(0.490393f) * AT(5, 3) + F(0.865723f) * AT(7, 3)); + const Temp_Type X034 = D(F(0.022887f) * AT(1, 4) + F(-0.097545f) * AT(3, 4) + F(0.490393f) * AT(5, 4) + F(0.865723f) * AT(7, 4)); + const Temp_Type X035 = D(F(0.022887f) * AT(1, 5) + F(-0.097545f) * AT(3, 5) + F(0.490393f) * AT(5, 5) + F(0.865723f) * AT(7, 5)); + const Temp_Type X036 = D(F(0.022887f) * AT(1, 6) + F(-0.097545f) * AT(3, 6) + F(0.490393f) * AT(5, 6) + F(0.865723f) * AT(7, 6)); + const Temp_Type X037 = D(F(0.022887f) * AT(1, 7) + F(-0.097545f) * AT(3, 7) + F(0.490393f) * AT(5, 7) + F(0.865723f) * AT(7, 7)); + + // 4x4 = 4x8 times 8x4, matrix 1 is constant + P.at(0, 0) = X000; + P.at(0, 1) = D(X001 * F(0.415735f) + X003 * F(0.791065f) + X005 * F(-0.352443f) + X007 * F(0.277785f)); + P.at(0, 2) = X004; + P.at(0, 3) = D(X001 * F(0.022887f) + X003 * F(-0.097545f) + X005 * F(0.490393f) + X007 * F(0.865723f)); + P.at(1, 0) = X010; + P.at(1, 1) = D(X011 * F(0.415735f) + X013 * F(0.791065f) + X015 * F(-0.352443f) + X017 * F(0.277785f)); + P.at(1, 2) = X014; + P.at(1, 3) = D(X011 * F(0.022887f) + X013 * F(-0.097545f) + X015 * F(0.490393f) + X017 * F(0.865723f)); + P.at(2, 0) = X020; + P.at(2, 1) = D(X021 * F(0.415735f) + X023 * F(0.791065f) + X025 * F(-0.352443f) + X027 * F(0.277785f)); + P.at(2, 2) = X024; + P.at(2, 3) = D(X021 * F(0.022887f) + X023 * F(-0.097545f) + X025 * F(0.490393f) + X027 * F(0.865723f)); + P.at(3, 0) = X030; + P.at(3, 1) = D(X031 * F(0.415735f) + X033 * F(0.791065f) + X035 * F(-0.352443f) + X037 * F(0.277785f)); + P.at(3, 2) = X034; + P.at(3, 3) = D(X031 * F(0.022887f) + X033 * F(-0.097545f) + X035 * F(0.490393f) + X037 * F(0.865723f)); + // 40 muls 24 adds + + // 4x4 = 4x8 times 8x4, matrix 1 is constant + Q.at(0, 0) = D(X001 * F(0.906127f) + X003 * F(-0.318190f) + X005 * F(0.212608f) + X007 * F(-0.180240f)); + Q.at(0, 1) = X002; + Q.at(0, 2) = D(X001 * F(-0.074658f) + X003 * F(0.513280f) + X005 * F(0.768178f) + X007 * F(-0.375330f)); + Q.at(0, 3) = X006; + Q.at(1, 0) = D(X011 * F(0.906127f) + X013 * F(-0.318190f) + X015 * F(0.212608f) + X017 * F(-0.180240f)); + Q.at(1, 1) = X012; + Q.at(1, 2) = D(X011 * F(-0.074658f) + X013 * F(0.513280f) + X015 * F(0.768178f) + X017 * F(-0.375330f)); + Q.at(1, 3) = X016; + Q.at(2, 0) = D(X021 * F(0.906127f) + X023 * F(-0.318190f) + X025 * F(0.212608f) + X027 * F(-0.180240f)); + Q.at(2, 1) = X022; + Q.at(2, 2) = D(X021 * F(-0.074658f) + X023 * F(0.513280f) + X025 * F(0.768178f) + X027 * F(-0.375330f)); + Q.at(2, 3) = X026; + Q.at(3, 0) = D(X031 * F(0.906127f) + X033 * F(-0.318190f) + X035 * F(0.212608f) + X037 * F(-0.180240f)); + Q.at(3, 1) = X032; + Q.at(3, 2) = D(X031 * F(-0.074658f) + X033 * F(0.513280f) + X035 * F(0.768178f) + X037 * F(-0.375330f)); + Q.at(3, 3) = X036; + // 40 muls 24 adds + } + }; + + template<int NUM_ROWS, int NUM_COLS> + struct R_S + { + static void calc(Matrix44& R, Matrix44& S, const jpgd_block_t* pSrc) + { + // 4x8 = 4x8 times 8x8, matrix 0 is constant + const Temp_Type X100 = D(F(0.906127f) * AT(1, 0) + F(-0.318190f) * AT(3, 0) + F(0.212608f) * AT(5, 0) + F(-0.180240f) * AT(7, 0)); + const Temp_Type X101 = D(F(0.906127f) * AT(1, 1) + F(-0.318190f) * AT(3, 1) + F(0.212608f) * AT(5, 1) + F(-0.180240f) * AT(7, 1)); + const Temp_Type X102 = D(F(0.906127f) * AT(1, 2) + F(-0.318190f) * AT(3, 2) + F(0.212608f) * AT(5, 2) + F(-0.180240f) * AT(7, 2)); + const Temp_Type X103 = D(F(0.906127f) * AT(1, 3) + F(-0.318190f) * AT(3, 3) + F(0.212608f) * AT(5, 3) + F(-0.180240f) * AT(7, 3)); + const Temp_Type X104 = D(F(0.906127f) * AT(1, 4) + F(-0.318190f) * AT(3, 4) + F(0.212608f) * AT(5, 4) + F(-0.180240f) * AT(7, 4)); + const Temp_Type X105 = D(F(0.906127f) * AT(1, 5) + F(-0.318190f) * AT(3, 5) + F(0.212608f) * AT(5, 5) + F(-0.180240f) * AT(7, 5)); + const Temp_Type X106 = D(F(0.906127f) * AT(1, 6) + F(-0.318190f) * AT(3, 6) + F(0.212608f) * AT(5, 6) + F(-0.180240f) * AT(7, 6)); + const Temp_Type X107 = D(F(0.906127f) * AT(1, 7) + F(-0.318190f) * AT(3, 7) + F(0.212608f) * AT(5, 7) + F(-0.180240f) * AT(7, 7)); + const Temp_Type X110 = AT(2, 0); + const Temp_Type X111 = AT(2, 1); + const Temp_Type X112 = AT(2, 2); + const Temp_Type X113 = AT(2, 3); + const Temp_Type X114 = AT(2, 4); + const Temp_Type X115 = AT(2, 5); + const Temp_Type X116 = AT(2, 6); + const Temp_Type X117 = AT(2, 7); + const Temp_Type X120 = D(F(-0.074658f) * AT(1, 0) + F(0.513280f) * AT(3, 0) + F(0.768178f) * AT(5, 0) + F(-0.375330f) * AT(7, 0)); + const Temp_Type X121 = D(F(-0.074658f) * AT(1, 1) + F(0.513280f) * AT(3, 1) + F(0.768178f) * AT(5, 1) + F(-0.375330f) * AT(7, 1)); + const Temp_Type X122 = D(F(-0.074658f) * AT(1, 2) + F(0.513280f) * AT(3, 2) + F(0.768178f) * AT(5, 2) + F(-0.375330f) * AT(7, 2)); + const Temp_Type X123 = D(F(-0.074658f) * AT(1, 3) + F(0.513280f) * AT(3, 3) + F(0.768178f) * AT(5, 3) + F(-0.375330f) * AT(7, 3)); + const Temp_Type X124 = D(F(-0.074658f) * AT(1, 4) + F(0.513280f) * AT(3, 4) + F(0.768178f) * AT(5, 4) + F(-0.375330f) * AT(7, 4)); + const Temp_Type X125 = D(F(-0.074658f) * AT(1, 5) + F(0.513280f) * AT(3, 5) + F(0.768178f) * AT(5, 5) + F(-0.375330f) * AT(7, 5)); + const Temp_Type X126 = D(F(-0.074658f) * AT(1, 6) + F(0.513280f) * AT(3, 6) + F(0.768178f) * AT(5, 6) + F(-0.375330f) * AT(7, 6)); + const Temp_Type X127 = D(F(-0.074658f) * AT(1, 7) + F(0.513280f) * AT(3, 7) + F(0.768178f) * AT(5, 7) + F(-0.375330f) * AT(7, 7)); + const Temp_Type X130 = AT(6, 0); + const Temp_Type X131 = AT(6, 1); + const Temp_Type X132 = AT(6, 2); + const Temp_Type X133 = AT(6, 3); + const Temp_Type X134 = AT(6, 4); + const Temp_Type X135 = AT(6, 5); + const Temp_Type X136 = AT(6, 6); + const Temp_Type X137 = AT(6, 7); + // 80 muls 48 adds + + // 4x4 = 4x8 times 8x4, matrix 1 is constant + R.at(0, 0) = X100; + R.at(0, 1) = D(X101 * F(0.415735f) + X103 * F(0.791065f) + X105 * F(-0.352443f) + X107 * F(0.277785f)); + R.at(0, 2) = X104; + R.at(0, 3) = D(X101 * F(0.022887f) + X103 * F(-0.097545f) + X105 * F(0.490393f) + X107 * F(0.865723f)); + R.at(1, 0) = X110; + R.at(1, 1) = D(X111 * F(0.415735f) + X113 * F(0.791065f) + X115 * F(-0.352443f) + X117 * F(0.277785f)); + R.at(1, 2) = X114; + R.at(1, 3) = D(X111 * F(0.022887f) + X113 * F(-0.097545f) + X115 * F(0.490393f) + X117 * F(0.865723f)); + R.at(2, 0) = X120; + R.at(2, 1) = D(X121 * F(0.415735f) + X123 * F(0.791065f) + X125 * F(-0.352443f) + X127 * F(0.277785f)); + R.at(2, 2) = X124; + R.at(2, 3) = D(X121 * F(0.022887f) + X123 * F(-0.097545f) + X125 * F(0.490393f) + X127 * F(0.865723f)); + R.at(3, 0) = X130; + R.at(3, 1) = D(X131 * F(0.415735f) + X133 * F(0.791065f) + X135 * F(-0.352443f) + X137 * F(0.277785f)); + R.at(3, 2) = X134; + R.at(3, 3) = D(X131 * F(0.022887f) + X133 * F(-0.097545f) + X135 * F(0.490393f) + X137 * F(0.865723f)); + // 40 muls 24 adds + // 4x4 = 4x8 times 8x4, matrix 1 is constant + S.at(0, 0) = D(X101 * F(0.906127f) + X103 * F(-0.318190f) + X105 * F(0.212608f) + X107 * F(-0.180240f)); + S.at(0, 1) = X102; + S.at(0, 2) = D(X101 * F(-0.074658f) + X103 * F(0.513280f) + X105 * F(0.768178f) + X107 * F(-0.375330f)); + S.at(0, 3) = X106; + S.at(1, 0) = D(X111 * F(0.906127f) + X113 * F(-0.318190f) + X115 * F(0.212608f) + X117 * F(-0.180240f)); + S.at(1, 1) = X112; + S.at(1, 2) = D(X111 * F(-0.074658f) + X113 * F(0.513280f) + X115 * F(0.768178f) + X117 * F(-0.375330f)); + S.at(1, 3) = X116; + S.at(2, 0) = D(X121 * F(0.906127f) + X123 * F(-0.318190f) + X125 * F(0.212608f) + X127 * F(-0.180240f)); + S.at(2, 1) = X122; + S.at(2, 2) = D(X121 * F(-0.074658f) + X123 * F(0.513280f) + X125 * F(0.768178f) + X127 * F(-0.375330f)); + S.at(2, 3) = X126; + S.at(3, 0) = D(X131 * F(0.906127f) + X133 * F(-0.318190f) + X135 * F(0.212608f) + X137 * F(-0.180240f)); + S.at(3, 1) = X132; + S.at(3, 2) = D(X131 * F(-0.074658f) + X133 * F(0.513280f) + X135 * F(0.768178f) + X137 * F(-0.375330f)); + S.at(3, 3) = X136; + // 40 muls 24 adds + } + }; +} // end namespace DCT_Upsample + +// Unconditionally frees all allocated m_blocks. +void jpeg_decoder::free_all_blocks() +{ + m_pStream = NULL; + for (mem_block *b = m_pMem_blocks; b; ) + { + mem_block *n = b->m_pNext; + jpgd_free(b); + b = n; + } + m_pMem_blocks = NULL; +} + +// This method handles all errors. It will never return. +// It could easily be changed to use C++ exceptions. +JPGD_NORETURN void jpeg_decoder::stop_decoding(jpgd_status status) +{ + m_error_code = status; + free_all_blocks(); + longjmp(m_jmp_state, status); +} + +void *jpeg_decoder::alloc(size_t nSize, bool zero) +{ + nSize = (JPGD_MAX(nSize, 1) + 3) & ~3; + char *rv = NULL; + for (mem_block *b = m_pMem_blocks; b; b = b->m_pNext) + { + if ((b->m_used_count + nSize) <= b->m_size) + { + rv = b->m_data + b->m_used_count; + b->m_used_count += nSize; + break; + } + } + if (!rv) + { + int capacity = JPGD_MAX(32768 - 256, (nSize + 2047) & ~2047); + mem_block *b = (mem_block*)jpgd_malloc(sizeof(mem_block) + capacity); + if (!b) { stop_decoding(JPGD_NOTENOUGHMEM); } + b->m_pNext = m_pMem_blocks; m_pMem_blocks = b; + b->m_used_count = nSize; + b->m_size = capacity; + rv = b->m_data; + } + if (zero) memset(rv, 0, nSize); + return rv; +} + +void jpeg_decoder::word_clear(void *p, uint16 c, uint n) +{ + uint8 *pD = (uint8*)p; + const uint8 l = c & 0xFF, h = (c >> 8) & 0xFF; + while (n) + { + pD[0] = l; pD[1] = h; pD += 2; + n--; + } +} + +// Refill the input buffer. +// This method will sit in a loop until (A) the buffer is full or (B) +// the stream's read() method reports and end of file condition. +void jpeg_decoder::prep_in_buffer() +{ + m_in_buf_left = 0; + m_pIn_buf_ofs = m_in_buf; + + if (m_eof_flag) + return; + + do + { + int bytes_read = m_pStream->read(m_in_buf + m_in_buf_left, JPGD_IN_BUF_SIZE - m_in_buf_left, &m_eof_flag); + if (bytes_read == -1) + stop_decoding(JPGD_STREAM_READ); + + m_in_buf_left += bytes_read; + } while ((m_in_buf_left < JPGD_IN_BUF_SIZE) && (!m_eof_flag)); + + m_total_bytes_read += m_in_buf_left; + + // Pad the end of the block with M_EOI (prevents the decompressor from going off the rails if the stream is invalid). + // (This dates way back to when this decompressor was written in C/asm, and the all-asm Huffman decoder did some fancy things to increase perf.) + word_clear(m_pIn_buf_ofs + m_in_buf_left, 0xD9FF, 64); +} + +// Read a Huffman code table. +void jpeg_decoder::read_dht_marker() +{ + int i, index, count; + uint8 huff_num[17]; + uint8 huff_val[256]; + + uint num_left = get_bits(16); + + if (num_left < 2) + stop_decoding(JPGD_BAD_DHT_MARKER); + + num_left -= 2; + + while (num_left) + { + index = get_bits(8); + + huff_num[0] = 0; + + count = 0; + + for (i = 1; i <= 16; i++) + { + huff_num[i] = static_cast<uint8>(get_bits(8)); + count += huff_num[i]; + } + + if (count > 255) + stop_decoding(JPGD_BAD_DHT_COUNTS); + + for (i = 0; i < count; i++) + huff_val[i] = static_cast<uint8>(get_bits(8)); + + i = 1 + 16 + count; + + if (num_left < (uint)i) + stop_decoding(JPGD_BAD_DHT_MARKER); + + num_left -= i; + + if ((index & 0x10) > 0x10) + stop_decoding(JPGD_BAD_DHT_INDEX); + + index = (index & 0x0F) + ((index & 0x10) >> 4) * (JPGD_MAX_HUFF_TABLES >> 1); + + if (index >= JPGD_MAX_HUFF_TABLES) + stop_decoding(JPGD_BAD_DHT_INDEX); + + if (!m_huff_num[index]) + m_huff_num[index] = (uint8 *)alloc(17); + + if (!m_huff_val[index]) + m_huff_val[index] = (uint8 *)alloc(256); + + m_huff_ac[index] = (index & 0x10) != 0; + memcpy(m_huff_num[index], huff_num, 17); + memcpy(m_huff_val[index], huff_val, 256); + } +} + +// Read a quantization table. +void jpeg_decoder::read_dqt_marker() +{ + int n, i, prec; + uint num_left; + uint temp; + + num_left = get_bits(16); + + if (num_left < 2) + stop_decoding(JPGD_BAD_DQT_MARKER); + + num_left -= 2; + + while (num_left) + { + n = get_bits(8); + prec = n >> 4; + n &= 0x0F; + + if (n >= JPGD_MAX_QUANT_TABLES) + stop_decoding(JPGD_BAD_DQT_TABLE); + + if (!m_quant[n]) + m_quant[n] = (jpgd_quant_t *)alloc(64 * sizeof(jpgd_quant_t)); + + // read quantization entries, in zag order + for (i = 0; i < 64; i++) + { + temp = get_bits(8); + + if (prec) + temp = (temp << 8) + get_bits(8); + + m_quant[n][i] = static_cast<jpgd_quant_t>(temp); + } + + i = 64 + 1; + + if (prec) + i += 64; + + if (num_left < (uint)i) + stop_decoding(JPGD_BAD_DQT_LENGTH); + + num_left -= i; + } +} + +// Read the start of frame (SOF) marker. +void jpeg_decoder::read_sof_marker() +{ + int i; + uint num_left; + + num_left = get_bits(16); + + if (get_bits(8) != 8) /* precision: sorry, only 8-bit precision is supported right now */ + stop_decoding(JPGD_BAD_PRECISION); + + m_image_y_size = get_bits(16); + + if ((m_image_y_size < 1) || (m_image_y_size > JPGD_MAX_HEIGHT)) + stop_decoding(JPGD_BAD_HEIGHT); + + m_image_x_size = get_bits(16); + + if ((m_image_x_size < 1) || (m_image_x_size > JPGD_MAX_WIDTH)) + stop_decoding(JPGD_BAD_WIDTH); + + m_comps_in_frame = get_bits(8); + + if (m_comps_in_frame > JPGD_MAX_COMPONENTS) + stop_decoding(JPGD_TOO_MANY_COMPONENTS); + + if (num_left != (uint)(m_comps_in_frame * 3 + 8)) + stop_decoding(JPGD_BAD_SOF_LENGTH); + + for (i = 0; i < m_comps_in_frame; i++) + { + m_comp_ident[i] = get_bits(8); + m_comp_h_samp[i] = get_bits(4); + m_comp_v_samp[i] = get_bits(4); + m_comp_quant[i] = get_bits(8); + } +} + +// Used to skip unrecognized markers. +void jpeg_decoder::skip_variable_marker() +{ + uint num_left; + + num_left = get_bits(16); + + if (num_left < 2) + stop_decoding(JPGD_BAD_VARIABLE_MARKER); + + num_left -= 2; + + while (num_left) + { + get_bits(8); + num_left--; + } +} + +// Read a define restart interval (DRI) marker. +void jpeg_decoder::read_dri_marker() +{ + if (get_bits(16) != 4) + stop_decoding(JPGD_BAD_DRI_LENGTH); + + m_restart_interval = get_bits(16); +} + +// Read a start of scan (SOS) marker. +void jpeg_decoder::read_sos_marker() +{ + uint num_left; + int i, ci, n, c, cc; + + num_left = get_bits(16); + + n = get_bits(8); + + m_comps_in_scan = n; + + num_left -= 3; + + if ( (num_left != (uint)(n * 2 + 3)) || (n < 1) || (n > JPGD_MAX_COMPS_IN_SCAN) ) + stop_decoding(JPGD_BAD_SOS_LENGTH); + + for (i = 0; i < n; i++) + { + cc = get_bits(8); + c = get_bits(8); + num_left -= 2; + + for (ci = 0; ci < m_comps_in_frame; ci++) + if (cc == m_comp_ident[ci]) + break; + + if (ci >= m_comps_in_frame) + stop_decoding(JPGD_BAD_SOS_COMP_ID); + + m_comp_list[i] = ci; + m_comp_dc_tab[ci] = (c >> 4) & 15; + m_comp_ac_tab[ci] = (c & 15) + (JPGD_MAX_HUFF_TABLES >> 1); + } + + m_spectral_start = get_bits(8); + m_spectral_end = get_bits(8); + m_successive_high = get_bits(4); + m_successive_low = get_bits(4); + + if (!m_progressive_flag) + { + m_spectral_start = 0; + m_spectral_end = 63; + } + + num_left -= 3; + + while (num_left) /* read past whatever is num_left */ + { + get_bits(8); + num_left--; + } +} + +// Finds the next marker. +int jpeg_decoder::next_marker() +{ + uint c, bytes; + + bytes = 0; + + do + { + do + { + bytes++; + c = get_bits(8); + } while (c != 0xFF); + + do + { + c = get_bits(8); + } while (c == 0xFF); + + } while (c == 0); + + // If bytes > 0 here, there where extra bytes before the marker (not good). + + return c; +} + +// Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is +// encountered. +int jpeg_decoder::process_markers() +{ + int c; + + for ( ; ; ) + { + c = next_marker(); + + switch (c) + { + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: +// case M_JPG: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + case M_SOI: + case M_EOI: + case M_SOS: + { + return c; + } + case M_DHT: + { + read_dht_marker(); + break; + } + // No arithmitic support - dumb patents! + case M_DAC: + { + stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT); + break; + } + case M_DQT: + { + read_dqt_marker(); + break; + } + case M_DRI: + { + read_dri_marker(); + break; + } + //case M_APP0: /* no need to read the JFIF marker */ + + case M_JPG: + case M_RST0: /* no parameters */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + { + stop_decoding(JPGD_UNEXPECTED_MARKER); + break; + } + default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */ + { + skip_variable_marker(); + break; + } + } + } +} + +// Finds the start of image (SOI) marker. +// This code is rather defensive: it only checks the first 512 bytes to avoid +// false positives. +void jpeg_decoder::locate_soi_marker() +{ + uint lastchar, thischar; + uint bytesleft; + + lastchar = get_bits(8); + + thischar = get_bits(8); + + /* ok if it's a normal JPEG file without a special header */ + + if ((lastchar == 0xFF) && (thischar == M_SOI)) + return; + + bytesleft = 4096; //512; + + for ( ; ; ) + { + if (--bytesleft == 0) + stop_decoding(JPGD_NOT_JPEG); + + lastchar = thischar; + + thischar = get_bits(8); + + if (lastchar == 0xFF) + { + if (thischar == M_SOI) + break; + else if (thischar == M_EOI) // get_bits will keep returning M_EOI if we read past the end + stop_decoding(JPGD_NOT_JPEG); + } + } + + // Check the next character after marker: if it's not 0xFF, it can't be the start of the next marker, so the file is bad. + thischar = (m_bit_buf >> 24) & 0xFF; + + if (thischar != 0xFF) + stop_decoding(JPGD_NOT_JPEG); +} + +// Find a start of frame (SOF) marker. +void jpeg_decoder::locate_sof_marker() +{ + locate_soi_marker(); + + int c = process_markers(); + + switch (c) + { + case M_SOF2: + m_progressive_flag = JPGD_TRUE; + case M_SOF0: /* baseline DCT */ + case M_SOF1: /* extended sequential DCT */ + { + read_sof_marker(); + break; + } + case M_SOF9: /* Arithmitic coding */ + { + stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT); + break; + } + default: + { + stop_decoding(JPGD_UNSUPPORTED_MARKER); + break; + } + } +} + +// Find a start of scan (SOS) marker. +int jpeg_decoder::locate_sos_marker() +{ + int c; + + c = process_markers(); + + if (c == M_EOI) + return JPGD_FALSE; + else if (c != M_SOS) + stop_decoding(JPGD_UNEXPECTED_MARKER); + + read_sos_marker(); + + return JPGD_TRUE; +} + +// Reset everything to default/uninitialized state. +void jpeg_decoder::init(jpeg_decoder_stream *pStream) +{ + m_pMem_blocks = NULL; + m_error_code = JPGD_SUCCESS; + m_ready_flag = false; + m_image_x_size = m_image_y_size = 0; + m_pStream = pStream; + m_progressive_flag = JPGD_FALSE; + + memset(m_huff_ac, 0, sizeof(m_huff_ac)); + memset(m_huff_num, 0, sizeof(m_huff_num)); + memset(m_huff_val, 0, sizeof(m_huff_val)); + memset(m_quant, 0, sizeof(m_quant)); + + m_scan_type = 0; + m_comps_in_frame = 0; + + memset(m_comp_h_samp, 0, sizeof(m_comp_h_samp)); + memset(m_comp_v_samp, 0, sizeof(m_comp_v_samp)); + memset(m_comp_quant, 0, sizeof(m_comp_quant)); + memset(m_comp_ident, 0, sizeof(m_comp_ident)); + memset(m_comp_h_blocks, 0, sizeof(m_comp_h_blocks)); + memset(m_comp_v_blocks, 0, sizeof(m_comp_v_blocks)); + + m_comps_in_scan = 0; + memset(m_comp_list, 0, sizeof(m_comp_list)); + memset(m_comp_dc_tab, 0, sizeof(m_comp_dc_tab)); + memset(m_comp_ac_tab, 0, sizeof(m_comp_ac_tab)); + + m_spectral_start = 0; + m_spectral_end = 0; + m_successive_low = 0; + m_successive_high = 0; + m_max_mcu_x_size = 0; + m_max_mcu_y_size = 0; + m_blocks_per_mcu = 0; + m_max_blocks_per_row = 0; + m_mcus_per_row = 0; + m_mcus_per_col = 0; + m_expanded_blocks_per_component = 0; + m_expanded_blocks_per_mcu = 0; + m_expanded_blocks_per_row = 0; + m_freq_domain_chroma_upsample = false; + + memset(m_mcu_org, 0, sizeof(m_mcu_org)); + + m_total_lines_left = 0; + m_mcu_lines_left = 0; + m_real_dest_bytes_per_scan_line = 0; + m_dest_bytes_per_scan_line = 0; + m_dest_bytes_per_pixel = 0; + + memset(m_pHuff_tabs, 0, sizeof(m_pHuff_tabs)); + + memset(m_dc_coeffs, 0, sizeof(m_dc_coeffs)); + memset(m_ac_coeffs, 0, sizeof(m_ac_coeffs)); + memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu)); + + m_eob_run = 0; + + memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu)); + + m_pIn_buf_ofs = m_in_buf; + m_in_buf_left = 0; + m_eof_flag = false; + m_tem_flag = 0; + + memset(m_in_buf_pad_start, 0, sizeof(m_in_buf_pad_start)); + memset(m_in_buf, 0, sizeof(m_in_buf)); + memset(m_in_buf_pad_end, 0, sizeof(m_in_buf_pad_end)); + + m_restart_interval = 0; + m_restarts_left = 0; + m_next_restart_num = 0; + + m_max_mcus_per_row = 0; + m_max_blocks_per_mcu = 0; + m_max_mcus_per_col = 0; + + memset(m_last_dc_val, 0, sizeof(m_last_dc_val)); + m_pMCU_coefficients = NULL; + m_pSample_buf = NULL; + + m_total_bytes_read = 0; + + m_pScan_line_0 = NULL; + m_pScan_line_1 = NULL; + + // Ready the input buffer. + prep_in_buffer(); + + // Prime the bit buffer. + m_bits_left = 16; + m_bit_buf = 0; + + get_bits(16); + get_bits(16); + + for (int i = 0; i < JPGD_MAX_BLOCKS_PER_MCU; i++) + m_mcu_block_max_zag[i] = 64; +} + +#define SCALEBITS 16 +#define ONE_HALF ((int) 1 << (SCALEBITS-1)) +#define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5f)) + +// Create a few tables that allow us to quickly convert YCbCr to RGB. +void jpeg_decoder::create_look_ups() +{ + for (int i = 0; i <= 255; i++) + { + int k = i - 128; + m_crr[i] = ( FIX(1.40200f) * k + ONE_HALF) >> SCALEBITS; + m_cbb[i] = ( FIX(1.77200f) * k + ONE_HALF) >> SCALEBITS; + m_crg[i] = (-FIX(0.71414f)) * k; + m_cbg[i] = (-FIX(0.34414f)) * k + ONE_HALF; + } +} + +// This method throws back into the stream any bytes that where read +// into the bit buffer during initial marker scanning. +void jpeg_decoder::fix_in_buffer() +{ + // In case any 0xFF's where pulled into the buffer during marker scanning. + JPGD_ASSERT((m_bits_left & 7) == 0); + + if (m_bits_left == 16) + stuff_char( (uint8)(m_bit_buf & 0xFF)); + + if (m_bits_left >= 8) + stuff_char( (uint8)((m_bit_buf >> 8) & 0xFF)); + + stuff_char((uint8)((m_bit_buf >> 16) & 0xFF)); + stuff_char((uint8)((m_bit_buf >> 24) & 0xFF)); + + m_bits_left = 16; + get_bits_no_markers(16); + get_bits_no_markers(16); +} + +void jpeg_decoder::transform_mcu(int mcu_row) +{ + jpgd_block_t* pSrc_ptr = m_pMCU_coefficients; + uint8* pDst_ptr = m_pSample_buf + mcu_row * m_blocks_per_mcu * 64; + + for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++) + { + idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block]); + pSrc_ptr += 64; + pDst_ptr += 64; + } +} + +static const uint8 s_max_rc[64] = +{ + 17, 18, 34, 50, 50, 51, 52, 52, 52, 68, 84, 84, 84, 84, 85, 86, 86, 86, 86, 86, + 102, 118, 118, 118, 118, 118, 118, 119, 120, 120, 120, 120, 120, 120, 120, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136 +}; + +void jpeg_decoder::transform_mcu_expand(int mcu_row) +{ + jpgd_block_t* pSrc_ptr = m_pMCU_coefficients; + uint8* pDst_ptr = m_pSample_buf + mcu_row * m_expanded_blocks_per_mcu * 64; + + // Y IDCT + int mcu_block; + for (mcu_block = 0; mcu_block < m_expanded_blocks_per_component; mcu_block++) + { + idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block]); + pSrc_ptr += 64; + pDst_ptr += 64; + } + + // Chroma IDCT, with upsampling + jpgd_block_t temp_block[64]; + + for (int i = 0; i < 2; i++) + { + DCT_Upsample::Matrix44 P, Q, R, S; + + JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] >= 1); + JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] <= 64); + + int max_zag = m_mcu_block_max_zag[mcu_block++] - 1; + if (max_zag <= 0) max_zag = 0; // should never happen, only here to shut up static analysis + switch (s_max_rc[max_zag]) + { + case 1*16+1: + DCT_Upsample::P_Q<1, 1>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<1, 1>::calc(R, S, pSrc_ptr); + break; + case 1*16+2: + DCT_Upsample::P_Q<1, 2>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<1, 2>::calc(R, S, pSrc_ptr); + break; + case 2*16+2: + DCT_Upsample::P_Q<2, 2>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<2, 2>::calc(R, S, pSrc_ptr); + break; + case 3*16+2: + DCT_Upsample::P_Q<3, 2>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<3, 2>::calc(R, S, pSrc_ptr); + break; + case 3*16+3: + DCT_Upsample::P_Q<3, 3>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<3, 3>::calc(R, S, pSrc_ptr); + break; + case 3*16+4: + DCT_Upsample::P_Q<3, 4>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<3, 4>::calc(R, S, pSrc_ptr); + break; + case 4*16+4: + DCT_Upsample::P_Q<4, 4>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<4, 4>::calc(R, S, pSrc_ptr); + break; + case 5*16+4: + DCT_Upsample::P_Q<5, 4>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<5, 4>::calc(R, S, pSrc_ptr); + break; + case 5*16+5: + DCT_Upsample::P_Q<5, 5>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<5, 5>::calc(R, S, pSrc_ptr); + break; + case 5*16+6: + DCT_Upsample::P_Q<5, 6>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<5, 6>::calc(R, S, pSrc_ptr); + break; + case 6*16+6: + DCT_Upsample::P_Q<6, 6>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<6, 6>::calc(R, S, pSrc_ptr); + break; + case 7*16+6: + DCT_Upsample::P_Q<7, 6>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<7, 6>::calc(R, S, pSrc_ptr); + break; + case 7*16+7: + DCT_Upsample::P_Q<7, 7>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<7, 7>::calc(R, S, pSrc_ptr); + break; + case 7*16+8: + DCT_Upsample::P_Q<7, 8>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<7, 8>::calc(R, S, pSrc_ptr); + break; + case 8*16+8: + DCT_Upsample::P_Q<8, 8>::calc(P, Q, pSrc_ptr); + DCT_Upsample::R_S<8, 8>::calc(R, S, pSrc_ptr); + break; + default: + JPGD_ASSERT(false); + } + + DCT_Upsample::Matrix44 a(P + Q); P -= Q; + DCT_Upsample::Matrix44& b = P; + DCT_Upsample::Matrix44 c(R + S); R -= S; + DCT_Upsample::Matrix44& d = R; + + DCT_Upsample::Matrix44::add_and_store(temp_block, a, c); + idct_4x4(temp_block, pDst_ptr); + pDst_ptr += 64; + + DCT_Upsample::Matrix44::sub_and_store(temp_block, a, c); + idct_4x4(temp_block, pDst_ptr); + pDst_ptr += 64; + + DCT_Upsample::Matrix44::add_and_store(temp_block, b, d); + idct_4x4(temp_block, pDst_ptr); + pDst_ptr += 64; + + DCT_Upsample::Matrix44::sub_and_store(temp_block, b, d); + idct_4x4(temp_block, pDst_ptr); + pDst_ptr += 64; + + pSrc_ptr += 64; + } +} + +// Loads and dequantizes the next row of (already decoded) coefficients. +// Progressive images only. +void jpeg_decoder::load_next_row() +{ + int i; + jpgd_block_t *p; + jpgd_quant_t *q; + int mcu_row, mcu_block, row_block = 0; + int component_num, component_id; + int block_x_mcu[JPGD_MAX_COMPONENTS]; + + memset(block_x_mcu, 0, JPGD_MAX_COMPONENTS * sizeof(int)); + + for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++) + { + int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0; + + for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++) + { + component_id = m_mcu_org[mcu_block]; + q = m_quant[m_comp_quant[component_id]]; + + p = m_pMCU_coefficients + 64 * mcu_block; + + jpgd_block_t* pAC = coeff_buf_getp(m_ac_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs); + jpgd_block_t* pDC = coeff_buf_getp(m_dc_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs); + p[0] = pDC[0]; + memcpy(&p[1], &pAC[1], 63 * sizeof(jpgd_block_t)); + + for (i = 63; i > 0; i--) + if (p[g_ZAG[i]]) + break; + + m_mcu_block_max_zag[mcu_block] = i + 1; + + for ( ; i >= 0; i--) + if (p[g_ZAG[i]]) + p[g_ZAG[i]] = static_cast<jpgd_block_t>(p[g_ZAG[i]] * q[i]); + + row_block++; + + if (m_comps_in_scan == 1) + block_x_mcu[component_id]++; + else + { + if (++block_x_mcu_ofs == m_comp_h_samp[component_id]) + { + block_x_mcu_ofs = 0; + + if (++block_y_mcu_ofs == m_comp_v_samp[component_id]) + { + block_y_mcu_ofs = 0; + + block_x_mcu[component_id] += m_comp_h_samp[component_id]; + } + } + } + } + + if (m_freq_domain_chroma_upsample) + transform_mcu_expand(mcu_row); + else + transform_mcu(mcu_row); + } + + if (m_comps_in_scan == 1) + m_block_y_mcu[m_comp_list[0]]++; + else + { + for (component_num = 0; component_num < m_comps_in_scan; component_num++) + { + component_id = m_comp_list[component_num]; + + m_block_y_mcu[component_id] += m_comp_v_samp[component_id]; + } + } +} + +// Restart interval processing. +void jpeg_decoder::process_restart() +{ + int i; + int c = 0; + + // Align to a byte boundry + // FIXME: Is this really necessary? get_bits_no_markers() never reads in markers! + //get_bits_no_markers(m_bits_left & 7); + + // Let's scan a little bit to find the marker, but not _too_ far. + // 1536 is a "fudge factor" that determines how much to scan. + for (i = 1536; i > 0; i--) + if (get_char() == 0xFF) + break; + + if (i == 0) + stop_decoding(JPGD_BAD_RESTART_MARKER); + + for ( ; i > 0; i--) + if ((c = get_char()) != 0xFF) + break; + + if (i == 0) + stop_decoding(JPGD_BAD_RESTART_MARKER); + + // Is it the expected marker? If not, something bad happened. + if (c != (m_next_restart_num + M_RST0)) + stop_decoding(JPGD_BAD_RESTART_MARKER); + + // Reset each component's DC prediction values. + memset(&m_last_dc_val, 0, m_comps_in_frame * sizeof(uint)); + + m_eob_run = 0; + + m_restarts_left = m_restart_interval; + + m_next_restart_num = (m_next_restart_num + 1) & 7; + + // Get the bit buffer going again... + + m_bits_left = 16; + get_bits_no_markers(16); + get_bits_no_markers(16); +} + +static inline int dequantize_ac(int c, int q) { c *= q; return c; } + +// Decodes and dequantizes the next row of coefficients. +void jpeg_decoder::decode_next_row() +{ + int row_block = 0; + + for (int mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++) + { + if ((m_restart_interval) && (m_restarts_left == 0)) + process_restart(); + + jpgd_block_t* p = m_pMCU_coefficients; + for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++, p += 64) + { + int component_id = m_mcu_org[mcu_block]; + jpgd_quant_t* q = m_quant[m_comp_quant[component_id]]; + + int r, s; + s = huff_decode(m_pHuff_tabs[m_comp_dc_tab[component_id]], r); + s = JPGD_HUFF_EXTEND(r, s); + + m_last_dc_val[component_id] = (s += m_last_dc_val[component_id]); + + p[0] = static_cast<jpgd_block_t>(s * q[0]); + + int prev_num_set = m_mcu_block_max_zag[mcu_block]; + + huff_tables *pH = m_pHuff_tabs[m_comp_ac_tab[component_id]]; + + int k; + for (k = 1; k < 64; k++) + { + int extra_bits; + s = huff_decode(pH, extra_bits); + + r = s >> 4; + s &= 15; + + if (s) + { + if (r) + { + if ((k + r) > 63) + stop_decoding(JPGD_DECODE_ERROR); + + if (k < prev_num_set) + { + int n = JPGD_MIN(r, prev_num_set - k); + int kt = k; + while (n--) + p[g_ZAG[kt++]] = 0; + } + + k += r; + } + + s = JPGD_HUFF_EXTEND(extra_bits, s); + + JPGD_ASSERT(k < 64); + + p[g_ZAG[k]] = static_cast<jpgd_block_t>(dequantize_ac(s, q[k])); //s * q[k]; + } + else + { + if (r == 15) + { + if ((k + 16) > 64) + stop_decoding(JPGD_DECODE_ERROR); + + if (k < prev_num_set) + { + int n = JPGD_MIN(16, prev_num_set - k); + int kt = k; + while (n--) + { + JPGD_ASSERT(kt <= 63); + p[g_ZAG[kt++]] = 0; + } + } + + k += 16 - 1; // - 1 because the loop counter is k + JPGD_ASSERT(p[g_ZAG[k]] == 0); + } + else + break; + } + } + + if (k < prev_num_set) + { + int kt = k; + while (kt < prev_num_set) + p[g_ZAG[kt++]] = 0; + } + + m_mcu_block_max_zag[mcu_block] = k; + + row_block++; + } + + if (m_freq_domain_chroma_upsample) + transform_mcu_expand(mcu_row); + else + transform_mcu(mcu_row); + + m_restarts_left--; + } +} + +// YCbCr H1V1 (1x1:1:1, 3 m_blocks per MCU) to RGB +void jpeg_decoder::H1V1Convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8 *d = m_pScan_line_0; + uint8 *s = m_pSample_buf + row * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int j = 0; j < 8; j++) + { + int y = s[j]; + int cb = s[64+j]; + int cr = s[128+j]; + + d[0] = clamp(y + m_crr[cr]); + d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16)); + d[2] = clamp(y + m_cbb[cb]); + d[3] = 255; + + d += 4; + } + + s += 64*3; + } +} + +// YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB +void jpeg_decoder::H2V1Convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8 *d0 = m_pScan_line_0; + uint8 *y = m_pSample_buf + row * 8; + uint8 *c = m_pSample_buf + 2*64 + row * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int l = 0; l < 2; l++) + { + for (int j = 0; j < 4; j++) + { + int cb = c[0]; + int cr = c[64]; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + int yy = y[j<<1]; + d0[0] = clamp(yy+rc); + d0[1] = clamp(yy+gc); + d0[2] = clamp(yy+bc); + d0[3] = 255; + + yy = y[(j<<1)+1]; + d0[4] = clamp(yy+rc); + d0[5] = clamp(yy+gc); + d0[6] = clamp(yy+bc); + d0[7] = 255; + + d0 += 8; + + c++; + } + y += 64; + } + + y += 64*4 - 64*2; + c += 64*4 - 8; + } +} + +// YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB +void jpeg_decoder::H1V2Convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8 *d0 = m_pScan_line_0; + uint8 *d1 = m_pScan_line_1; + uint8 *y; + uint8 *c; + + if (row < 8) + y = m_pSample_buf + row * 8; + else + y = m_pSample_buf + 64*1 + (row & 7) * 8; + + c = m_pSample_buf + 64*2 + (row >> 1) * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int j = 0; j < 8; j++) + { + int cb = c[0+j]; + int cr = c[64+j]; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + int yy = y[j]; + d0[0] = clamp(yy+rc); + d0[1] = clamp(yy+gc); + d0[2] = clamp(yy+bc); + d0[3] = 255; + + yy = y[8+j]; + d1[0] = clamp(yy+rc); + d1[1] = clamp(yy+gc); + d1[2] = clamp(yy+bc); + d1[3] = 255; + + d0 += 4; + d1 += 4; + } + + y += 64*4; + c += 64*4; + } +} + +// YCbCr H2V2 (2x2:1:1, 6 m_blocks per MCU) to RGB +void jpeg_decoder::H2V2Convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8 *d0 = m_pScan_line_0; + uint8 *d1 = m_pScan_line_1; + uint8 *y; + uint8 *c; + + if (row < 8) + y = m_pSample_buf + row * 8; + else + y = m_pSample_buf + 64*2 + (row & 7) * 8; + + c = m_pSample_buf + 64*4 + (row >> 1) * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int l = 0; l < 2; l++) + { + for (int j = 0; j < 8; j += 2) + { + int cb = c[0]; + int cr = c[64]; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + int yy = y[j]; + d0[0] = clamp(yy+rc); + d0[1] = clamp(yy+gc); + d0[2] = clamp(yy+bc); + d0[3] = 255; + + yy = y[j+1]; + d0[4] = clamp(yy+rc); + d0[5] = clamp(yy+gc); + d0[6] = clamp(yy+bc); + d0[7] = 255; + + yy = y[j+8]; + d1[0] = clamp(yy+rc); + d1[1] = clamp(yy+gc); + d1[2] = clamp(yy+bc); + d1[3] = 255; + + yy = y[j+8+1]; + d1[4] = clamp(yy+rc); + d1[5] = clamp(yy+gc); + d1[6] = clamp(yy+bc); + d1[7] = 255; + + d0 += 8; + d1 += 8; + + c++; + } + y += 64; + } + + y += 64*6 - 64*2; + c += 64*6 - 8; + } +} + +// Y (1 block per MCU) to 8-bit grayscale +void jpeg_decoder::gray_convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8 *d = m_pScan_line_0; + uint8 *s = m_pSample_buf + row * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + *(uint *)d = *(uint *)s; + *(uint *)(&d[4]) = *(uint *)(&s[4]); + + s += 64; + d += 8; + } +} + +void jpeg_decoder::expanded_convert() +{ + int row = m_max_mcu_y_size - m_mcu_lines_left; + + uint8* Py = m_pSample_buf + (row / 8) * 64 * m_comp_h_samp[0] + (row & 7) * 8; + + uint8* d = m_pScan_line_0; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int k = 0; k < m_max_mcu_x_size; k += 8) + { + const int Y_ofs = k * 8; + const int Cb_ofs = Y_ofs + 64 * m_expanded_blocks_per_component; + const int Cr_ofs = Y_ofs + 64 * m_expanded_blocks_per_component * 2; + for (int j = 0; j < 8; j++) + { + int y = Py[Y_ofs + j]; + int cb = Py[Cb_ofs + j]; + int cr = Py[Cr_ofs + j]; + + d[0] = clamp(y + m_crr[cr]); + d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16)); + d[2] = clamp(y + m_cbb[cb]); + d[3] = 255; + + d += 4; + } + } + + Py += 64 * m_expanded_blocks_per_mcu; + } +} + +// Find end of image (EOI) marker, so we can return to the user the exact size of the input stream. +void jpeg_decoder::find_eoi() +{ + if (!m_progressive_flag) + { + // Attempt to read the EOI marker. + //get_bits_no_markers(m_bits_left & 7); + + // Prime the bit buffer + m_bits_left = 16; + get_bits(16); + get_bits(16); + + // The next marker _should_ be EOI + process_markers(); + } + + m_total_bytes_read -= m_in_buf_left; +} + +int jpeg_decoder::decode(const void** pScan_line, uint* pScan_line_len) +{ + if ((m_error_code) || (!m_ready_flag)) + return JPGD_FAILED; + + if (m_total_lines_left == 0) + return JPGD_DONE; + + if (m_mcu_lines_left == 0) + { + if (setjmp(m_jmp_state)) + return JPGD_FAILED; + + if (m_progressive_flag) + load_next_row(); + else + decode_next_row(); + + // Find the EOI marker if that was the last row. + if (m_total_lines_left <= m_max_mcu_y_size) + find_eoi(); + + m_mcu_lines_left = m_max_mcu_y_size; + } + + if (m_freq_domain_chroma_upsample) + { + expanded_convert(); + *pScan_line = m_pScan_line_0; + } + else + { + switch (m_scan_type) + { + case JPGD_YH2V2: + { + if ((m_mcu_lines_left & 1) == 0) + { + H2V2Convert(); + *pScan_line = m_pScan_line_0; + } + else + *pScan_line = m_pScan_line_1; + + break; + } + case JPGD_YH2V1: + { + H2V1Convert(); + *pScan_line = m_pScan_line_0; + break; + } + case JPGD_YH1V2: + { + if ((m_mcu_lines_left & 1) == 0) + { + H1V2Convert(); + *pScan_line = m_pScan_line_0; + } + else + *pScan_line = m_pScan_line_1; + + break; + } + case JPGD_YH1V1: + { + H1V1Convert(); + *pScan_line = m_pScan_line_0; + break; + } + case JPGD_GRAYSCALE: + { + gray_convert(); + *pScan_line = m_pScan_line_0; + + break; + } + } + } + + *pScan_line_len = m_real_dest_bytes_per_scan_line; + + m_mcu_lines_left--; + m_total_lines_left--; + + return JPGD_SUCCESS; +} + +// Creates the tables needed for efficient Huffman decoding. +void jpeg_decoder::make_huff_table(int index, huff_tables *pH) +{ + int p, i, l, si; + uint8 huffsize[257]; + uint huffcode[257]; + uint code; + uint subtree; + int code_size; + int lastp; + int nextfreeentry; + int currententry; + + pH->ac_table = m_huff_ac[index] != 0; + + p = 0; + + for (l = 1; l <= 16; l++) + { + for (i = 1; i <= m_huff_num[index][l]; i++) + huffsize[p++] = static_cast<uint8>(l); + } + + huffsize[p] = 0; + + lastp = p; + + code = 0; + si = huffsize[0]; + p = 0; + + while (huffsize[p]) + { + while (huffsize[p] == si) + { + huffcode[p++] = code; + code++; + } + + code <<= 1; + si++; + } + + memset(pH->look_up, 0, sizeof(pH->look_up)); + memset(pH->look_up2, 0, sizeof(pH->look_up2)); + memset(pH->tree, 0, sizeof(pH->tree)); + memset(pH->code_size, 0, sizeof(pH->code_size)); + + nextfreeentry = -1; + + p = 0; + + while (p < lastp) + { + i = m_huff_val[index][p]; + code = huffcode[p]; + code_size = huffsize[p]; + + pH->code_size[i] = static_cast<uint8>(code_size); + + if (code_size <= 8) + { + code <<= (8 - code_size); + + for (l = 1 << (8 - code_size); l > 0; l--) + { + JPGD_ASSERT(i < 256); + + pH->look_up[code] = i; + + bool has_extrabits = false; + int extra_bits = 0; + int num_extra_bits = i & 15; + + int bits_to_fetch = code_size; + if (num_extra_bits) + { + int total_codesize = code_size + num_extra_bits; + if (total_codesize <= 8) + { + has_extrabits = true; + extra_bits = ((1 << num_extra_bits) - 1) & (code >> (8 - total_codesize)); + JPGD_ASSERT(extra_bits <= 0x7FFF); + bits_to_fetch += num_extra_bits; + } + } + + if (!has_extrabits) + pH->look_up2[code] = i | (bits_to_fetch << 8); + else + pH->look_up2[code] = i | 0x8000 | (extra_bits << 16) | (bits_to_fetch << 8); + + code++; + } + } + else + { + subtree = (code >> (code_size - 8)) & 0xFF; + + currententry = pH->look_up[subtree]; + + if (currententry == 0) + { + pH->look_up[subtree] = currententry = nextfreeentry; + pH->look_up2[subtree] = currententry = nextfreeentry; + + nextfreeentry -= 2; + } + + code <<= (16 - (code_size - 8)); + + for (l = code_size; l > 9; l--) + { + if ((code & 0x8000) == 0) + currententry--; + + if (pH->tree[-currententry - 1] == 0) + { + pH->tree[-currententry - 1] = nextfreeentry; + + currententry = nextfreeentry; + + nextfreeentry -= 2; + } + else + currententry = pH->tree[-currententry - 1]; + + code <<= 1; + } + + if ((code & 0x8000) == 0) + currententry--; + + pH->tree[-currententry - 1] = i; + } + + p++; + } +} + +// Verifies the quantization tables needed for this scan are available. +void jpeg_decoder::check_quant_tables() +{ + for (int i = 0; i < m_comps_in_scan; i++) + if (m_quant[m_comp_quant[m_comp_list[i]]] == NULL) + stop_decoding(JPGD_UNDEFINED_QUANT_TABLE); +} + +// Verifies that all the Huffman tables needed for this scan are available. +void jpeg_decoder::check_huff_tables() +{ + for (int i = 0; i < m_comps_in_scan; i++) + { + if ((m_spectral_start == 0) && (m_huff_num[m_comp_dc_tab[m_comp_list[i]]] == NULL)) + stop_decoding(JPGD_UNDEFINED_HUFF_TABLE); + + if ((m_spectral_end > 0) && (m_huff_num[m_comp_ac_tab[m_comp_list[i]]] == NULL)) + stop_decoding(JPGD_UNDEFINED_HUFF_TABLE); + } + + for (int i = 0; i < JPGD_MAX_HUFF_TABLES; i++) + if (m_huff_num[i]) + { + if (!m_pHuff_tabs[i]) + m_pHuff_tabs[i] = (huff_tables *)alloc(sizeof(huff_tables)); + + make_huff_table(i, m_pHuff_tabs[i]); + } +} + +// Determines the component order inside each MCU. +// Also calcs how many MCU's are on each row, etc. +void jpeg_decoder::calc_mcu_block_order() +{ + int component_num, component_id; + int max_h_samp = 0, max_v_samp = 0; + + for (component_id = 0; component_id < m_comps_in_frame; component_id++) + { + if (m_comp_h_samp[component_id] > max_h_samp) + max_h_samp = m_comp_h_samp[component_id]; + + if (m_comp_v_samp[component_id] > max_v_samp) + max_v_samp = m_comp_v_samp[component_id]; + } + + for (component_id = 0; component_id < m_comps_in_frame; component_id++) + { + m_comp_h_blocks[component_id] = ((((m_image_x_size * m_comp_h_samp[component_id]) + (max_h_samp - 1)) / max_h_samp) + 7) / 8; + m_comp_v_blocks[component_id] = ((((m_image_y_size * m_comp_v_samp[component_id]) + (max_v_samp - 1)) / max_v_samp) + 7) / 8; + } + + if (m_comps_in_scan == 1) + { + m_mcus_per_row = m_comp_h_blocks[m_comp_list[0]]; + m_mcus_per_col = m_comp_v_blocks[m_comp_list[0]]; + } + else + { + m_mcus_per_row = (((m_image_x_size + 7) / 8) + (max_h_samp - 1)) / max_h_samp; + m_mcus_per_col = (((m_image_y_size + 7) / 8) + (max_v_samp - 1)) / max_v_samp; + } + + if (m_comps_in_scan == 1) + { + m_mcu_org[0] = m_comp_list[0]; + + m_blocks_per_mcu = 1; + } + else + { + m_blocks_per_mcu = 0; + + for (component_num = 0; component_num < m_comps_in_scan; component_num++) + { + int num_blocks; + + component_id = m_comp_list[component_num]; + + num_blocks = m_comp_h_samp[component_id] * m_comp_v_samp[component_id]; + + while (num_blocks--) + m_mcu_org[m_blocks_per_mcu++] = component_id; + } + } +} + +// Starts a new scan. +int jpeg_decoder::init_scan() +{ + if (!locate_sos_marker()) + return JPGD_FALSE; + + calc_mcu_block_order(); + + check_huff_tables(); + + check_quant_tables(); + + memset(m_last_dc_val, 0, m_comps_in_frame * sizeof(uint)); + + m_eob_run = 0; + + if (m_restart_interval) + { + m_restarts_left = m_restart_interval; + m_next_restart_num = 0; + } + + fix_in_buffer(); + + return JPGD_TRUE; +} + +// Starts a frame. Determines if the number of components or sampling factors +// are supported. +void jpeg_decoder::init_frame() +{ + int i; + + if (m_comps_in_frame == 1) + { + if ((m_comp_h_samp[0] != 1) || (m_comp_v_samp[0] != 1)) + stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS); + + m_scan_type = JPGD_GRAYSCALE; + m_max_blocks_per_mcu = 1; + m_max_mcu_x_size = 8; + m_max_mcu_y_size = 8; + } + else if (m_comps_in_frame == 3) + { + if ( ((m_comp_h_samp[1] != 1) || (m_comp_v_samp[1] != 1)) || + ((m_comp_h_samp[2] != 1) || (m_comp_v_samp[2] != 1)) ) + stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS); + + if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1)) + { + m_scan_type = JPGD_YH1V1; + + m_max_blocks_per_mcu = 3; + m_max_mcu_x_size = 8; + m_max_mcu_y_size = 8; + } + else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1)) + { + m_scan_type = JPGD_YH2V1; + m_max_blocks_per_mcu = 4; + m_max_mcu_x_size = 16; + m_max_mcu_y_size = 8; + } + else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 2)) + { + m_scan_type = JPGD_YH1V2; + m_max_blocks_per_mcu = 4; + m_max_mcu_x_size = 8; + m_max_mcu_y_size = 16; + } + else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2)) + { + m_scan_type = JPGD_YH2V2; + m_max_blocks_per_mcu = 6; + m_max_mcu_x_size = 16; + m_max_mcu_y_size = 16; + } + else + stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS); + } + else + stop_decoding(JPGD_UNSUPPORTED_COLORSPACE); + + m_max_mcus_per_row = (m_image_x_size + (m_max_mcu_x_size - 1)) / m_max_mcu_x_size; + m_max_mcus_per_col = (m_image_y_size + (m_max_mcu_y_size - 1)) / m_max_mcu_y_size; + + // These values are for the *destination* pixels: after conversion. + if (m_scan_type == JPGD_GRAYSCALE) + m_dest_bytes_per_pixel = 1; + else + m_dest_bytes_per_pixel = 4; + + m_dest_bytes_per_scan_line = ((m_image_x_size + 15) & 0xFFF0) * m_dest_bytes_per_pixel; + + m_real_dest_bytes_per_scan_line = (m_image_x_size * m_dest_bytes_per_pixel); + + // Initialize two scan line buffers. + m_pScan_line_0 = (uint8 *)alloc(m_dest_bytes_per_scan_line, true); + if ((m_scan_type == JPGD_YH1V2) || (m_scan_type == JPGD_YH2V2)) + m_pScan_line_1 = (uint8 *)alloc(m_dest_bytes_per_scan_line, true); + + m_max_blocks_per_row = m_max_mcus_per_row * m_max_blocks_per_mcu; + + // Should never happen + if (m_max_blocks_per_row > JPGD_MAX_BLOCKS_PER_ROW) + stop_decoding(JPGD_ASSERTION_ERROR); + + // Allocate the coefficient buffer, enough for one MCU + m_pMCU_coefficients = (jpgd_block_t*)alloc(m_max_blocks_per_mcu * 64 * sizeof(jpgd_block_t)); + + for (i = 0; i < m_max_blocks_per_mcu; i++) + m_mcu_block_max_zag[i] = 64; + + m_expanded_blocks_per_component = m_comp_h_samp[0] * m_comp_v_samp[0]; + m_expanded_blocks_per_mcu = m_expanded_blocks_per_component * m_comps_in_frame; + m_expanded_blocks_per_row = m_max_mcus_per_row * m_expanded_blocks_per_mcu; + // Freq. domain chroma upsampling is only supported for H2V2 subsampling factor (the most common one I've seen). + m_freq_domain_chroma_upsample = false; +#if JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING + m_freq_domain_chroma_upsample = (m_expanded_blocks_per_mcu == 4*3); +#endif + + if (m_freq_domain_chroma_upsample) + m_pSample_buf = (uint8 *)alloc(m_expanded_blocks_per_row * 64); + else + m_pSample_buf = (uint8 *)alloc(m_max_blocks_per_row * 64); + + m_total_lines_left = m_image_y_size; + + m_mcu_lines_left = 0; + + create_look_ups(); +} + +// The coeff_buf series of methods originally stored the coefficients +// into a "virtual" file which was located in EMS, XMS, or a disk file. A cache +// was used to make this process more efficient. Now, we can store the entire +// thing in RAM. +jpeg_decoder::coeff_buf* jpeg_decoder::coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y) +{ + coeff_buf* cb = (coeff_buf*)alloc(sizeof(coeff_buf)); + + cb->block_num_x = block_num_x; + cb->block_num_y = block_num_y; + cb->block_len_x = block_len_x; + cb->block_len_y = block_len_y; + cb->block_size = (block_len_x * block_len_y) * sizeof(jpgd_block_t); + cb->pData = (uint8 *)alloc(cb->block_size * block_num_x * block_num_y, true); + return cb; +} + +inline jpgd_block_t *jpeg_decoder::coeff_buf_getp(coeff_buf *cb, int block_x, int block_y) +{ + JPGD_ASSERT((block_x < cb->block_num_x) && (block_y < cb->block_num_y)); + return (jpgd_block_t *)(cb->pData + block_x * cb->block_size + block_y * (cb->block_size * cb->block_num_x)); +} + +// The following methods decode the various types of m_blocks encountered +// in progressively encoded images. +void jpeg_decoder::decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y) +{ + int s, r; + jpgd_block_t *p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y); + + if ((s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_dc_tab[component_id]])) != 0) + { + r = pD->get_bits_no_markers(s); + s = JPGD_HUFF_EXTEND(r, s); + } + + pD->m_last_dc_val[component_id] = (s += pD->m_last_dc_val[component_id]); + + p[0] = static_cast<jpgd_block_t>(s << pD->m_successive_low); +} + +void jpeg_decoder::decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y) +{ + if (pD->get_bits_no_markers(1)) + { + jpgd_block_t *p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y); + + p[0] |= (1 << pD->m_successive_low); + } +} + +void jpeg_decoder::decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y) +{ + int k, s, r; + + if (pD->m_eob_run) + { + pD->m_eob_run--; + return; + } + + jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y); + + for (k = pD->m_spectral_start; k <= pD->m_spectral_end; k++) + { + s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_ac_tab[component_id]]); + + r = s >> 4; + s &= 15; + + if (s) + { + if ((k += r) > 63) + pD->stop_decoding(JPGD_DECODE_ERROR); + + r = pD->get_bits_no_markers(s); + s = JPGD_HUFF_EXTEND(r, s); + + p[g_ZAG[k]] = static_cast<jpgd_block_t>(s << pD->m_successive_low); + } + else + { + if (r == 15) + { + if ((k += 15) > 63) + pD->stop_decoding(JPGD_DECODE_ERROR); + } + else + { + pD->m_eob_run = 1 << r; + + if (r) + pD->m_eob_run += pD->get_bits_no_markers(r); + + pD->m_eob_run--; + + break; + } + } + } +} + +void jpeg_decoder::decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y) +{ + int s, k, r; + int p1 = 1 << pD->m_successive_low; + int m1 = (-1) << pD->m_successive_low; + jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y); + + JPGD_ASSERT(pD->m_spectral_end <= 63); + + k = pD->m_spectral_start; + + if (pD->m_eob_run == 0) + { + for ( ; k <= pD->m_spectral_end; k++) + { + s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_ac_tab[component_id]]); + + r = s >> 4; + s &= 15; + + if (s) + { + if (s != 1) + pD->stop_decoding(JPGD_DECODE_ERROR); + + if (pD->get_bits_no_markers(1)) + s = p1; + else + s = m1; + } + else + { + if (r != 15) + { + pD->m_eob_run = 1 << r; + + if (r) + pD->m_eob_run += pD->get_bits_no_markers(r); + + break; + } + } + + do + { + jpgd_block_t *this_coef = p + g_ZAG[k & 63]; + + if (*this_coef != 0) + { + if (pD->get_bits_no_markers(1)) + { + if ((*this_coef & p1) == 0) + { + if (*this_coef >= 0) + *this_coef = static_cast<jpgd_block_t>(*this_coef + p1); + else + *this_coef = static_cast<jpgd_block_t>(*this_coef + m1); + } + } + } + else + { + if (--r < 0) + break; + } + + k++; + + } while (k <= pD->m_spectral_end); + + if ((s) && (k < 64)) + { + p[g_ZAG[k]] = static_cast<jpgd_block_t>(s); + } + } + } + + if (pD->m_eob_run > 0) + { + for ( ; k <= pD->m_spectral_end; k++) + { + jpgd_block_t *this_coef = p + g_ZAG[k & 63]; // logical AND to shut up static code analysis + + if (*this_coef != 0) + { + if (pD->get_bits_no_markers(1)) + { + if ((*this_coef & p1) == 0) + { + if (*this_coef >= 0) + *this_coef = static_cast<jpgd_block_t>(*this_coef + p1); + else + *this_coef = static_cast<jpgd_block_t>(*this_coef + m1); + } + } + } + } + + pD->m_eob_run--; + } +} + +// Decode a scan in a progressively encoded image. +void jpeg_decoder::decode_scan(pDecode_block_func decode_block_func) +{ + int mcu_row, mcu_col, mcu_block; + int block_x_mcu[JPGD_MAX_COMPONENTS], m_block_y_mcu[JPGD_MAX_COMPONENTS]; + + memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu)); + + for (mcu_col = 0; mcu_col < m_mcus_per_col; mcu_col++) + { + int component_num, component_id; + + memset(block_x_mcu, 0, sizeof(block_x_mcu)); + + for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++) + { + int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0; + + if ((m_restart_interval) && (m_restarts_left == 0)) + process_restart(); + + for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++) + { + component_id = m_mcu_org[mcu_block]; + + decode_block_func(this, component_id, block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs); + + if (m_comps_in_scan == 1) + block_x_mcu[component_id]++; + else + { + if (++block_x_mcu_ofs == m_comp_h_samp[component_id]) + { + block_x_mcu_ofs = 0; + + if (++block_y_mcu_ofs == m_comp_v_samp[component_id]) + { + block_y_mcu_ofs = 0; + block_x_mcu[component_id] += m_comp_h_samp[component_id]; + } + } + } + } + + m_restarts_left--; + } + + if (m_comps_in_scan == 1) + m_block_y_mcu[m_comp_list[0]]++; + else + { + for (component_num = 0; component_num < m_comps_in_scan; component_num++) + { + component_id = m_comp_list[component_num]; + m_block_y_mcu[component_id] += m_comp_v_samp[component_id]; + } + } + } +} + +// Decode a progressively encoded image. +void jpeg_decoder::init_progressive() +{ + int i; + + if (m_comps_in_frame == 4) + stop_decoding(JPGD_UNSUPPORTED_COLORSPACE); + + // Allocate the coefficient buffers. + for (i = 0; i < m_comps_in_frame; i++) + { + m_dc_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 1, 1); + m_ac_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 8, 8); + } + + for ( ; ; ) + { + int dc_only_scan, refinement_scan; + pDecode_block_func decode_block_func; + + if (!init_scan()) + break; + + dc_only_scan = (m_spectral_start == 0); + refinement_scan = (m_successive_high != 0); + + if ((m_spectral_start > m_spectral_end) || (m_spectral_end > 63)) + stop_decoding(JPGD_BAD_SOS_SPECTRAL); + + if (dc_only_scan) + { + if (m_spectral_end) + stop_decoding(JPGD_BAD_SOS_SPECTRAL); + } + else if (m_comps_in_scan != 1) /* AC scans can only contain one component */ + stop_decoding(JPGD_BAD_SOS_SPECTRAL); + + if ((refinement_scan) && (m_successive_low != m_successive_high - 1)) + stop_decoding(JPGD_BAD_SOS_SUCCESSIVE); + + if (dc_only_scan) + { + if (refinement_scan) + decode_block_func = decode_block_dc_refine; + else + decode_block_func = decode_block_dc_first; + } + else + { + if (refinement_scan) + decode_block_func = decode_block_ac_refine; + else + decode_block_func = decode_block_ac_first; + } + + decode_scan(decode_block_func); + + m_bits_left = 16; + get_bits(16); + get_bits(16); + } + + m_comps_in_scan = m_comps_in_frame; + + for (i = 0; i < m_comps_in_frame; i++) + m_comp_list[i] = i; + + calc_mcu_block_order(); +} + +void jpeg_decoder::init_sequential() +{ + if (!init_scan()) + stop_decoding(JPGD_UNEXPECTED_MARKER); +} + +void jpeg_decoder::decode_start() +{ + init_frame(); + + if (m_progressive_flag) + init_progressive(); + else + init_sequential(); +} + +void jpeg_decoder::decode_init(jpeg_decoder_stream *pStream) +{ + init(pStream); + locate_sof_marker(); +} + +jpeg_decoder::jpeg_decoder(jpeg_decoder_stream *pStream) +{ + if (setjmp(m_jmp_state)) + return; + decode_init(pStream); +} + +int jpeg_decoder::begin_decoding() +{ + if (m_ready_flag) + return JPGD_SUCCESS; + + if (m_error_code) + return JPGD_FAILED; + + if (setjmp(m_jmp_state)) + return JPGD_FAILED; + + decode_start(); + + m_ready_flag = true; + + return JPGD_SUCCESS; +} + +jpeg_decoder::~jpeg_decoder() +{ + free_all_blocks(); +} + +jpeg_decoder_file_stream::jpeg_decoder_file_stream() +{ + m_pFile = NULL; + m_eof_flag = false; + m_error_flag = false; +} + +void jpeg_decoder_file_stream::close() +{ + if (m_pFile) + { + fclose(m_pFile); + m_pFile = NULL; + } + + m_eof_flag = false; + m_error_flag = false; +} + +jpeg_decoder_file_stream::~jpeg_decoder_file_stream() +{ + close(); +} + +bool jpeg_decoder_file_stream::open(const char *Pfilename) +{ + close(); + + m_eof_flag = false; + m_error_flag = false; + +#if defined(_MSC_VER) + m_pFile = NULL; + fopen_s(&m_pFile, Pfilename, "rb"); +#else + m_pFile = fopen(Pfilename, "rb"); +#endif + return m_pFile != NULL; +} + +int jpeg_decoder_file_stream::read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag) +{ + if (!m_pFile) + return -1; + + if (m_eof_flag) + { + *pEOF_flag = true; + return 0; + } + + if (m_error_flag) + return -1; + + int bytes_read = static_cast<int>(fread(pBuf, 1, max_bytes_to_read, m_pFile)); + if (bytes_read < max_bytes_to_read) + { + if (ferror(m_pFile)) + { + m_error_flag = true; + return -1; + } + + m_eof_flag = true; + *pEOF_flag = true; + } + + return bytes_read; +} + +bool jpeg_decoder_mem_stream::open(const uint8 *pSrc_data, uint size) +{ + close(); + m_pSrc_data = pSrc_data; + m_ofs = 0; + m_size = size; + return true; +} + +int jpeg_decoder_mem_stream::read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag) +{ + *pEOF_flag = false; + + if (!m_pSrc_data) + return -1; + + uint bytes_remaining = m_size - m_ofs; + if ((uint)max_bytes_to_read > bytes_remaining) + { + max_bytes_to_read = bytes_remaining; + *pEOF_flag = true; + } + + memcpy(pBuf, m_pSrc_data + m_ofs, max_bytes_to_read); + m_ofs += max_bytes_to_read; + + return max_bytes_to_read; +} + +unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps) +{ + if (!actual_comps) + return NULL; + *actual_comps = 0; + + if ((!pStream) || (!width) || (!height) || (!req_comps)) + return NULL; + + if ((req_comps != 1) && (req_comps != 3) && (req_comps != 4)) + return NULL; + + jpeg_decoder decoder(pStream); + if (decoder.get_error_code() != JPGD_SUCCESS) + return NULL; + + const int image_width = decoder.get_width(), image_height = decoder.get_height(); + *width = image_width; + *height = image_height; + *actual_comps = decoder.get_num_components(); + + if (decoder.begin_decoding() != JPGD_SUCCESS) + return NULL; + + const int dst_bpl = image_width * req_comps; + + uint8 *pImage_data = (uint8*)jpgd_malloc(dst_bpl * image_height); + if (!pImage_data) + return NULL; + + for (int y = 0; y < image_height; y++) + { + const uint8* pScan_line; + uint scan_line_len; + if (decoder.decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS) + { + jpgd_free(pImage_data); + return NULL; + } + + uint8 *pDst = pImage_data + y * dst_bpl; + + if (((req_comps == 1) && (decoder.get_num_components() == 1)) || ((req_comps == 4) && (decoder.get_num_components() == 3))) + memcpy(pDst, pScan_line, dst_bpl); + else if (decoder.get_num_components() == 1) + { + if (req_comps == 3) + { + for (int x = 0; x < image_width; x++) + { + uint8 luma = pScan_line[x]; + pDst[0] = luma; + pDst[1] = luma; + pDst[2] = luma; + pDst += 3; + } + } + else + { + for (int x = 0; x < image_width; x++) + { + uint8 luma = pScan_line[x]; + pDst[0] = luma; + pDst[1] = luma; + pDst[2] = luma; + pDst[3] = 255; + pDst += 4; + } + } + } + else if (decoder.get_num_components() == 3) + { + if (req_comps == 1) + { + const int YR = 19595, YG = 38470, YB = 7471; + for (int x = 0; x < image_width; x++) + { + int r = pScan_line[x*4+0]; + int g = pScan_line[x*4+1]; + int b = pScan_line[x*4+2]; + *pDst++ = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16); + } + } + else + { + for (int x = 0; x < image_width; x++) + { + pDst[0] = pScan_line[x*4+0]; + pDst[1] = pScan_line[x*4+1]; + pDst[2] = pScan_line[x*4+2]; + pDst += 3; + } + } + } + } + + return pImage_data; +} + +unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps) +{ + jpgd::jpeg_decoder_mem_stream mem_stream(pSrc_data, src_data_size); + return decompress_jpeg_image_from_stream(&mem_stream, width, height, actual_comps, req_comps); +} + +unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps) +{ + jpgd::jpeg_decoder_file_stream file_stream; + if (!file_stream.open(pSrc_filename)) + return NULL; + return decompress_jpeg_image_from_stream(&file_stream, width, height, actual_comps, req_comps); +} + +} // namespace jpgd
\ No newline at end of file diff --git a/drivers/jpegd/jpgd.h b/drivers/jpegd/jpgd.h new file mode 100644 index 0000000000..150b9a0b26 --- /dev/null +++ b/drivers/jpegd/jpgd.h @@ -0,0 +1,319 @@ +// jpgd.h - C++ class for JPEG decompression. +// Public domain, Rich Geldreich <richgel99@gmail.com> +#ifndef JPEG_DECODER_H +#define JPEG_DECODER_H + +#include <stdlib.h> +#include <stdio.h> +#include <setjmp.h> + +#ifdef _MSC_VER + #define JPGD_NORETURN __declspec(noreturn) +#elif defined(__GNUC__) + #define JPGD_NORETURN __attribute__ ((noreturn)) +#else + #define JPGD_NORETURN +#endif + +namespace jpgd +{ + typedef unsigned char uint8; + typedef signed short int16; + typedef unsigned short uint16; + typedef unsigned int uint; + typedef signed int int32; + + // Loads a JPEG image from a memory buffer or a file. + // req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA). + // On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB). + // Notes: For more control over where and how the source data is read, see the decompress_jpeg_image_from_stream() function below, or call the jpeg_decoder class directly. + // Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp. + unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps); + unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps); + + // Success/failure error codes. + enum jpgd_status + { + JPGD_SUCCESS = 0, JPGD_FAILED = -1, JPGD_DONE = 1, + JPGD_BAD_DHT_COUNTS = -256, JPGD_BAD_DHT_INDEX, JPGD_BAD_DHT_MARKER, JPGD_BAD_DQT_MARKER, JPGD_BAD_DQT_TABLE, + JPGD_BAD_PRECISION, JPGD_BAD_HEIGHT, JPGD_BAD_WIDTH, JPGD_TOO_MANY_COMPONENTS, + JPGD_BAD_SOF_LENGTH, JPGD_BAD_VARIABLE_MARKER, JPGD_BAD_DRI_LENGTH, JPGD_BAD_SOS_LENGTH, + JPGD_BAD_SOS_COMP_ID, JPGD_W_EXTRA_BYTES_BEFORE_MARKER, JPGD_NO_ARITHMITIC_SUPPORT, JPGD_UNEXPECTED_MARKER, + JPGD_NOT_JPEG, JPGD_UNSUPPORTED_MARKER, JPGD_BAD_DQT_LENGTH, JPGD_TOO_MANY_BLOCKS, + JPGD_UNDEFINED_QUANT_TABLE, JPGD_UNDEFINED_HUFF_TABLE, JPGD_NOT_SINGLE_SCAN, JPGD_UNSUPPORTED_COLORSPACE, + JPGD_UNSUPPORTED_SAMP_FACTORS, JPGD_DECODE_ERROR, JPGD_BAD_RESTART_MARKER, JPGD_ASSERTION_ERROR, + JPGD_BAD_SOS_SPECTRAL, JPGD_BAD_SOS_SUCCESSIVE, JPGD_STREAM_READ, JPGD_NOTENOUGHMEM + }; + + // Input stream interface. + // Derive from this class to read input data from sources other than files or memory. Set m_eof_flag to true when no more data is available. + // The decoder is rather greedy: it will keep on calling this method until its internal input buffer is full, or until the EOF flag is set. + // It the input stream contains data after the JPEG stream's EOI (end of image) marker it will probably be pulled into the internal buffer. + // Call the get_total_bytes_read() method to determine the actual size of the JPEG stream after successful decoding. + class jpeg_decoder_stream + { + public: + jpeg_decoder_stream() { } + virtual ~jpeg_decoder_stream() { } + + // The read() method is called when the internal input buffer is empty. + // Parameters: + // pBuf - input buffer + // max_bytes_to_read - maximum bytes that can be written to pBuf + // pEOF_flag - set this to true if at end of stream (no more bytes remaining) + // Returns -1 on error, otherwise return the number of bytes actually written to the buffer (which may be 0). + // Notes: This method will be called in a loop until you set *pEOF_flag to true or the internal buffer is full. + virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag) = 0; + }; + + // stdio FILE stream class. + class jpeg_decoder_file_stream : public jpeg_decoder_stream + { + jpeg_decoder_file_stream(const jpeg_decoder_file_stream &); + jpeg_decoder_file_stream &operator =(const jpeg_decoder_file_stream &); + + FILE *m_pFile; + bool m_eof_flag, m_error_flag; + + public: + jpeg_decoder_file_stream(); + virtual ~jpeg_decoder_file_stream(); + + bool open(const char *Pfilename); + void close(); + + virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag); + }; + + // Memory stream class. + class jpeg_decoder_mem_stream : public jpeg_decoder_stream + { + const uint8 *m_pSrc_data; + uint m_ofs, m_size; + + public: + jpeg_decoder_mem_stream() : m_pSrc_data(NULL), m_ofs(0), m_size(0) { } + jpeg_decoder_mem_stream(const uint8 *pSrc_data, uint size) : m_pSrc_data(pSrc_data), m_ofs(0), m_size(size) { } + + virtual ~jpeg_decoder_mem_stream() { } + + bool open(const uint8 *pSrc_data, uint size); + void close() { m_pSrc_data = NULL; m_ofs = 0; m_size = 0; } + + virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag); + }; + + // Loads JPEG file from a jpeg_decoder_stream. + unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps); + + enum + { + JPGD_IN_BUF_SIZE = 8192, JPGD_MAX_BLOCKS_PER_MCU = 10, JPGD_MAX_HUFF_TABLES = 8, JPGD_MAX_QUANT_TABLES = 4, + JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 8192, JPGD_MAX_HEIGHT = 16384, JPGD_MAX_WIDTH = 16384 + }; + + typedef int16 jpgd_quant_t; + typedef int16 jpgd_block_t; + + class jpeg_decoder + { + public: + // Call get_error_code() after constructing to determine if the stream is valid or not. You may call the get_width(), get_height(), etc. + // methods after the constructor is called. You may then either destruct the object, or begin decoding the image by calling begin_decoding(), then decode() on each scanline. + jpeg_decoder(jpeg_decoder_stream *pStream); + + ~jpeg_decoder(); + + // Call this method after constructing the object to begin decompression. + // If JPGD_SUCCESS is returned you may then call decode() on each scanline. + int begin_decoding(); + + // Returns the next scan line. + // For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1). + // Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and get_bytes_per_pixel() will return 4). + // Returns JPGD_SUCCESS if a scan line has been returned. + // Returns JPGD_DONE if all scan lines have been returned. + // Returns JPGD_FAILED if an error occurred. Call get_error_code() for a more info. + int decode(const void** pScan_line, uint* pScan_line_len); + + inline jpgd_status get_error_code() const { return m_error_code; } + + inline int get_width() const { return m_image_x_size; } + inline int get_height() const { return m_image_y_size; } + + inline int get_num_components() const { return m_comps_in_frame; } + + inline int get_bytes_per_pixel() const { return m_dest_bytes_per_pixel; } + inline int get_bytes_per_scan_line() const { return m_image_x_size * get_bytes_per_pixel(); } + + // Returns the total number of bytes actually consumed by the decoder (which should equal the actual size of the JPEG file). + inline int get_total_bytes_read() const { return m_total_bytes_read; } + + private: + jpeg_decoder(const jpeg_decoder &); + jpeg_decoder &operator =(const jpeg_decoder &); + + typedef void (*pDecode_block_func)(jpeg_decoder *, int, int, int); + + struct huff_tables + { + bool ac_table; + uint look_up[256]; + uint look_up2[256]; + uint8 code_size[256]; + uint tree[512]; + }; + + struct coeff_buf + { + uint8 *pData; + int block_num_x, block_num_y; + int block_len_x, block_len_y; + int block_size; + }; + + struct mem_block + { + mem_block *m_pNext; + size_t m_used_count; + size_t m_size; + char m_data[1]; + }; + + jmp_buf m_jmp_state; + mem_block *m_pMem_blocks; + int m_image_x_size; + int m_image_y_size; + jpeg_decoder_stream *m_pStream; + int m_progressive_flag; + uint8 m_huff_ac[JPGD_MAX_HUFF_TABLES]; + uint8* m_huff_num[JPGD_MAX_HUFF_TABLES]; // pointer to number of Huffman codes per bit size + uint8* m_huff_val[JPGD_MAX_HUFF_TABLES]; // pointer to Huffman codes per bit size + jpgd_quant_t* m_quant[JPGD_MAX_QUANT_TABLES]; // pointer to quantization tables + int m_scan_type; // Gray, Yh1v1, Yh1v2, Yh2v1, Yh2v2 (CMYK111, CMYK4114 no longer supported) + int m_comps_in_frame; // # of components in frame + int m_comp_h_samp[JPGD_MAX_COMPONENTS]; // component's horizontal sampling factor + int m_comp_v_samp[JPGD_MAX_COMPONENTS]; // component's vertical sampling factor + int m_comp_quant[JPGD_MAX_COMPONENTS]; // component's quantization table selector + int m_comp_ident[JPGD_MAX_COMPONENTS]; // component's ID + int m_comp_h_blocks[JPGD_MAX_COMPONENTS]; + int m_comp_v_blocks[JPGD_MAX_COMPONENTS]; + int m_comps_in_scan; // # of components in scan + int m_comp_list[JPGD_MAX_COMPS_IN_SCAN]; // components in this scan + int m_comp_dc_tab[JPGD_MAX_COMPONENTS]; // component's DC Huffman coding table selector + int m_comp_ac_tab[JPGD_MAX_COMPONENTS]; // component's AC Huffman coding table selector + int m_spectral_start; // spectral selection start + int m_spectral_end; // spectral selection end + int m_successive_low; // successive approximation low + int m_successive_high; // successive approximation high + int m_max_mcu_x_size; // MCU's max. X size in pixels + int m_max_mcu_y_size; // MCU's max. Y size in pixels + int m_blocks_per_mcu; + int m_max_blocks_per_row; + int m_mcus_per_row, m_mcus_per_col; + int m_mcu_org[JPGD_MAX_BLOCKS_PER_MCU]; + int m_total_lines_left; // total # lines left in image + int m_mcu_lines_left; // total # lines left in this MCU + int m_real_dest_bytes_per_scan_line; + int m_dest_bytes_per_scan_line; // rounded up + int m_dest_bytes_per_pixel; // 4 (RGB) or 1 (Y) + huff_tables* m_pHuff_tabs[JPGD_MAX_HUFF_TABLES]; + coeff_buf* m_dc_coeffs[JPGD_MAX_COMPONENTS]; + coeff_buf* m_ac_coeffs[JPGD_MAX_COMPONENTS]; + int m_eob_run; + int m_block_y_mcu[JPGD_MAX_COMPONENTS]; + uint8* m_pIn_buf_ofs; + int m_in_buf_left; + int m_tem_flag; + bool m_eof_flag; + uint8 m_in_buf_pad_start[128]; + uint8 m_in_buf[JPGD_IN_BUF_SIZE + 128]; + uint8 m_in_buf_pad_end[128]; + int m_bits_left; + uint m_bit_buf; + int m_restart_interval; + int m_restarts_left; + int m_next_restart_num; + int m_max_mcus_per_row; + int m_max_blocks_per_mcu; + int m_expanded_blocks_per_mcu; + int m_expanded_blocks_per_row; + int m_expanded_blocks_per_component; + bool m_freq_domain_chroma_upsample; + int m_max_mcus_per_col; + uint m_last_dc_val[JPGD_MAX_COMPONENTS]; + jpgd_block_t* m_pMCU_coefficients; + int m_mcu_block_max_zag[JPGD_MAX_BLOCKS_PER_MCU]; + uint8* m_pSample_buf; + int m_crr[256]; + int m_cbb[256]; + int m_crg[256]; + int m_cbg[256]; + uint8* m_pScan_line_0; + uint8* m_pScan_line_1; + jpgd_status m_error_code; + bool m_ready_flag; + int m_total_bytes_read; + + void free_all_blocks(); + JPGD_NORETURN void stop_decoding(jpgd_status status); + void *alloc(size_t n, bool zero = false); + void word_clear(void *p, uint16 c, uint n); + void prep_in_buffer(); + void read_dht_marker(); + void read_dqt_marker(); + void read_sof_marker(); + void skip_variable_marker(); + void read_dri_marker(); + void read_sos_marker(); + int next_marker(); + int process_markers(); + void locate_soi_marker(); + void locate_sof_marker(); + int locate_sos_marker(); + void init(jpeg_decoder_stream * pStream); + void create_look_ups(); + void fix_in_buffer(); + void transform_mcu(int mcu_row); + void transform_mcu_expand(int mcu_row); + coeff_buf* coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y); + inline jpgd_block_t *coeff_buf_getp(coeff_buf *cb, int block_x, int block_y); + void load_next_row(); + void decode_next_row(); + void make_huff_table(int index, huff_tables *pH); + void check_quant_tables(); + void check_huff_tables(); + void calc_mcu_block_order(); + int init_scan(); + void init_frame(); + void process_restart(); + void decode_scan(pDecode_block_func decode_block_func); + void init_progressive(); + void init_sequential(); + void decode_start(); + void decode_init(jpeg_decoder_stream * pStream); + void H2V2Convert(); + void H2V1Convert(); + void H1V2Convert(); + void H1V1Convert(); + void gray_convert(); + void expanded_convert(); + void find_eoi(); + inline uint get_char(); + inline uint get_char(bool *pPadding_flag); + inline void stuff_char(uint8 q); + inline uint8 get_octet(); + inline uint get_bits(int num_bits); + inline uint get_bits_no_markers(int numbits); + inline int huff_decode(huff_tables *pH); + inline int huff_decode(huff_tables *pH, int& extrabits); + static inline uint8 clamp(int i); + static void decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y); + static void decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y); + static void decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y); + static void decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y); + }; + +} // namespace jpgd + +#endif // JPEG_DECODER_H diff --git a/drivers/jpg/image_loader_jpg.cpp b/drivers/jpg/image_loader_jpg.cpp deleted file mode 100644 index 62b587f61c..0000000000 --- a/drivers/jpg/image_loader_jpg.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/*************************************************/ -/* image_loader_jpg.cpp */ -/*************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/*************************************************/ -/* Source code within this file is: */ -/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */ -/* All Rights Reserved. */ -/*************************************************/ - -#include "image_loader_jpg.h" - -#include "print_string.h" -#include "os/os.h" -#include "drivers/jpg/tinyjpeg.h" - - -static void* _tinyjpg_alloc(unsigned int amount) { - - return memalloc(amount); -} - -static void _tinyjpg_free(void *ptr) { - - memfree(ptr); -} - -Error ImageLoaderJPG::load_image(Image *p_image,FileAccess *f) { - - - DVector<uint8_t> src_image; - int src_image_len = f->get_len(); - ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); - src_image.resize(src_image_len); - - DVector<uint8_t>::Write w = src_image.write(); - - f->get_buffer(&w[0],src_image_len); - - f->close(); - - jdec_private* jdec=tinyjpeg_init(_tinyjpg_alloc,_tinyjpg_free); - ERR_FAIL_COND_V(!jdec,ERR_UNAVAILABLE); - - int ret = tinyjpeg_parse_header(jdec,&w[0],src_image_len); - - if (ret!=0) { - tinyjpeg_free(jdec); - } - - ERR_FAIL_COND_V(ret!=0,ERR_FILE_CORRUPT); - - unsigned int width,height; - - - tinyjpeg_get_size(jdec,&width,&height); - - - - DVector<uint8_t> imgdata; - imgdata.resize(width*height*3); - DVector<uint8_t>::Write imgdataw = imgdata.write(); - - - unsigned char *components[1]={&imgdataw[0]}; - tinyjpeg_set_components(jdec,components,1); - tinyjpeg_decode(jdec,TINYJPEG_FMT_RGB24); - imgdataw = DVector<uint8_t>::Write(); - - Image dst_image(width,height,0,Image::FORMAT_RGB,imgdata); - - tinyjpeg_free(jdec); - - *p_image=dst_image; - - return OK; - -} - -void ImageLoaderJPG::get_recognized_extensions(List<String> *p_extensions) const { - - p_extensions->push_back("jpg"); - p_extensions->push_back("jpeg"); -} - - -ImageLoaderJPG::ImageLoaderJPG() { - - -} - - diff --git a/drivers/jpg/jidctflt.c b/drivers/jpg/jidctflt.c deleted file mode 100644 index 40a9eab83e..0000000000 --- a/drivers/jpg/jidctflt.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * jidctflt.c - * - * Copyright (C) 1994-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * - * The authors make NO WARRANTY or representation, either express or implied, - * with respect to this software, its quality, accuracy, merchantability, or - * fitness for a particular purpose. This software is provided "AS IS", and you, - * its user, assume the entire risk as to its quality and accuracy. - * - * This software is copyright (C) 1991-1998, Thomas G. Lane. - * All Rights Reserved except as specified below. - * - * Permission is hereby granted to use, copy, modify, and distribute this - * software (or portions thereof) for any purpose, without fee, subject to these - * conditions: - * (1) If any part of the source code for this software is distributed, then this - * README file must be included, with this copyright and no-warranty notice - * unaltered; and any additions, deletions, or changes to the original files - * must be clearly indicated in accompanying documentation. - * (2) If only executable code is distributed, then the accompanying - * documentation must state that "this software is based in part on the work of - * the Independent JPEG Group". - * (3) Permission for use of this software is granted only if the user accepts - * full responsibility for any undesirable consequences; the authors accept - * NO LIABILITY for damages of any kind. - * - * These conditions apply to any software derived from or based on the IJG code, - * not just to the unmodified library. If you use our work, you ought to - * acknowledge us. - * - * Permission is NOT granted for the use of any IJG author's name or company name - * in advertising or publicity relating to this software or products derived from - * it. This software may be referred to only as "the Independent JPEG Group's - * software". - * - * We specifically permit and encourage the use of this software as the basis of - * commercial products, provided that all warranty or liability claims are - * assumed by the product vendor. - * - * - * This file contains a floating-point implementation of the - * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - * must also perform dequantization of the input coefficients. - * - * This implementation should be more accurate than either of the integer - * IDCT implementations. However, it may not give the same results on all - * machines because of differences in roundoff behavior. Speed will depend - * on the hardware's floating point capacity. - * - * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - * on each row (or vice versa, but it's more convenient to emit a row at - * a time). Direct algorithms are also available, but they are much more - * complex and seem not to be any faster when reduced to code. - * - * This implementation is based on Arai, Agui, and Nakajima's algorithm for - * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in - * Japanese, but the algorithm is described in the Pennebaker & Mitchell - * JPEG textbook (see REFERENCES section in file README). The following code - * is based directly on figure 4-8 in P&M. - * While an 8-point DCT cannot be done in less than 11 multiplies, it is - * possible to arrange the computation so that many of the multiplies are - * simple scalings of the final outputs. These multiplies can then be - * folded into the multiplications or divisions by the JPEG quantization - * table entries. The AA&N method leaves only 5 multiplies and 29 adds - * to be done in the DCT itself. - * The primary disadvantage of this method is that with a fixed-point - * implementation, accuracy is lost due to imprecise representation of the - * scaled quantization values. However, that problem does not arise if - * we use floating point arithmetic. - */ - -#include "tinyjpeg-internal.h" - -#define FAST_FLOAT float -#define DCTSIZE 8 -#define DCTSIZE2 (DCTSIZE*DCTSIZE) - -#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) - -#if 0 && defined(__GNUC__) && (defined(__i686__)) -// || defined(__x86_64__)) - -static inline unsigned char descale_and_clamp(int x, int shift) -{ - __asm__ ( - "add %3,%1\n" - "\tsar %2,%1\n" - "\tsub $-128,%1\n" - "\tcmovl %5,%1\n" /* Use the sub to compare to 0 */ - "\tcmpl %4,%1\n" - "\tcmovg %4,%1\n" - : "=r"(x) - : "0"(x), "Ir"(shift), "ir"(1UL<<(shift-1)), "r" (0xff), "r" (0) - ); - return x; -} - -#else -static __inline unsigned char descale_and_clamp(int x, int shift) -{ - x += (1UL<<(shift-1)); - if (x<0) - x = (x >> shift) | ((~(0UL)) << (32-(shift))); - else - x >>= shift; - x += 128; - if (x>255) - return 255; - else if (x<0) - return 0; - else - return x; -} -#endif - -/* - * Perform dequantization and inverse DCT on one block of coefficients. - */ - -void -tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride) -{ - FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; - FAST_FLOAT tmp10, tmp11, tmp12, tmp13; - FAST_FLOAT z5, z10, z11, z12, z13; - int16_t *inptr; - FAST_FLOAT *quantptr; - FAST_FLOAT *wsptr; - uint8_t *outptr; - int ctr; - FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ - - /* Pass 1: process columns from input, store into work array. */ - - inptr = compptr->DCT; - quantptr = compptr->Q_table; - wsptr = workspace; - for (ctr = DCTSIZE; ctr > 0; ctr--) { - /* Due to quantization, we will usually find that many of the input - * coefficients are zero, especially the AC terms. We can exploit this - * by short-circuiting the IDCT calculation for any column in which all - * the AC terms are zero. In that case each output is equal to the - * DC coefficient (with scale factor as needed). - * With typical images and quantization tables, half or more of the - * column DCT calculations can be simplified this way. - */ - - if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && - inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && - inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && - inptr[DCTSIZE*7] == 0) { - /* AC terms all zero */ - FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - - wsptr[DCTSIZE*0] = dcval; - wsptr[DCTSIZE*1] = dcval; - wsptr[DCTSIZE*2] = dcval; - wsptr[DCTSIZE*3] = dcval; - wsptr[DCTSIZE*4] = dcval; - wsptr[DCTSIZE*5] = dcval; - wsptr[DCTSIZE*6] = dcval; - wsptr[DCTSIZE*7] = dcval; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - continue; - } - - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp10 = tmp0 + tmp2; /* phase 3 */ - tmp11 = tmp0 - tmp2; - - tmp13 = tmp1 + tmp3; /* phases 5-3 */ - tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ - - tmp0 = tmp10 + tmp13; /* phase 2 */ - tmp3 = tmp10 - tmp13; - tmp1 = tmp11 + tmp12; - tmp2 = tmp11 - tmp12; - - /* Odd part */ - - tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - z13 = tmp6 + tmp5; /* phase 6 */ - z10 = tmp6 - tmp5; - z11 = tmp4 + tmp7; - z12 = tmp4 - tmp7; - - tmp7 = z11 + z13; /* phase 5 */ - tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ - - z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ - tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ - tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ - - tmp6 = tmp12 - tmp7; /* phase 2 */ - tmp5 = tmp11 - tmp6; - tmp4 = tmp10 + tmp5; - - wsptr[DCTSIZE*0] = tmp0 + tmp7; - wsptr[DCTSIZE*7] = tmp0 - tmp7; - wsptr[DCTSIZE*1] = tmp1 + tmp6; - wsptr[DCTSIZE*6] = tmp1 - tmp6; - wsptr[DCTSIZE*2] = tmp2 + tmp5; - wsptr[DCTSIZE*5] = tmp2 - tmp5; - wsptr[DCTSIZE*4] = tmp3 + tmp4; - wsptr[DCTSIZE*3] = tmp3 - tmp4; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - } - - /* Pass 2: process rows from work array, store into output array. */ - /* Note that we must descale the results by a factor of 8 == 2**3. */ - - wsptr = workspace; - outptr = output_buf; - for (ctr = 0; ctr < DCTSIZE; ctr++) { - /* Rows of zeroes can be exploited in the same way as we did with columns. - * However, the column calculation has created many nonzero AC terms, so - * the simplification applies less often (typically 5% to 10% of the time). - * And testing floats for zero is relatively expensive, so we don't bother. - */ - - /* Even part */ - - tmp10 = wsptr[0] + wsptr[4]; - tmp11 = wsptr[0] - wsptr[4]; - - tmp13 = wsptr[2] + wsptr[6]; - tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13; - - tmp0 = tmp10 + tmp13; - tmp3 = tmp10 - tmp13; - tmp1 = tmp11 + tmp12; - tmp2 = tmp11 - tmp12; - - /* Odd part */ - - z13 = wsptr[5] + wsptr[3]; - z10 = wsptr[5] - wsptr[3]; - z11 = wsptr[1] + wsptr[7]; - z12 = wsptr[1] - wsptr[7]; - - tmp7 = z11 + z13; - tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); - - z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ - tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ - tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ - - tmp6 = tmp12 - tmp7; - tmp5 = tmp11 - tmp6; - tmp4 = tmp10 + tmp5; - - /* Final output stage: scale down by a factor of 8 and range-limit */ - - outptr[0] = descale_and_clamp((int)(tmp0 + tmp7), 3); - outptr[7] = descale_and_clamp((int)(tmp0 - tmp7), 3); - outptr[1] = descale_and_clamp((int)(tmp1 + tmp6), 3); - outptr[6] = descale_and_clamp((int)(tmp1 - tmp6), 3); - outptr[2] = descale_and_clamp((int)(tmp2 + tmp5), 3); - outptr[5] = descale_and_clamp((int)(tmp2 - tmp5), 3); - outptr[4] = descale_and_clamp((int)(tmp3 + tmp4), 3); - outptr[3] = descale_and_clamp((int)(tmp3 - tmp4), 3); - - - wsptr += DCTSIZE; /* advance pointer to next row */ - outptr += stride; - } -} - diff --git a/drivers/jpg/loadjpeg.c b/drivers/jpg/loadjpeg.c deleted file mode 100644 index 82072d4272..0000000000 --- a/drivers/jpg/loadjpeg.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Small jpeg decoder library - testing application - * - * Copyright (c) 2006, Luc Saillard <luc@saillard.org> - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * - Neither the name of the author nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "tinyjpeg.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#define snprintf(buf, size, fmt, ...) sprintf(buf, fmt, __VA_ARGS__) - -static void exitmessage(const char *message) __attribute__((noreturn)); -static void exitmessage(const char *message) -{ - printf("%s\n", message); - exit(0); -} - -static int filesize(FILE *fp) -{ - long pos; - fseek(fp, 0, SEEK_END); - pos = ftell(fp); - fseek(fp, 0, SEEK_SET); - return pos; -} - -/** - * Save a buffer in 24bits Targa format - * (BGR byte order) - */ -static void write_tga(const char *filename, int output_format, int width, int height, unsigned char **components) -{ - unsigned char targaheader[18]; - FILE *F; - char temp[1024]; - unsigned int bufferlen = width * height * 3; - unsigned char *rgb_data = components[0]; - - sprintf(temp, sizeof(temp), filename); - - memset(targaheader,0,sizeof(targaheader)); - - targaheader[12] = (unsigned char) (width & 0xFF); - targaheader[13] = (unsigned char) (width >> 8); - targaheader[14] = (unsigned char) (height & 0xFF); - targaheader[15] = (unsigned char) (height >> 8); - targaheader[17] = 0x20; /* Top-down, non-interlaced */ - targaheader[2] = 2; /* image type = uncompressed RGB */ - targaheader[16] = 24; - - if (output_format == TINYJPEG_FMT_RGB24) - { - unsigned char *data = rgb_data + bufferlen - 3; - do - { - unsigned char c = data[0]; - data[0] = data[2]; - data[2] = c; - data-=3; - } - while (data > rgb_data); - } - - F = fopen(temp, "wb"); - fwrite(targaheader, sizeof(targaheader), 1, F); - fwrite(rgb_data, 1, bufferlen, F); - fclose(F); -} - -/** - * Save a buffer in three files (.Y, .U, .V) useable by yuvsplittoppm - */ -static void write_yuv(const char *filename, int width, int height, unsigned char **components) -{ - FILE *F; - char temp[1024]; - - snprintf(temp, 1024, "%s.Y", filename); - F = fopen(temp, "wb"); - fwrite(components[0], width, height, F); - fclose(F); - snprintf(temp, 1024, "%s.U", filename); - F = fopen(temp, "wb"); - fwrite(components[1], width*height/4, 1, F); - fclose(F); - snprintf(temp, 1024, "%s.V", filename); - F = fopen(temp, "wb"); - fwrite(components[2], width*height/4, 1, F); - fclose(F); -} - -/** - * Save a buffer in grey image (pgm format) - */ -static void write_pgm(const char *filename, int width, int height, unsigned char **components) -{ - FILE *F; - char temp[1024]; - - snprintf(temp, 1024, "%s", filename); - F = fopen(temp, "wb"); - fprintf(F, "P5\n%d %d\n255\n", width, height); - fwrite(components[0], width, height, F); - fclose(F); -} - -/** - * Load one jpeg image, and try to decompress 1000 times, and save the result. - * This is mainly used for benchmarking the decoder, or to test if between each - * called of the library the DCT is corrected reset (a bug was found). - */ -int load_multiple_times(const char *filename, const char *outfilename, int output_format) -{ - FILE *fp; - int count, length_of_file; - unsigned int width, height; - unsigned char *buf; - struct jdec_private *jdec; - unsigned char *components[4]; - - jdec = tinyjpeg_init(); - count = 0; - - /* Load the Jpeg into memory */ - fp = fopen(filename, "rb"); - if (fp == NULL) - exitmessage("Cannot open filename\n"); - length_of_file = filesize(fp); - buf = (unsigned char *)malloc(length_of_file + 4); - fread(buf, length_of_file, 1, fp); - fclose(fp); - - while (count<1000) - { - if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0) - exitmessage(tinyjpeg_get_errorstring(jdec)); - - tinyjpeg_decode(jdec, output_format); - - count++; - } - - /* - * Get address for each plane (not only max 3 planes is supported), and - * depending of the output mode, only some components will be filled - * RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane - */ - tinyjpeg_get_components(jdec, components); - tinyjpeg_get_size(jdec, &width, &height); - - /* Save it */ - switch (output_format) - { - case TINYJPEG_FMT_RGB24: - case TINYJPEG_FMT_BGR24: - write_tga(outfilename, output_format, width, height, components); - break; - case TINYJPEG_FMT_YUV420P: - write_yuv(outfilename, width, height, components); - break; - case TINYJPEG_FMT_GREY: - write_pgm(outfilename, width, height, components); - break; - } - - free(buf); - tinyjpeg_free(jdec); - return 0; -} - -/** - * Load one jpeg image, and decompress it, and save the result. - */ -int convert_one_image(const char *infilename, const char *outfilename, int output_format) -{ - FILE *fp; - unsigned int length_of_file; - unsigned int width, height; - unsigned char *buf; - struct jdec_private *jdec; - unsigned char *components[3]; - - /* Load the Jpeg into memory */ - fp = fopen(infilename, "rb"); - if (fp == NULL) - exitmessage("Cannot open filename\n"); - length_of_file = filesize(fp); - buf = (unsigned char *)malloc(length_of_file + 4); - if (buf == NULL) - exitmessage("Not enough memory for loading file\n"); - fread(buf, length_of_file, 1, fp); - fclose(fp); - - /* Decompress it */ - jdec = tinyjpeg_init(); - if (jdec == NULL) - exitmessage("Not enough memory to alloc the structure need for decompressing\n"); - - if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0) - exitmessage(tinyjpeg_get_errorstring(jdec)); - - /* Get the size of the image */ - tinyjpeg_get_size(jdec, &width, &height); - - printf("Decoding JPEG image...\n"); - if (tinyjpeg_decode(jdec, output_format) < 0) - exitmessage(tinyjpeg_get_errorstring(jdec)); - - /* - * Get address for each plane (not only max 3 planes is supported), and - * depending of the output mode, only some components will be filled - * RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane - */ - tinyjpeg_get_components(jdec, components); - - /* Save it */ - switch (output_format) - { - case TINYJPEG_FMT_RGB24: - case TINYJPEG_FMT_BGR24: - write_tga(outfilename, output_format, width, height, components); - break; - case TINYJPEG_FMT_YUV420P: - write_yuv(outfilename, width, height, components); - break; - case TINYJPEG_FMT_GREY: - write_pgm(outfilename, width, height, components); - break; - } - - /* Only called this if the buffers were allocated by tinyjpeg_decode() */ - tinyjpeg_free(jdec); - /* else called just free(jdec); */ - - free(buf); - return 0; -} - -static void usage(void) -{ - fprintf(stderr, "Usage: loadjpeg [options] <input_filename.jpeg> <format> <output_filename>\n"); - fprintf(stderr, "options:\n"); - fprintf(stderr, " --benchmark - Convert 1000 times the same image\n"); - fprintf(stderr, "format:\n"); - fprintf(stderr, " yuv420p - output 3 files .Y,.U,.V\n"); - fprintf(stderr, " rgb24 - output a .tga image\n"); - fprintf(stderr, " bgr24 - output a .tga image\n"); - fprintf(stderr, " gray - output a .pgm image\n"); - exit(1); -} - -/** - * main - * - */ -int main(int argc, char *argv[]) -{ - int output_format = TINYJPEG_FMT_YUV420P; - char *output_filename, *input_filename; - clock_t start_time, finish_time; - unsigned int duration; - int current_argument; - int benchmark_mode = 0; - - if (argc < 3) - usage(); - - current_argument = 1; - while (1) - { - if (strcmp(argv[current_argument], "--benchmark")==0) - benchmark_mode = 1; - else - break; - current_argument++; - } - - if (argc < current_argument+2) - usage(); - - input_filename = argv[current_argument]; - if (strcmp(argv[current_argument+1],"yuv420p")==0) - output_format = TINYJPEG_FMT_YUV420P; - else if (strcmp(argv[current_argument+1],"rgb24")==0) - output_format = TINYJPEG_FMT_RGB24; - else if (strcmp(argv[current_argument+1],"bgr24")==0) - output_format = TINYJPEG_FMT_BGR24; - else if (strcmp(argv[current_argument+1],"grey")==0) - output_format = TINYJPEG_FMT_GREY; - else - exitmessage("Bad format: need to be one of yuv420p, rgb24, bgr24, grey\n"); - output_filename = argv[current_argument+2]; - - start_time = clock(); - - if (benchmark_mode) - load_multiple_times(input_filename, output_filename, output_format); - else - convert_one_image(input_filename, output_filename, output_format); - - finish_time = clock(); - duration = finish_time - start_time; - printf("Decoding finished in %u ticks\n", duration); - - return 0; -} - - - - diff --git a/drivers/jpg/tinyjpeg-internal.h b/drivers/jpg/tinyjpeg-internal.h deleted file mode 100644 index b2d5fe42aa..0000000000 --- a/drivers/jpg/tinyjpeg-internal.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Small jpeg decoder library (Internal header) - * - * Copyright (c) 2006, Luc Saillard <luc@saillard.org> - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * - Neither the name of the author nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#ifndef __TINYJPEG_INTERNAL_H_ -#define __TINYJPEG_INTERNAL_H_ - -#ifdef _MSC_VER - -typedef signed __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef signed __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef signed __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef signed __int64 int64_t; -typedef unsigned __int64 uint64_t; - -#else - -#ifdef NO_STDINT_H -typedef unsigned char uint8_t; -typedef signed char int8_t; -typedef unsigned short uint16_t; -typedef signed short int16_t; -typedef unsigned int uint32_t; -typedef signed int int32_t; -typedef long long int64_t; -typedef unsigned long long int64_t; -#else -#include <stdint.h> -#endif -#endif - - -#include <setjmp.h> - -#define SANITY_CHECK 1 - -struct jdec_private; - -#define HUFFMAN_BITS_SIZE 256 -#define HUFFMAN_HASH_NBITS 9 -#define HUFFMAN_HASH_SIZE (1UL<<HUFFMAN_HASH_NBITS) -#define HUFFMAN_HASH_MASK (HUFFMAN_HASH_SIZE-1) - -#define HUFFMAN_TABLES 4 -#define COMPONENTS 3 -#define JPEG_MAX_WIDTH 4096 -#define JPEG_MAX_HEIGHT 4096 - -struct huffman_table -{ - /* Fast look up table, using HUFFMAN_HASH_NBITS bits we can have directly the symbol, - * if the symbol is <0, then we need to look into the tree table */ - short int lookup[HUFFMAN_HASH_SIZE]; - /* code size: give the number of bits of a symbol is encoded */ - unsigned char code_size[HUFFMAN_HASH_SIZE]; - /* some place to store value that is not encoded in the lookup table - * FIXME: Calculate if 256 value is enough to store all values - */ - uint16_t slowtable[16-HUFFMAN_HASH_NBITS][256]; -}; - -struct component -{ - unsigned int Hfactor; - unsigned int Vfactor; - float *Q_table; /* Pointer to the quantisation table to use */ - struct huffman_table *AC_table; - struct huffman_table *DC_table; - short int previous_DC; /* Previous DC coefficient */ - short int DCT[64]; /* DCT coef */ -#if SANITY_CHECK - unsigned int cid; -#endif -}; - - -typedef void (*decode_MCU_fct) (struct jdec_private *priv); -typedef void (*convert_colorspace_fct) (struct jdec_private *priv); - -struct jdec_private -{ - void *(*allocate_mem)(unsigned int amount); - void (*free_mem)(void *mem); - - /* Public variables */ - uint8_t *components[COMPONENTS]; - unsigned int width, height; /* Size of the image */ - unsigned int flags; - - /* Private variables */ - const unsigned char *stream_begin, *stream_end; - unsigned int stream_length; - - const unsigned char *stream; /* Pointer to the current stream */ - unsigned int reservoir, nbits_in_reservoir; - - struct component component_infos[COMPONENTS]; - float Q_tables[COMPONENTS][64]; /* quantization tables */ - struct huffman_table HTDC[HUFFMAN_TABLES]; /* DC huffman tables */ - struct huffman_table HTAC[HUFFMAN_TABLES]; /* AC huffman tables */ - int default_huffman_table_initialized; - int restart_interval; - int restarts_to_go; /* MCUs left in this restart interval */ - int last_rst_marker_seen; /* Rst marker is incremented each time */ - - /* Temp space used after the IDCT to store each components */ - uint8_t Y[64*4], Cr[64], Cb[64]; - - jmp_buf jump_state; - /* Internal Pointer use for colorspace conversion, do not modify it !!! */ - uint8_t *plane[COMPONENTS]; - - uint8_t decomp_block[16][16*3]; - -}; - -#if defined(__GNUC__) && (__GNUC__ > 3) && defined(__OPTIMIZE__) -#define __likely(x) __builtin_expect(!!(x), 1) -#define __unlikely(x) __builtin_expect(!!(x), 0) -#else -#define __likely(x) (x) -#define __unlikely(x) (x) -#endif - -#define IDCT tinyjpeg_idct_float -void tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride); - -#endif - diff --git a/drivers/jpg/tinyjpeg.c b/drivers/jpg/tinyjpeg.c deleted file mode 100644 index 8e3c934ce0..0000000000 --- a/drivers/jpg/tinyjpeg.c +++ /dev/null @@ -1,2202 +0,0 @@ -/* - * Small jpeg decoder library - * - * Copyright (c) 2006, Luc Saillard <luc@saillard.org> - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * - Neither the name of the author nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <errno.h> - -#include "tinyjpeg.h" -#include "tinyjpeg-internal.h" - -enum std_markers { - DQT = 0xDB, /* Define Quantization Table */ - SOF = 0xC0, /* Start of Frame (size information) */ - DHT = 0xC4, /* Huffman Table */ - SOI = 0xD8, /* Start of Image */ - SOS = 0xDA, /* Start of Scan */ - RST = 0xD0, /* Reset Marker d0 -> .. */ - RST7 = 0xD7, /* Reset Marker .. -> d7 */ - EOI = 0xD9, /* End of Image */ - DRI = 0xDD, /* Define Restart Interval */ - APP0 = 0xE0, -}; - -#define cY 0 -#define cCb 1 -#define cCr 2 - -#define BLACK_Y 0 -#define BLACK_U 127 -#define BLACK_V 127 - -#if DEBUG -#define trace(fmt, args...) do { \ - fprintf(stderr, fmt, ## args); \ - fflush(stderr); \ -} while(0) -#else -#define trace(fmt, ...) do { } while (0) -#endif - -#define error(fmt, ...) do { \ - sprintf(error_string, fmt, ## __VA_ARGS__); \ - return -1; \ -} while(0) - - -#if 0 -static char *print_bits(unsigned int value, char *bitstr) -{ - int i, j; - i=31; - while (i>0) - { - if (value & (1UL<<i)) - break; - i--; - } - j=0; - while (i>=0) - { - bitstr[j++] = (value & (1UL<<i))?'1':'0'; - i--; - } - bitstr[j] = 0; - return bitstr; -} - -static void print_next_16bytes(int offset, const unsigned char *stream) -{ - trace("%4.4x: %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", - offset, - stream[0], stream[1], stream[2], stream[3], - stream[4], stream[5], stream[6], stream[7], - stream[8], stream[9], stream[10], stream[11], - stream[12], stream[13], stream[14], stream[15]); -} - -#endif - -/* Global variable to return the last error found while deconding */ -static char error_string[256]; - -static const unsigned char zigzag[64] = -{ - 0, 1, 5, 6, 14, 15, 27, 28, - 2, 4, 7, 13, 16, 26, 29, 42, - 3, 8, 12, 17, 25, 30, 41, 43, - 9, 11, 18, 24, 31, 40, 44, 53, - 10, 19, 23, 32, 39, 45, 52, 54, - 20, 22, 33, 38, 46, 51, 55, 60, - 21, 34, 37, 47, 50, 56, 59, 61, - 35, 36, 48, 49, 57, 58, 62, 63 -}; - -/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */ -/* IMPORTANT: these are only valid for 8-bit data precision! */ -static const unsigned char bits_dc_luminance[17] = -{ - 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 -}; -static const unsigned char val_dc_luminance[] = -{ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 -}; - -static const unsigned char bits_dc_chrominance[17] = -{ - 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 -}; -static const unsigned char val_dc_chrominance[] = -{ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 -}; - -static const unsigned char bits_ac_luminance[17] = -{ - 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d -}; -static const unsigned char val_ac_luminance[] = -{ - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa -}; - -static const unsigned char bits_ac_chrominance[17] = -{ - 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 -}; - -static const unsigned char val_ac_chrominance[] = -{ - 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, - 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, - 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, - 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, - 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, - 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, - 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, - 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, - 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, - 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, - 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa -}; - - -/* - * 4 functions to manage the stream - * - * fill_nbits: put at least nbits in the reservoir of bits. - * But convert any 0xff,0x00 into 0xff - * get_nbits: read nbits from the stream, and put it in result, - * bits is removed from the stream and the reservoir is filled - * automaticaly. The result is signed according to the number of - * bits. - * look_nbits: read nbits from the stream without marking as read. - * skip_nbits: read nbits from the stream but do not return the result. - * - * stream: current pointer in the jpeg data (read bytes per bytes) - * nbits_in_reservoir: number of bits filled into the reservoir - * reservoir: register that contains bits information. Only nbits_in_reservoir - * is valid. - * nbits_in_reservoir - * <-- 17 bits --> - * Ex: 0000 0000 1010 0000 1111 0000 <== reservoir - * ^ - * bit 1 - * To get two bits from this example - * result = (reservoir >> 15) & 3 - * - */ -#define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ - while (nbits_in_reservoir<nbits_wanted) \ - { \ - unsigned char c; \ - if (stream >= priv->stream_end) \ - longjmp(priv->jump_state, -EIO); \ - c = *stream++; \ - reservoir <<= 8; \ - if (c == 0xff && *stream == 0x00) \ - stream++; \ - reservoir |= c; \ - nbits_in_reservoir+=8; \ - } \ -} while(0); - -/* Signed version !!!! */ -#define get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \ - fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \ - result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \ - nbits_in_reservoir -= (nbits_wanted); \ - reservoir &= ((1U<<nbits_in_reservoir)-1); \ - if ((unsigned int)result < (1UL<<((nbits_wanted)-1))) \ - result += (0xFFFFFFFFUL<<(nbits_wanted))+1; \ -} while(0); - -#define look_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \ - fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \ - result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \ -} while(0); - -/* To speed up the decoding, we assume that the reservoir have enough bit - * slow version: - * #define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ - * fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \ - * nbits_in_reservoir -= (nbits_wanted); \ - * reservoir &= ((1U<<nbits_in_reservoir)-1); \ - * } while(0); - */ -#define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ - nbits_in_reservoir -= (nbits_wanted); \ - reservoir &= ((1U<<nbits_in_reservoir)-1); \ -} while(0); - - -#define be16_to_cpu(x) (((x)[0]<<8)|(x)[1]) - -static void resync(struct jdec_private *priv); - -/** - * Get the next (valid) huffman code in the stream. - * - * To speedup the procedure, we look HUFFMAN_HASH_NBITS bits and the code is - * lower than HUFFMAN_HASH_NBITS we have automaticaly the length of the code - * and the value by using two lookup table. - * Else if the value is not found, just search (linear) into an array for each - * bits is the code is present. - * - * If the code is not present for any reason, -1 is return. - */ -static int get_next_huffman_code(struct jdec_private *priv, struct huffman_table *huffman_table) -{ - int value, hcode; - unsigned int extra_nbits, nbits; - uint16_t *slowtable; - - look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, HUFFMAN_HASH_NBITS, hcode); - value = huffman_table->lookup[hcode]; - if (__likely(value >= 0)) - { - unsigned int code_size = huffman_table->code_size[value]; - skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, code_size); - return value; - } - - /* Decode more bits each time ... */ - for (extra_nbits=0; extra_nbits<16-HUFFMAN_HASH_NBITS; extra_nbits++) - { - nbits = HUFFMAN_HASH_NBITS + 1 + extra_nbits; - - look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits, hcode); - slowtable = huffman_table->slowtable[extra_nbits]; - /* Search if the code is in this array */ - while (slowtable[0]) { - if (slowtable[0] == hcode) { - skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits); - return slowtable[1]; - } - slowtable+=2; - } - } - return 0; -} - - - - -/** - * - * Decode a single block that contains the DCT coefficients. - * The table coefficients is already dezigzaged at the end of the operation. - * - */ -static void process_Huffman_data_unit(struct jdec_private *priv, int component) -{ - unsigned char j; - unsigned int huff_code; - unsigned char size_val, count_0; - - struct component *c = &priv->component_infos[component]; - short int DCT[64]; - - - /* Initialize the DCT coef table */ - memset(DCT, 0, sizeof(DCT)); - - /* DC coefficient decoding */ - huff_code = get_next_huffman_code(priv, c->DC_table); - //trace("+ %x\n", huff_code); - if (huff_code) { - get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, huff_code, DCT[0]); - DCT[0] += c->previous_DC; - c->previous_DC = DCT[0]; - } else { - DCT[0] = c->previous_DC; - } - - /* AC coefficient decoding */ - j = 1; - while (j<64) - { - huff_code = get_next_huffman_code(priv, c->AC_table); - //trace("- %x\n", huff_code); - - size_val = huff_code & 0xF; - count_0 = huff_code >> 4; - - if (size_val == 0) - { /* RLE */ - if (count_0 == 0) - break; /* EOB found, go out */ - else if (count_0 == 0xF) - j += 16; /* skip 16 zeros */ - } - else - { - j += count_0; /* skip count_0 zeroes */ - if (__unlikely(j >= 64)) - { - sprintf(error_string, "Bad huffman data (buffer overflow)"); - break; - } - get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]); - j++; - } - } - - for (j = 0; j < 64; j++) - c->DCT[j] = DCT[zigzag[j]]; -} - -/* - * Takes two array of bits, and build the huffman table for size, and code - * - * lookup will return the symbol if the code is less or equal than HUFFMAN_HASH_NBITS. - * code_size will be used to known how many bits this symbol is encoded. - * slowtable will be used when the first lookup didn't give the result. - */ -static void build_huffman_table(const unsigned char *bits, const unsigned char *vals, struct huffman_table *table) -{ - unsigned int i, j, code, code_size, val, nbits; - unsigned char huffsize[HUFFMAN_BITS_SIZE+1], *hz; - unsigned int huffcode[HUFFMAN_BITS_SIZE+1], *hc; - int next_free_entry; - - /* - * Build a temp array - * huffsize[X] => numbers of bits to write vals[X] - */ - hz = huffsize; - for (i=1; i<=16; i++) - { - for (j=1; j<=bits[i]; j++) - *hz++ = i; - } - *hz = 0; - - memset(table->lookup, 0xff, sizeof(table->lookup)); - for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++) - table->slowtable[i][0] = 0; - - /* Build a temp array - * huffcode[X] => code used to write vals[X] - */ - code = 0; - hc = huffcode; - hz = huffsize; - nbits = *hz; - while (*hz) - { - while (*hz == nbits) - { - *hc++ = code++; - hz++; - } - code <<= 1; - nbits++; - } - - /* - * Build the lookup table, and the slowtable if needed. - */ - next_free_entry = -1; - for (i=0; huffsize[i]; i++) - { - val = vals[i]; - code = huffcode[i]; - code_size = huffsize[i]; - - trace("val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size); - - table->code_size[val] = code_size; - if (code_size <= HUFFMAN_HASH_NBITS) - { - /* - * Good: val can be put in the lookup table, so fill all value of this - * column with value val - */ - int repeat = 1UL<<(HUFFMAN_HASH_NBITS - code_size); - code <<= HUFFMAN_HASH_NBITS - code_size; - while ( repeat-- ) - table->lookup[code++] = val; - - } - else - { - /* Perhaps sorting the array will be an optimization */ - uint16_t *slowtable = table->slowtable[code_size-HUFFMAN_HASH_NBITS-1]; - while(slowtable[0]) - slowtable+=2; - slowtable[0] = code; - slowtable[1] = val; - slowtable[2] = 0; - /* TODO: NEED TO CHECK FOR AN OVERFLOW OF THE TABLE */ - } - - } -} - -static void build_default_huffman_tables(struct jdec_private *priv) -{ - if ( (priv->flags & TINYJPEG_FLAGS_MJPEG_TABLE) - && priv->default_huffman_table_initialized) - return; - - build_huffman_table(bits_dc_luminance, val_dc_luminance, &priv->HTDC[0]); - build_huffman_table(bits_ac_luminance, val_ac_luminance, &priv->HTAC[0]); - - build_huffman_table(bits_dc_chrominance, val_dc_chrominance, &priv->HTDC[1]); - build_huffman_table(bits_ac_chrominance, val_ac_chrominance, &priv->HTAC[1]); - - priv->default_huffman_table_initialized = 1; -} - - - -/******************************************************************************* - * - * Colorspace conversion routine - * - * - * Note: - * YCbCr is defined per CCIR 601-1, except that Cb and Cr are - * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. - * The conversion equations to be implemented are therefore - * R = Y + 1.40200 * Cr - * G = Y - 0.34414 * Cb - 0.71414 * Cr - * B = Y + 1.77200 * Cb - * - ******************************************************************************/ - -static unsigned char clamp(int i) -{ - if (i<0) - return 0; - else if (i>255) - return 255; - else - return i; -} - - -/** - * YCrCb -> YUV420P (1x1) - * .---. - * | 1 | - * `---' - */ -static void YCrCB_to_YUV420P_1x1(struct jdec_private *priv) -{ - const unsigned char *s, *y; - unsigned char *p; - int i,j; - - p = priv->plane[0]; - y = priv->Y; - for (i=0; i<8; i++) - { - memcpy(p, y, 8); - p+=priv->width; - y+=8; - } - - p = priv->plane[1]; - s = priv->Cb; - for (i=0; i<8; i+=2) - { - for (j=0; j<8; j+=2, s+=2) - *p++ = *s; - s += 8; /* Skip one line */ - p += priv->width/2 - 4; - } - - p = priv->plane[2]; - s = priv->Cr; - for (i=0; i<8; i+=2) - { - for (j=0; j<8; j+=2, s+=2) - *p++ = *s; - s += 8; /* Skip one line */ - p += priv->width/2 - 4; - } -} - -/** - * YCrCb -> YUV420P (2x1) - * .-------. - * | 1 | 2 | - * `-------' - */ -static void YCrCB_to_YUV420P_2x1(struct jdec_private *priv) -{ - unsigned char *p; - const unsigned char *s, *y1; - unsigned int i; - - p = priv->plane[0]; - y1 = priv->Y; - for (i=0; i<8; i++) - { - memcpy(p, y1, 16); - p += priv->width; - y1 += 16; - } - - p = priv->plane[1]; - s = priv->Cb; - for (i=0; i<8; i+=2) - { - memcpy(p, s, 8); - s += 16; /* Skip one line */ - p += priv->width/2; - } - - p = priv->plane[2]; - s = priv->Cr; - for (i=0; i<8; i+=2) - { - memcpy(p, s, 8); - s += 16; /* Skip one line */ - p += priv->width/2; - } -} - - -/** - * YCrCb -> YUV420P (1x2) - * .---. - * | 1 | - * |---| - * | 2 | - * `---' - */ -static void YCrCB_to_YUV420P_1x2(struct jdec_private *priv) -{ - const unsigned char *s, *y; - unsigned char *p; - int i,j; - - p = priv->plane[0]; - y = priv->Y; - for (i=0; i<16; i++) - { - memcpy(p, y, 8); - p+=priv->width; - y+=8; - } - - p = priv->plane[1]; - s = priv->Cb; - for (i=0; i<8; i++) - { - for (j=0; j<8; j+=2, s+=2) - *p++ = *s; - p += priv->width/2 - 4; - } - - p = priv->plane[2]; - s = priv->Cr; - for (i=0; i<8; i++) - { - for (j=0; j<8; j+=2, s+=2) - *p++ = *s; - p += priv->width/2 - 4; - } -} - -/** - * YCrCb -> YUV420P (2x2) - * .-------. - * | 1 | 2 | - * |---+---| - * | 3 | 4 | - * `-------' - */ -static void YCrCB_to_YUV420P_2x2(struct jdec_private *priv) -{ - unsigned char *p; - const unsigned char *s, *y1; - unsigned int i; - - p = priv->plane[0]; - y1 = priv->Y; - for (i=0; i<16; i++) - { - memcpy(p, y1, 16); - p += priv->width; - y1 += 16; - } - - p = priv->plane[1]; - s = priv->Cb; - for (i=0; i<8; i++) - { - memcpy(p, s, 8); - s += 8; - p += priv->width/2; - } - - p = priv->plane[2]; - s = priv->Cr; - for (i=0; i<8; i++) - { - memcpy(p, s, 8); - s += 8; - p += priv->width/2; - } -} - -/** - * YCrCb -> RGB24 (1x1) - * .---. - * | 1 | - * `---' - */ -static void YCrCB_to_RGB24_1x1(struct jdec_private *priv) -{ - const unsigned char *Y, *Cb, *Cr; - unsigned char *p; - int i,j; - int offset_to_next_row; - -#define SCALEBITS 10 -#define ONE_HALF (1UL << (SCALEBITS-1)) -#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) - - p = priv->plane[0]; - Y = priv->Y; - Cb = priv->Cb; - Cr = priv->Cr; - offset_to_next_row = priv->width*3 - 8*3; - for (i=0; i<8; i++) { - - for (j=0; j<8; j++) { - - int y, cb, cr; - int add_r, add_g, add_b; - int r, g , b; - - y = (*Y++) << SCALEBITS; - cb = *Cb++ - 128; - cr = *Cr++ - 128; - add_r = FIX(1.40200) * cr + ONE_HALF; - add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; - add_b = FIX(1.77200) * cb + ONE_HALF; - - - r = (y + add_r) >> SCALEBITS; - g = (y + add_g) >> SCALEBITS; - b = (y + add_b) >> SCALEBITS; - priv->decomp_block[i][j*3+0]=clamp(r); - priv->decomp_block[i][j*3+1]=clamp(g); - priv->decomp_block[i][j*3+2]=clamp(b); - - } - -// p += offset_to_next_row; - } - -#undef SCALEBITS -#undef ONE_HALF -#undef FIX - -} - -/** - * YCrCb -> BGR24 (1x1) - * .---. - * | 1 | - * `---' - */ -static void YCrCB_to_BGR24_1x1(struct jdec_private *priv) -{ - const unsigned char *Y, *Cb, *Cr; - unsigned char *p; - int i,j; - int offset_to_next_row; - -#define SCALEBITS 10 -#define ONE_HALF (1UL << (SCALEBITS-1)) -#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) - - p = priv->plane[0]; - Y = priv->Y; - Cb = priv->Cb; - Cr = priv->Cr; - offset_to_next_row = priv->width*3 - 8*3; - for (i=0; i<8; i++) { - - for (j=0; j<8; j++) { - - int y, cb, cr; - int add_r, add_g, add_b; - int r, g , b; - - y = (*Y++) << SCALEBITS; - cb = *Cb++ - 128; - cr = *Cr++ - 128; - add_r = FIX(1.40200) * cr + ONE_HALF; - add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; - add_b = FIX(1.77200) * cb + ONE_HALF; - - b = (y + add_b) >> SCALEBITS; - *p++ = clamp(b); - g = (y + add_g) >> SCALEBITS; - *p++ = clamp(g); - r = (y + add_r) >> SCALEBITS; - *p++ = clamp(r); - - } - - p += offset_to_next_row; - } - -#undef SCALEBITS -#undef ONE_HALF -#undef FIX - -} - - -/** - * YCrCb -> RGB24 (2x1) - * .-------. - * | 1 | 2 | - * `-------' - */ -static void YCrCB_to_RGB24_2x1(struct jdec_private *priv) -{ - const unsigned char *Y, *Cb, *Cr; - unsigned char *p; - int i,j; - int offset_to_next_row; - -#define SCALEBITS 10 -#define ONE_HALF (1UL << (SCALEBITS-1)) -#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) - - p = priv->plane[0]; - Y = priv->Y; - Cb = priv->Cb; - Cr = priv->Cr; - offset_to_next_row = priv->width*3 - 16*3; - for (i=0; i<8; i++) { - - for (j=0; j<8; j++) { - - int y, cb, cr; - int add_r, add_g, add_b; - int r, g , b; - - y = (*Y++) << SCALEBITS; - cb = *Cb++ - 128; - cr = *Cr++ - 128; - add_r = FIX(1.40200) * cr + ONE_HALF; - add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; - add_b = FIX(1.77200) * cb + ONE_HALF; - - r = (y + add_r) >> SCALEBITS; - g = (y + add_g) >> SCALEBITS; - b = (y + add_b) >> SCALEBITS; - - priv->decomp_block[i][j*6+0]=clamp(r); - priv->decomp_block[i][j*6+1]=clamp(g); - priv->decomp_block[i][j*6+2]=clamp(b); - - y = (*Y++) << SCALEBITS; - - r = (y + add_r) >> SCALEBITS; - g = (y + add_g) >> SCALEBITS; - b = (y + add_b) >> SCALEBITS; - - priv->decomp_block[i][j*6+3]=clamp(r); - priv->decomp_block[i][j*6+4]=clamp(g); - priv->decomp_block[i][j*6+5]=clamp(b); - - } - - p += offset_to_next_row; - } - -#undef SCALEBITS -#undef ONE_HALF -#undef FIX - -} - -/* - * YCrCb -> BGR24 (2x1) - * .-------. - * | 1 | 2 | - * `-------' - */ -static void YCrCB_to_BGR24_2x1(struct jdec_private *priv) -{ - const unsigned char *Y, *Cb, *Cr; - unsigned char *p; - int i,j; - int offset_to_next_row; - -#define SCALEBITS 10 -#define ONE_HALF (1UL << (SCALEBITS-1)) -#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) - - p = priv->plane[0]; - Y = priv->Y; - Cb = priv->Cb; - Cr = priv->Cr; - offset_to_next_row = priv->width*3 - 16*3; - for (i=0; i<8; i++) { - - for (j=0; j<8; j++) { - - int y, cb, cr; - int add_r, add_g, add_b; - int r, g , b; - - cb = *Cb++ - 128; - cr = *Cr++ - 128; - add_r = FIX(1.40200) * cr + ONE_HALF; - add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; - add_b = FIX(1.77200) * cb + ONE_HALF; - - y = (*Y++) << SCALEBITS; - b = (y + add_b) >> SCALEBITS; - *p++ = clamp(b); - g = (y + add_g) >> SCALEBITS; - *p++ = clamp(g); - r = (y + add_r) >> SCALEBITS; - *p++ = clamp(r); - - y = (*Y++) << SCALEBITS; - b = (y + add_b) >> SCALEBITS; - *p++ = clamp(b); - g = (y + add_g) >> SCALEBITS; - *p++ = clamp(g); - r = (y + add_r) >> SCALEBITS; - *p++ = clamp(r); - - } - - p += offset_to_next_row; - } - -#undef SCALEBITS -#undef ONE_HALF -#undef FIX - -} - -/** - * YCrCb -> RGB24 (1x2) - * .---. - * | 1 | - * |---| - * | 2 | - * `---' - */ -static void YCrCB_to_RGB24_1x2(struct jdec_private *priv) -{ - const unsigned char *Y, *Cb, *Cr; - unsigned char *p, *p2; - int i,j; - int offset_to_next_row; - -#define SCALEBITS 10 -#define ONE_HALF (1UL << (SCALEBITS-1)) -#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) - - p = priv->plane[0]; - p2 = priv->plane[0] + priv->width*3; - Y = priv->Y; - Cb = priv->Cb; - Cr = priv->Cr; - offset_to_next_row = 2*priv->width*3 - 8*3; - for (i=0; i<8; i++) { - - for (j=0; j<8; j++) { - - int y, cb, cr; - int add_r, add_g, add_b; - int r, g , b; - - cb = *Cb++ - 128; - cr = *Cr++ - 128; - add_r = FIX(1.40200) * cr + ONE_HALF; - add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; - add_b = FIX(1.77200) * cb + ONE_HALF; - - y = (*Y++) << SCALEBITS; - r = (y + add_r) >> SCALEBITS; - g = (y + add_g) >> SCALEBITS; - b = (y + add_b) >> SCALEBITS; - - priv->decomp_block[i*2][j*3+0]=clamp(r); - priv->decomp_block[i*2][j*3+1]=clamp(g); - priv->decomp_block[i*2][j*3+2]=clamp(b); - - y = (Y[8-1]) << SCALEBITS; - r = (y + add_r) >> SCALEBITS; - g = (y + add_g) >> SCALEBITS; - b = (y + add_b) >> SCALEBITS; - - priv->decomp_block[i*2+1][j*3+0]=clamp(r); - priv->decomp_block[i*2+1][j*3+1]=clamp(g); - priv->decomp_block[i*2+1][j*3+2]=clamp(b); - - } - Y += 8; - p += offset_to_next_row; - p2 += offset_to_next_row; - } - -#undef SCALEBITS -#undef ONE_HALF -#undef FIX - -} - -/* - * YCrCb -> BGR24 (1x2) - * .---. - * | 1 | - * |---| - * | 2 | - * `---' - */ -static void YCrCB_to_BGR24_1x2(struct jdec_private *priv) -{ - const unsigned char *Y, *Cb, *Cr; - unsigned char *p, *p2; - int i,j; - int offset_to_next_row; - -#define SCALEBITS 10 -#define ONE_HALF (1UL << (SCALEBITS-1)) -#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) - - p = priv->plane[0]; - p2 = priv->plane[0] + priv->width*3; - Y = priv->Y; - Cb = priv->Cb; - Cr = priv->Cr; - offset_to_next_row = 2*priv->width*3 - 8*3; - for (i=0; i<8; i++) { - - for (j=0; j<8; j++) { - - int y, cb, cr; - int add_r, add_g, add_b; - int r, g , b; - - cb = *Cb++ - 128; - cr = *Cr++ - 128; - add_r = FIX(1.40200) * cr + ONE_HALF; - add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; - add_b = FIX(1.77200) * cb + ONE_HALF; - - y = (*Y++) << SCALEBITS; - b = (y + add_b) >> SCALEBITS; - *p++ = clamp(b); - g = (y + add_g) >> SCALEBITS; - *p++ = clamp(g); - r = (y + add_r) >> SCALEBITS; - *p++ = clamp(r); - - y = (Y[8-1]) << SCALEBITS; - b = (y + add_b) >> SCALEBITS; - *p2++ = clamp(b); - g = (y + add_g) >> SCALEBITS; - *p2++ = clamp(g); - r = (y + add_r) >> SCALEBITS; - *p2++ = clamp(r); - - } - Y += 8; - p += offset_to_next_row; - p2 += offset_to_next_row; - } - -#undef SCALEBITS -#undef ONE_HALF -#undef FIX - -} - - -/** - * YCrCb -> RGB24 (2x2) - * .-------. - * | 1 | 2 | - * |---+---| - * | 3 | 4 | - * `-------' - */ -static void YCrCB_to_RGB24_2x2(struct jdec_private *priv) -{ - const unsigned char *Y, *Cb, *Cr; - unsigned char *p, *p2; - int i,j; - int offset_to_next_row; - -#define SCALEBITS 10 -#define ONE_HALF (1UL << (SCALEBITS-1)) -#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) - - p = priv->plane[0]; - p2 = priv->plane[0] + priv->width*3; - Y = priv->Y; - Cb = priv->Cb; - Cr = priv->Cr; - offset_to_next_row = (priv->width*3*2) - 16*3; - for (i=0; i<8; i++) { - - for (j=0; j<8; j++) { - - int y, cb, cr; - int add_r, add_g, add_b; - int r, g , b; - - cb = *Cb++ - 128; - cr = *Cr++ - 128; - add_r = FIX(1.40200) * cr + ONE_HALF; - add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; - add_b = FIX(1.77200) * cb + ONE_HALF; - - y = (*Y++) << SCALEBITS; - r = (y + add_r) >> SCALEBITS; - g = (y + add_g) >> SCALEBITS; - b = (y + add_b) >> SCALEBITS; - - priv->decomp_block[i*2][j*6+0]=clamp(r); - priv->decomp_block[i*2][j*6+1]=clamp(g); - priv->decomp_block[i*2][j*6+2]=clamp(b); - - y = (*Y++) << SCALEBITS; - r = (y + add_r) >> SCALEBITS; - g = (y + add_g) >> SCALEBITS; - b = (y + add_b) >> SCALEBITS; - - priv->decomp_block[i*2][j*6+3]=clamp(r); - priv->decomp_block[i*2][j*6+4]=clamp(g); - priv->decomp_block[i*2][j*6+5]=clamp(b); - - y = (Y[16-2]) << SCALEBITS; - r = (y + add_r) >> SCALEBITS; - g = (y + add_g) >> SCALEBITS; - b = (y + add_b) >> SCALEBITS; - - priv->decomp_block[i*2+1][j*6+0]=clamp(r); - priv->decomp_block[i*2+1][j*6+1]=clamp(g); - priv->decomp_block[i*2+1][j*6+2]=clamp(b); - - y = (Y[16-1]) << SCALEBITS; - r = (y + add_r) >> SCALEBITS; - g = (y + add_g) >> SCALEBITS; - b = (y + add_b) >> SCALEBITS; - - priv->decomp_block[i*2+1][j*6+3]=clamp(r); - priv->decomp_block[i*2+1][j*6+4]=clamp(g); - priv->decomp_block[i*2+1][j*6+5]=clamp(b); - - } - Y += 16; - p += offset_to_next_row; - p2 += offset_to_next_row; - } - -#undef SCALEBITS -#undef ONE_HALF -#undef FIX - -} - - -/* - * YCrCb -> BGR24 (2x2) - * .-------. - * | 1 | 2 | - * |---+---| - * | 3 | 4 | - * `-------' - */ -static void YCrCB_to_BGR24_2x2(struct jdec_private *priv) -{ - const unsigned char *Y, *Cb, *Cr; - unsigned char *p, *p2; - int i,j; - int offset_to_next_row; - -#define SCALEBITS 10 -#define ONE_HALF (1UL << (SCALEBITS-1)) -#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) - - p = priv->plane[0]; - p2 = priv->plane[0] + priv->width*3; - Y = priv->Y; - Cb = priv->Cb; - Cr = priv->Cr; - offset_to_next_row = (priv->width*3*2) - 16*3; - for (i=0; i<8; i++) { - - for (j=0; j<8; j++) { - - int y, cb, cr; - int add_r, add_g, add_b; - int r, g , b; - - cb = *Cb++ - 128; - cr = *Cr++ - 128; - add_r = FIX(1.40200) * cr + ONE_HALF; - add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; - add_b = FIX(1.77200) * cb + ONE_HALF; - - y = (*Y++) << SCALEBITS; - b = (y + add_b) >> SCALEBITS; - *p++ = clamp(b); - g = (y + add_g) >> SCALEBITS; - *p++ = clamp(g); - r = (y + add_r) >> SCALEBITS; - *p++ = clamp(r); - - y = (*Y++) << SCALEBITS; - b = (y + add_b) >> SCALEBITS; - *p++ = clamp(b); - g = (y + add_g) >> SCALEBITS; - *p++ = clamp(g); - r = (y + add_r) >> SCALEBITS; - *p++ = clamp(r); - - y = (Y[16-2]) << SCALEBITS; - b = (y + add_b) >> SCALEBITS; - *p2++ = clamp(b); - g = (y + add_g) >> SCALEBITS; - *p2++ = clamp(g); - r = (y + add_r) >> SCALEBITS; - *p2++ = clamp(r); - - y = (Y[16-1]) << SCALEBITS; - b = (y + add_b) >> SCALEBITS; - *p2++ = clamp(b); - g = (y + add_g) >> SCALEBITS; - *p2++ = clamp(g); - r = (y + add_r) >> SCALEBITS; - *p2++ = clamp(r); - } - Y += 16; - p += offset_to_next_row; - p2 += offset_to_next_row; - } - -#undef SCALEBITS -#undef ONE_HALF -#undef FIX - -} - - - -/** - * YCrCb -> Grey (1x1) - * .---. - * | 1 | - * `---' - */ -static void YCrCB_to_Grey_1x1(struct jdec_private *priv) -{ - const unsigned char *y; - unsigned char *p; - unsigned int i; - int offset_to_next_row; - - p = priv->plane[0]; - y = priv->Y; - offset_to_next_row = priv->width; - - for (i=0; i<8; i++) { - memcpy(p, y, 8); - y+=8; - p += offset_to_next_row; - } -} - -/** - * YCrCb -> Grey (2x1) - * .-------. - * | 1 | 2 | - * `-------' - */ -static void YCrCB_to_Grey_2x1(struct jdec_private *priv) -{ - const unsigned char *y; - unsigned char *p; - unsigned int i; - - p = priv->plane[0]; - y = priv->Y; - - for (i=0; i<8; i++) { - memcpy(p, y, 16); - y += 16; - p += priv->width; - } -} - - -/** - * YCrCb -> Grey (1x2) - * .---. - * | 1 | - * |---| - * | 2 | - * `---' - */ -static void YCrCB_to_Grey_1x2(struct jdec_private *priv) -{ - const unsigned char *y; - unsigned char *p; - unsigned int i; - - p = priv->plane[0]; - y = priv->Y; - - for (i=0; i<16; i++) { - memcpy(p, y, 8); - y += 8; - p += priv->width; - } -} - -/** - * YCrCb -> Grey (2x2) - * .-------. - * | 1 | 2 | - * |---+---| - * | 3 | 4 | - * `-------' - */ -static void YCrCB_to_Grey_2x2(struct jdec_private *priv) -{ - const unsigned char *y; - unsigned char *p; - unsigned int i; - - p = priv->plane[0]; - y = priv->Y; - - for (i=0; i<16; i++) { - memcpy(p, y, 16); - y += 16; - p += priv->width; - } -} - - -/* - * Decode all the 3 components for 1x1 - */ -static void decode_MCU_1x1_3planes(struct jdec_private *priv) -{ - // Y - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y, 8); - - // Cb - process_Huffman_data_unit(priv, cCb); - IDCT(&priv->component_infos[cCb], priv->Cb, 8); - - // Cr - process_Huffman_data_unit(priv, cCr); - IDCT(&priv->component_infos[cCr], priv->Cr, 8); -} - -/* - * Decode a 1x1 directly in 1 color - */ -static void decode_MCU_1x1_1plane(struct jdec_private *priv) -{ - // Y - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y, 8); - - // Cb - process_Huffman_data_unit(priv, cCb); - IDCT(&priv->component_infos[cCb], priv->Cb, 8); - - // Cr - process_Huffman_data_unit(priv, cCr); - IDCT(&priv->component_infos[cCr], priv->Cr, 8); -} - - -/* - * Decode a 2x1 - * .-------. - * | 1 | 2 | - * `-------' - */ -static void decode_MCU_2x1_3planes(struct jdec_private *priv) -{ - // Y - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y, 16); - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y+8, 16); - - // Cb - process_Huffman_data_unit(priv, cCb); - IDCT(&priv->component_infos[cCb], priv->Cb, 8); - - // Cr - process_Huffman_data_unit(priv, cCr); - IDCT(&priv->component_infos[cCr], priv->Cr, 8); -} - -/* - * Decode a 2x1 - * .-------. - * | 1 | 2 | - * `-------' - */ -static void decode_MCU_2x1_1plane(struct jdec_private *priv) -{ - // Y - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y, 16); - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y+8, 16); - - // Cb - process_Huffman_data_unit(priv, cCb); - - // Cr - process_Huffman_data_unit(priv, cCr); -} - - -/* - * Decode a 2x2 - * .-------. - * | 1 | 2 | - * |---+---| - * | 3 | 4 | - * `-------' - */ -static void decode_MCU_2x2_3planes(struct jdec_private *priv) -{ - // Y - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y, 16); - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y+8, 16); - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y+64*2, 16); - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16); - - // Cb - process_Huffman_data_unit(priv, cCb); - IDCT(&priv->component_infos[cCb], priv->Cb, 8); - - // Cr - process_Huffman_data_unit(priv, cCr); - IDCT(&priv->component_infos[cCr], priv->Cr, 8); -} - -/* - * Decode a 2x2 directly in GREY format (8bits) - * .-------. - * | 1 | 2 | - * |---+---| - * | 3 | 4 | - * `-------' - */ -static void decode_MCU_2x2_1plane(struct jdec_private *priv) -{ - // Y - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y, 16); - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y+8, 16); - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y+64*2, 16); - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16); - - // Cb - process_Huffman_data_unit(priv, cCb); - - // Cr - process_Huffman_data_unit(priv, cCr); -} - -/* - * Decode a 1x2 mcu - * .---. - * | 1 | - * |---| - * | 2 | - * `---' - */ -static void decode_MCU_1x2_3planes(struct jdec_private *priv) -{ - // Y - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y, 8); - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y+64, 8); - - // Cb - process_Huffman_data_unit(priv, cCb); - IDCT(&priv->component_infos[cCb], priv->Cb, 8); - - // Cr - process_Huffman_data_unit(priv, cCr); - IDCT(&priv->component_infos[cCr], priv->Cr, 8); -} - -/* - * Decode a 1x2 mcu - * .---. - * | 1 | - * |---| - * | 2 | - * `---' - */ -static void decode_MCU_1x2_1plane(struct jdec_private *priv) -{ - // Y - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y, 8); - process_Huffman_data_unit(priv, cY); - IDCT(&priv->component_infos[cY], priv->Y+64, 8); - - // Cb - process_Huffman_data_unit(priv, cCb); - - // Cr - process_Huffman_data_unit(priv, cCr); -} - -static void print_SOF(const unsigned char *stream) -{ - int width, height, nr_components, precision; -#if DEBUG - const char *nr_components_to_string[] = { - "????", - "Grayscale", - "????", - "YCbCr", - "CYMK" - }; -#endif - - precision = stream[2]; - height = be16_to_cpu(stream+3); - width = be16_to_cpu(stream+5); - nr_components = stream[7]; - - trace("> SOF marker\n"); - trace("Size:%dx%d nr_components:%d (%s) precision:%d\n", - width, height, - nr_components, nr_components_to_string[nr_components], - precision); -} - -/******************************************************************************* - * - * JPEG/JFIF Parsing functions - * - * Note: only a small subset of the jpeg file format is supported. No markers, - * nor progressive stream is supported. - * - ******************************************************************************/ - -static void build_quantization_table(float *qtable, const unsigned char *ref_table) -{ - /* Taken from libjpeg. Copyright Independent JPEG Group's LLM idct. - * For float AA&N IDCT method, divisors are equal to quantization - * coefficients scaled by scalefactor[row]*scalefactor[col], where - * scalefactor[0] = 1 - * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 - * We apply a further scale factor of 8. - * What's actually stored is 1/divisor so that the inner loop can - * use a multiplication rather than a division. - */ - int i, j; - static const double aanscalefactor[8] = { - 1.0, 1.387039845, 1.306562965, 1.175875602, - 1.0, 0.785694958, 0.541196100, 0.275899379 - }; - const unsigned char *zz = zigzag; - - for (i=0; i<8; i++) { - for (j=0; j<8; j++) { - *qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j]; - } - } - -} - -static int parse_DQT(struct jdec_private *priv, const unsigned char *stream) -{ - int qi; - float *table; - const unsigned char *dqt_block_end; - - trace("> DQT marker\n"); - dqt_block_end = stream + be16_to_cpu(stream); - stream += 2; /* Skip length */ - - while (stream < dqt_block_end) - { - qi = *stream++; -#if SANITY_CHECK - if (qi>>4) - error("16 bits quantization table is not supported\n"); - if (qi>4) - error("No more 4 quantization table is supported (got %d)\n", qi); -#endif - table = priv->Q_tables[qi]; - build_quantization_table(table, stream); - stream += 64; - } - trace("< DQT marker\n"); - return 0; -} - -static int parse_SOF(struct jdec_private *priv, const unsigned char *stream) -{ - int i, width, height, nr_components, cid, sampling_factor; - int Q_table; - struct component *c; - - trace("> SOF marker\n"); - print_SOF(stream); - - height = be16_to_cpu(stream+3); - width = be16_to_cpu(stream+5); - nr_components = stream[7]; -#if SANITY_CHECK - if (stream[2] != 8) - error("Precision other than 8 is not supported\n"); - if (width>JPEG_MAX_WIDTH || height>JPEG_MAX_HEIGHT) - error("Width and Height (%dx%d) seems suspicious\n", width, height); - if (nr_components != 3) - error("We only support YUV images\n"); - //if (height%16) -// error("Height need to be a multiple of 16 (current height is %d)\n", height); -// if (width%16) - // error("Width need to be a multiple of 16 (current Width is %d)\n", width); -#endif - stream += 8; - for (i=0; i<nr_components; i++) { - cid = *stream++; - sampling_factor = *stream++; - Q_table = *stream++; - c = &priv->component_infos[i]; -#if SANITY_CHECK - c->cid = cid; - if (Q_table >= COMPONENTS) - error("Bad Quantization table index (got %d, max allowed %d)\n", Q_table, COMPONENTS-1); -#endif - c->Vfactor = sampling_factor&0xf; - c->Hfactor = sampling_factor>>4; - c->Q_table = priv->Q_tables[Q_table]; - trace("Component:%d factor:%dx%d Quantization table:%d\n", - cid, c->Hfactor, c->Hfactor, Q_table ); - - } - priv->width = width; - priv->height = height; - - trace("< SOF marker\n"); - - return 0; -} - -static int parse_SOS(struct jdec_private *priv, const unsigned char *stream) -{ - unsigned int i, cid, table; - unsigned int nr_components = stream[2]; - - trace("> SOS marker\n"); - -#if SANITY_CHECK - if (nr_components != 3) - error("We only support YCbCr image\n"); -#endif - - stream += 3; - for (i=0;i<nr_components;i++) { - cid = *stream++; - table = *stream++; -#if SANITY_CHECK - if ((table&0xf)>=4) - error("We do not support more than 2 AC Huffman table\n"); - if ((table>>4)>=4) - error("We do not support more than 2 DC Huffman table\n"); - if (cid != priv->component_infos[i].cid) - error("SOS cid order (%d:%d) isn't compatible with the SOF marker (%d:%d)\n", - i, cid, i, priv->component_infos[i].cid); - trace("ComponentId:%d tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4); -#endif - priv->component_infos[i].AC_table = &priv->HTAC[table&0xf]; - priv->component_infos[i].DC_table = &priv->HTDC[table>>4]; - } - priv->stream = stream+3; - trace("< SOS marker\n"); - return 0; -} - -static int parse_DHT(struct jdec_private *priv, const unsigned char *stream) -{ - unsigned int count, i; - unsigned char huff_bits[17]; - int length, index; - - length = be16_to_cpu(stream) - 2; - stream += 2; /* Skip length */ - - trace("> DHT marker (length=%d)\n", length); - - while (length>0) { - index = *stream++; - - /* We need to calculate the number of bytes 'vals' will takes */ - huff_bits[0] = 0; - count = 0; - for (i=1; i<17; i++) { - huff_bits[i] = *stream++; - count += huff_bits[i]; - } -#if SANITY_CHECK - if (count >= HUFFMAN_BITS_SIZE) - error("No more than %d bytes is allowed to describe a huffman table", HUFFMAN_BITS_SIZE); - if ( (index &0xf) >= HUFFMAN_TABLES) - error("No more than %d Huffman tables is supported (got %d)\n", HUFFMAN_TABLES, index&0xf); - trace("Huffman table %s[%d] length=%d\n", (index&0xf0)?"AC":"DC", index&0xf, count); -#endif - - if (index & 0xf0 ) - build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]); - else - build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]); - - length -= 1; - length -= 16; - length -= count; - stream += count; - } - trace("< DHT marker\n"); - return 0; -} - -static int parse_DRI(struct jdec_private *priv, const unsigned char *stream) -{ - unsigned int length; - - trace("> DRI marker\n"); - - length = be16_to_cpu(stream); - -#if SANITY_CHECK - if (length != 4) - error("Length of DRI marker need to be 4\n"); -#endif - - priv->restart_interval = be16_to_cpu(stream+2); - -#if DEBUG - trace("Restart interval = %d\n", priv->restart_interval); -#endif - - trace("< DRI marker\n"); - - return 0; -} - - - -static void resync(struct jdec_private *priv) -{ - int i; - - /* Init DC coefficients */ - for (i=0; i<COMPONENTS; i++) - priv->component_infos[i].previous_DC = 0; - - priv->reservoir = 0; - priv->nbits_in_reservoir = 0; - if (priv->restart_interval > 0) - priv->restarts_to_go = priv->restart_interval; - else - priv->restarts_to_go = -1; -} - -static int find_next_rst_marker(struct jdec_private *priv) -{ - int rst_marker_found = 0; - int marker; - const unsigned char *stream = priv->stream; - - /* Parse marker */ - while (!rst_marker_found) - { - while (*stream++ != 0xff) - { - if (stream >= priv->stream_end) - error("EOF while search for a RST marker."); - } - /* Skip any padding ff byte (this is normal) */ - while (*stream == 0xff) - stream++; - - marker = *stream++; - if ((RST+priv->last_rst_marker_seen) == marker) - rst_marker_found = 1; - else if (marker >= RST && marker <= RST7) - error("Wrong Reset marker found, abording"); - else if (marker == EOI) - return 0; - } - trace("RST Marker %d found at offset %d\n", priv->last_rst_marker_seen, stream - priv->stream_begin); - - priv->stream = stream; - priv->last_rst_marker_seen++; - priv->last_rst_marker_seen &= 7; - - return 0; -} - -static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream) -{ - int chuck_len; - int marker; - int sos_marker_found = 0; - int dht_marker_found = 0; - const unsigned char *next_chunck; - - /* Parse marker */ - while (!sos_marker_found) - { - if (*stream++ != 0xff) - goto bogus_jpeg_format; - /* Skip any padding ff byte (this is normal) */ - while (*stream == 0xff) - stream++; - - marker = *stream++; - chuck_len = be16_to_cpu(stream); - next_chunck = stream + chuck_len; - switch (marker) - { - case SOF: - if (parse_SOF(priv, stream) < 0) - return -1; - break; - case DQT: - if (parse_DQT(priv, stream) < 0) - return -1; - break; - case SOS: - if (parse_SOS(priv, stream) < 0) - return -1; - sos_marker_found = 1; - break; - case DHT: - if (parse_DHT(priv, stream) < 0) - return -1; - dht_marker_found = 1; - break; - case DRI: - if (parse_DRI(priv, stream) < 0) - return -1; - break; - default: - trace("> Unknown marker %2.2x\n", marker); - break; - } - - stream = next_chunck; - } - - if (!dht_marker_found) { - trace("No Huffman table loaded, using the default one\n"); - build_default_huffman_tables(priv); - } - -#ifdef SANITY_CHECK - if ( (priv->component_infos[cY].Hfactor < priv->component_infos[cCb].Hfactor) - || (priv->component_infos[cY].Hfactor < priv->component_infos[cCr].Hfactor)) - error("Horizontal sampling factor for Y should be greater than horitontal sampling factor for Cb or Cr\n"); - if ( (priv->component_infos[cY].Vfactor < priv->component_infos[cCb].Vfactor) - || (priv->component_infos[cY].Vfactor < priv->component_infos[cCr].Vfactor)) - error("Vertical sampling factor for Y should be greater than vertical sampling factor for Cb or Cr\n"); - if ( (priv->component_infos[cCb].Hfactor!=1) - || (priv->component_infos[cCr].Hfactor!=1) - || (priv->component_infos[cCb].Vfactor!=1) - || (priv->component_infos[cCr].Vfactor!=1)) - error("Sampling other than 1x1 for Cr and Cb is not supported"); -#endif - - return 0; -bogus_jpeg_format: - trace("Bogus jpeg format\n"); - return -1; -} - -/******************************************************************************* - * - * Functions exported of the library. - * - * Note: Some applications can access directly to internal pointer of the - * structure. It's is not recommended, but if you have many images to - * uncompress with the same parameters, some functions can be called to speedup - * the decoding. - * - ******************************************************************************/ - -/** - * Allocate a new tinyjpeg decoder object. - * - * Before calling any other functions, an object need to be called. - */ -struct jdec_private *tinyjpeg_init(void *(*allocate_mem)(unsigned int),void (*free_mem)(void *)) -{ - struct jdec_private *priv; - unsigned int i; - - priv = (struct jdec_private *)allocate_mem(sizeof(struct jdec_private)); - for(i=0;i<sizeof(struct jdec_private);i++) { - char *pzero = (char*)priv; - pzero[i]=0; - } - priv->allocate_mem=allocate_mem; - priv->free_mem=free_mem; - if (priv == NULL) - return NULL; - return priv; -} - -/** - * Free a tinyjpeg object. - * - * No others function can be called after this one. - */ -void tinyjpeg_free(struct jdec_private *priv) -{ - int i; - for (i=0; i<COMPONENTS; i++) { - if (priv->components[i]) { - // priv->free_mem(priv->components[i]); - priv->components[i] = NULL; - } - } - priv->free_mem(priv); -} - -/** - * Initialize the tinyjpeg object and prepare the decoding of the stream. - * - * Check if the jpeg can be decoded with this jpeg decoder. - * Fill some table used for preprocessing. - */ -int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size) -{ - int ret; - - /* Identify the file */ - if ((buf[0] != 0xFF) || (buf[1] != SOI)) - error("Not a JPG file ?\n"); - - priv->stream_begin = buf+2; - priv->stream_length = size-2; - priv->stream_end = priv->stream_begin + priv->stream_length; - - ret = parse_JFIF(priv, priv->stream_begin); - - return ret; -} - -static const decode_MCU_fct decode_mcu_3comp_table[4] = { - decode_MCU_1x1_3planes, - decode_MCU_1x2_3planes, - decode_MCU_2x1_3planes, - decode_MCU_2x2_3planes, -}; - -static const decode_MCU_fct decode_mcu_1comp_table[4] = { - decode_MCU_1x1_1plane, - decode_MCU_1x2_1plane, - decode_MCU_2x1_1plane, - decode_MCU_2x2_1plane, -}; - -static const convert_colorspace_fct convert_colorspace_yuv420p[4] = { - YCrCB_to_YUV420P_1x1, - YCrCB_to_YUV420P_1x2, - YCrCB_to_YUV420P_2x1, - YCrCB_to_YUV420P_2x2, -}; - -static const convert_colorspace_fct convert_colorspace_rgb24[4] = { - YCrCB_to_RGB24_1x1, - YCrCB_to_RGB24_1x2, - YCrCB_to_RGB24_2x1, - YCrCB_to_RGB24_2x2, -}; - -static const convert_colorspace_fct convert_colorspace_bgr24[4] = { - YCrCB_to_BGR24_1x1, - YCrCB_to_BGR24_1x2, - YCrCB_to_BGR24_2x1, - YCrCB_to_BGR24_2x2, -}; - -static const convert_colorspace_fct convert_colorspace_grey[4] = { - YCrCB_to_Grey_1x1, - YCrCB_to_Grey_1x2, - YCrCB_to_Grey_2x1, - YCrCB_to_Grey_2x2, -}; - -/** - * Decode and convert the jpeg image into @pixfmt@ image - * - * Note: components will be automaticaly allocated if no memory is attached. - */ -int tinyjpeg_decode(struct jdec_private *priv, int pixfmt) -{ - unsigned int x, y, xstride_by_mcu, ystride_by_mcu; - unsigned int bytes_per_blocklines[3], bytes_per_mcu[3]; - decode_MCU_fct decode_MCU; - const decode_MCU_fct *decode_mcu_table; - const convert_colorspace_fct *colorspace_array_conv; - convert_colorspace_fct convert_to_pixfmt; - - if (pixfmt!=TINYJPEG_FMT_RGB24) - error("Only TINYJPEG_FMT_RGB24 is supported in this version"); - - if (setjmp(priv->jump_state)) - return -1; - - /* To keep gcc happy initialize some array */ - bytes_per_mcu[1] = 0; - bytes_per_mcu[2] = 0; - bytes_per_blocklines[1] = 0; - bytes_per_blocklines[2] = 0; - - decode_mcu_table = decode_mcu_3comp_table; - switch (pixfmt) { - case TINYJPEG_FMT_YUV420P: - colorspace_array_conv = convert_colorspace_yuv420p; - if (priv->components[0] == NULL) - priv->components[0] = (uint8_t *)priv->allocate_mem(priv->width * priv->height); - if (priv->components[1] == NULL) - priv->components[1] = (uint8_t *)priv->allocate_mem(priv->width * priv->height/4); - if (priv->components[2] == NULL) - priv->components[2] = (uint8_t *)priv->allocate_mem(priv->width * priv->height/4); - bytes_per_blocklines[0] = priv->width; - bytes_per_blocklines[1] = priv->width/4; - bytes_per_blocklines[2] = priv->width/4; - bytes_per_mcu[0] = 8; - bytes_per_mcu[1] = 4; - bytes_per_mcu[2] = 4; - break; - - case TINYJPEG_FMT_RGB24: - colorspace_array_conv = convert_colorspace_rgb24; - if (priv->components[0] == NULL) - priv->components[0] = (uint8_t *)priv->allocate_mem(priv->width * priv->height * 3); - bytes_per_blocklines[0] = priv->width * 3; - bytes_per_mcu[0] = 3*8; - break; - - case TINYJPEG_FMT_BGR24: - colorspace_array_conv = convert_colorspace_bgr24; - if (priv->components[0] == NULL) - priv->components[0] = (uint8_t *)priv->allocate_mem(priv->width * priv->height * 3); - bytes_per_blocklines[0] = priv->width * 3; - bytes_per_mcu[0] = 3*8; - break; - - case TINYJPEG_FMT_GREY: - decode_mcu_table = decode_mcu_1comp_table; - colorspace_array_conv = convert_colorspace_grey; - if (priv->components[0] == NULL) - priv->components[0] = (uint8_t *)priv->allocate_mem(priv->width * priv->height); - bytes_per_blocklines[0] = priv->width; - bytes_per_mcu[0] = 8; - break; - - default: - trace("Bad pixel format\n"); - return -1; - } - - xstride_by_mcu = ystride_by_mcu = 8; - if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) { - decode_MCU = decode_mcu_table[0]; - convert_to_pixfmt = colorspace_array_conv[0]; - trace("Use decode 1x1 sampling\n"); - } else if (priv->component_infos[cY].Hfactor == 1) { - decode_MCU = decode_mcu_table[1]; - convert_to_pixfmt = colorspace_array_conv[1]; - ystride_by_mcu = 16; - trace("Use decode 1x2 sampling (not supported)\n"); - } else if (priv->component_infos[cY].Vfactor == 2) { - decode_MCU = decode_mcu_table[3]; - convert_to_pixfmt = colorspace_array_conv[3]; - xstride_by_mcu = 16; - ystride_by_mcu = 16; - trace("Use decode 2x2 sampling\n"); - } else { - decode_MCU = decode_mcu_table[2]; - convert_to_pixfmt = colorspace_array_conv[2]; - xstride_by_mcu = 16; - trace("Use decode 2x1 sampling\n"); - } - - resync(priv); - - /* Don't forget to that block can be either 8 or 16 lines */ - bytes_per_blocklines[0] *= ystride_by_mcu; - bytes_per_blocklines[1] *= ystride_by_mcu; - bytes_per_blocklines[2] *= ystride_by_mcu; - - bytes_per_mcu[0] *= xstride_by_mcu/8; - bytes_per_mcu[1] *= xstride_by_mcu/8; - bytes_per_mcu[2] *= xstride_by_mcu/8; - - /* Just the decode the image by macroblock (size is 8x8, 8x16, or 16x16) */ - - - - for (y=0; y < priv->height; y+=ystride_by_mcu) - { - //trace("Decoding row %d\n", y); - /// priv->plane[0] = priv->components[0] + (y/ystride_by_mcu * bytes_per_blocklines[0]); - /// priv->plane[1] = priv->components[1] + (y/ystride_by_mcu * bytes_per_blocklines[1]); - /// priv->plane[2] = priv->components[2] + (y/ystride_by_mcu * bytes_per_blocklines[2]); - for (x=0; x < priv->width; x+=xstride_by_mcu) - { - int i,copy_x,copy_y; - decode_MCU(priv); - convert_to_pixfmt(priv); - //priv->plane[0] += bytes_per_mcu[0]; - //priv->plane[1] += bytes_per_mcu[1]; - //priv->plane[2] += bytes_per_mcu[2]; - - copy_x=priv->width-x; - if (copy_x>xstride_by_mcu) - copy_x=xstride_by_mcu; - - copy_y=priv->height-y; - if (copy_y>ystride_by_mcu) - copy_y=ystride_by_mcu; - - for(i=0;i<copy_y;i++) { - unsigned char *dst = &priv->components[0][((y+i)*priv->width+x)*3]; - memcpy(dst,&priv->decomp_block[i][0],copy_x*3); - } - - if (priv->restarts_to_go>0) - { - priv->restarts_to_go--; - if (priv->restarts_to_go == 0) - { - priv->stream -= (priv->nbits_in_reservoir/8); - resync(priv); - if (find_next_rst_marker(priv) < 0) - return -1; - } - } - } - } - - trace("Input file size: %d\n", priv->stream_length+2); - trace("Input bytes actually read: %d\n", priv->stream - priv->stream_begin + 2); - - return 0; -} - -const char *tinyjpeg_get_errorstring(struct jdec_private *priv) -{ - /* FIXME: the error string must be store in the context */ - priv = priv; - return error_string; -} - -void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height) -{ - *width = priv->width; - *height = priv->height; -} - -int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components) -{ - int i; - for (i=0; priv->components[i] && i<COMPONENTS; i++) - components[i] = priv->components[i]; - return 0; -} - -int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents) -{ - unsigned int i; - if (ncomponents > COMPONENTS) - ncomponents = COMPONENTS; - for (i=0; i<ncomponents; i++) - priv->components[i] = components[i]; - return 0; -} - -int tinyjpeg_set_flags(struct jdec_private *priv, int flags) -{ - int oldflags = priv->flags; - priv->flags = flags; - return oldflags; -} - diff --git a/drivers/jpg/tinyjpeg.h b/drivers/jpg/tinyjpeg.h deleted file mode 100644 index fe4652360b..0000000000 --- a/drivers/jpg/tinyjpeg.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Small jpeg decoder library (header file) - * - * Copyright (c) 2006, Luc Saillard <luc@saillard.org> - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * - Neither the name of the author nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#ifndef __JPEGDEC_H__ -#define __JPEGDEC_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -struct jdec_private; - -/* Flags that can be set by any applications */ -#define TINYJPEG_FLAGS_MJPEG_TABLE (1<<1) - -/* Format accepted in outout */ -enum tinyjpeg_fmt { - TINYJPEG_FMT_GREY = 1, - TINYJPEG_FMT_BGR24, - TINYJPEG_FMT_RGB24, - TINYJPEG_FMT_YUV420P, -}; - -struct jdec_private *tinyjpeg_init(void *(*allocate_mem)(unsigned int),void (*free_mem)(void *)); - -void tinyjpeg_free(struct jdec_private *priv); - -int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size); -int tinyjpeg_decode(struct jdec_private *priv, int pixel_format); -const char *tinyjpeg_get_errorstring(struct jdec_private *priv); -void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height); -int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components); -int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents); -int tinyjpeg_set_flags(struct jdec_private *priv, int flags); - -#ifdef __cplusplus -} -#endif - -#endif - - - diff --git a/drivers/pnm/SCsub b/drivers/pnm/SCsub new file mode 100644 index 0000000000..28b35773a4 --- /dev/null +++ b/drivers/pnm/SCsub @@ -0,0 +1,10 @@ +Import('env') + + +pnm_sources = [ + "pnm/bitmap_loader_pnm.cpp" + ] + +env.drivers_sources+=pnm_sources + +#env.add_source_files(env.drivers_sources, pnm_sources) diff --git a/drivers/pnm/bitmap_loader_pnm.cpp b/drivers/pnm/bitmap_loader_pnm.cpp new file mode 100644 index 0000000000..874e5977c1 --- /dev/null +++ b/drivers/pnm/bitmap_loader_pnm.cpp @@ -0,0 +1,232 @@ +/*************************************************/ +/* image_loader_jpg.cpp */ +/*************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/*************************************************/ +/* Source code within this file is: */ +/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */ +/* All Rights Reserved. */ +/*************************************************/ + +#include "bitmap_loader_pnm.h" +#include "os/file_access.h" +#include "scene/resources/bit_mask.h" + + +static bool _get_token(FileAccessRef& f,uint8_t &saved,DVector<uint8_t>& r_token,bool p_binary=false,bool p_single_chunk=false) { + + + int token_max = r_token.size(); + DVector<uint8_t>::Write w; + if (token_max) + w=r_token.write(); + int ofs=0; + bool lf=false; + + + while(true) { + + uint8_t b; + if (saved) { + b=saved; + saved=0; + } else { + b = f->get_8(); + } + if (f->eof_reached()) { + if (ofs) { + w=DVector<uint8_t>::Write(); + r_token.resize(ofs); + return true; + } else { + return false; + } + } + + if (!ofs && !p_binary && b=='#') { + //skip comment + while(b!='\n') { + if (f->eof_reached()) { + return false; + } + + b = f->get_8(); + } + + lf=true; + + } else if (b<=32 && !(p_binary && (ofs || lf))) { + + if (b=='\n') { + lf=true; + } + + + if (ofs && !p_single_chunk) { + w=DVector<uint8_t>::Write(); + r_token.resize(ofs); + saved=b; + + return true; + } + } else { + + bool resized=false; + while (ofs>=token_max) { + if (token_max) + token_max<<=1; + else + token_max=1; + resized=true; + } + if (resized) { + w=DVector<uint8_t>::Write(); + r_token.resize(token_max); + w=r_token.write(); + } + w[ofs++]=b; + } + } + + return false; +} + +static int _get_number_from_token(DVector<uint8_t>& r_token) { + + int len = r_token.size(); + DVector<uint8_t>::Read r = r_token.read(); + return String::to_int((const char*)r.ptr(),len); + +} + + +RES ResourceFormatPBM::load(const String &p_path,const String& p_original_path,Error *r_error) { + +#define _RETURN(m_err)\ +{\ + if (r_error)\ + *r_error=m_err;\ + ERR_FAIL_V(RES());\ +} + + + FileAccessRef f=FileAccess::open(p_path,FileAccess::READ); + uint8_t saved=0; + if (!f) + _RETURN(ERR_CANT_OPEN); + + DVector<uint8_t> token; + + if (!_get_token(f,saved,token)) { + _RETURN(ERR_PARSE_ERROR); + } + + if (token.size()!=2) { + _RETURN(ERR_FILE_CORRUPT); + } + if (token[0]!='P') { + _RETURN(ERR_FILE_CORRUPT); + } + if (token[1]!='1' && token[1]!='4') { + _RETURN(ERR_FILE_CORRUPT); + } + + bool bits = token[1]=='4'; + + if (!_get_token(f,saved,token)) { + _RETURN(ERR_PARSE_ERROR); + } + + int width = _get_number_from_token(token); + if (width<=0) { + _RETURN(ERR_FILE_CORRUPT); + } + + + if (!_get_token(f,saved,token)) { + _RETURN(ERR_PARSE_ERROR); + } + + int height = _get_number_from_token(token); + if (height<=0) { + _RETURN(ERR_FILE_CORRUPT); + } + + + Ref<BitMap> bm; + bm.instance(); + bm->create(Size2i(width,height)); + + if (!bits) { + + int required_bytes = width*height; + if (!_get_token(f,saved,token,false,true)) { + _RETURN(ERR_PARSE_ERROR); + } + + if (token.size()<required_bytes) { + _RETURN(ERR_FILE_CORRUPT); + } + + DVector<uint8_t>::Read r=token.read(); + + for(int i=0;i<height;i++) { + for(int j=0;j<width;j++) { + + + char num = r[i*width+j]; + bm->set_bit(Point2i(j,i),num=='0'); + } + + } + + + + } else { + //a single, entire token of bits! + if (!_get_token(f,saved,token,true)) { + _RETURN(ERR_PARSE_ERROR); + } + int required_bytes = Math::ceil((width*height)/8.0); + if (token.size()<required_bytes) { + _RETURN(ERR_FILE_CORRUPT); + } + + DVector<uint8_t>::Read r=token.read(); + + for(int i=0;i<height;i++) { + for(int j=0;j<width;j++) { + + int ofs = width*i+j; + + uint8_t byte = r[ofs/8]; + bool bit = (byte>>(7-(ofs%8)))&1; + + bm->set_bit(Point2i(j,i),!bit); + + } + + } + + } + + return bm; + + +} + +void ResourceFormatPBM::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("pbm"); +} +bool ResourceFormatPBM::handles_type(const String& p_type) const { + return p_type=="BitMap"; +} +String ResourceFormatPBM::get_resource_type(const String &p_path) const { + + if (p_path.extension().to_lower()=="pbm") + return "BitMap"; + return ""; +} + + diff --git a/drivers/pnm/bitmap_loader_pnm.h b/drivers/pnm/bitmap_loader_pnm.h new file mode 100644 index 0000000000..6e6c8a59c8 --- /dev/null +++ b/drivers/pnm/bitmap_loader_pnm.h @@ -0,0 +1,33 @@ +/*************************************************/ +/* image_loader_jpg.h */ +/*************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/*************************************************/ +/* Source code within this file is: */ +/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */ +/* All Rights Reserved. */ +/*************************************************/ + +#ifndef BITMAP_LOADER_PNM_H +#define BITMAP_LOADER_PNM_H + +#include "io/resource_loader.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class ResourceFormatPBM : public ResourceFormatLoader { + + +public: + + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String& p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + + + +#endif diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp index 3248177bab..e7bbf28f01 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_types.cpp @@ -14,11 +14,12 @@ #include "png/image_loader_png.h" #include "webp/image_loader_webp.h" #include "png/resource_saver_png.h" -#include "jpg/image_loader_jpg.h" +#include "jpegd/image_loader_jpegd.h" #include "dds/texture_loader_dds.h" #include "pvr/texture_loader_pvr.h" #include "etc1/image_etc.h" #include "chibi/event_stream_chibi.h" +#include "pnm/bitmap_loader_pnm.h" #ifdef TOOLS_ENABLED @@ -112,6 +113,9 @@ static ResourceFormatLoaderAudioStreamMPC * mpc_stream_loader=NULL; #include "openssl/register_openssl.h" #endif + +static ResourceFormatPBM * pbm_loader=NULL; + void register_core_driver_types() { #ifdef PNG_ENABLED @@ -138,6 +142,9 @@ void register_core_driver_types() { ImageLoader::add_image_format_loader( image_loader_jpg ); #endif + pbm_loader = memnew( ResourceFormatPBM ); + ResourceLoader::add_resource_format_loader(pbm_loader); + ObjectTypeDB::register_type<RegEx>(); } @@ -162,6 +169,7 @@ void unregister_core_driver_types() { memdelete( image_loader_jpg ); #endif + memdelete( pbm_loader ); } diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 9843405d4a..349831077c 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -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="rb+"; + mode_string="wb+"; else return ERR_INVALID_PARAMETER; diff --git a/drivers/unix/semaphore_posix.cpp b/drivers/unix/semaphore_posix.cpp index f1f50b0381..3ae94ae5d9 100644 --- a/drivers/unix/semaphore_posix.cpp +++ b/drivers/unix/semaphore_posix.cpp @@ -42,7 +42,7 @@ Error SemaphorePosix::wait() { errno=0; continue; } else { -perror("sem waiting"); + perror("sem waiting"); return ERR_BUSY; } } diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 0de686ed53..818e4258ba 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -71,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"rb+"; + mode_string=L"wb+"; else return ERR_INVALID_PARAMETER; diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index 6180c668ef..53519030fc 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -1253,6 +1253,7 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode * StringName func_name; if (p_func) { + if (p_func->default_values.size()) { codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_TO_DEF_ARGUMENT); @@ -1346,7 +1347,7 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode * if (defarg_addr.size()) { gdfunc->default_arguments=defarg_addr; - gdfunc->_default_arg_count=defarg_addr.size(); + gdfunc->_default_arg_count=defarg_addr.size()-1; gdfunc->_default_arg_ptr=&gdfunc->default_arguments[0]; } else { gdfunc->_default_arg_count=0; diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index 11bb3a859a..e015ddb65e 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -34,6 +34,7 @@ #include "func_ref.h" #include "os/os.h" #include "variant_parser.h" +#include "io/marshalls.h" const char *GDFunctions::get_func_name(Function p_func) { @@ -94,6 +95,8 @@ const char *GDFunctions::get_func_name(Function p_func) { "printraw", "var2str", "str2var", + "var2bytes", + "bytes2var", "range", "load", "inst2dict", @@ -639,6 +642,57 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va } } break; + case VAR_TO_BYTES: { + VALIDATE_ARG_COUNT(1); + + ByteArray barr; + int len; + Error err = encode_variant(*p_args[0],NULL,len); + if (err) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::NIL; + r_ret=Variant(); + return; + } + + barr.resize(len); + { + ByteArray::Write w = barr.write(); + encode_variant(*p_args[0],w.ptr(),len); + + } + r_ret=barr; + } break; + case BYTES_TO_VAR: { + VALIDATE_ARG_COUNT(1); + if (p_args[0]->get_type()!=Variant::RAW_ARRAY) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::RAW_ARRAY; + r_ret=Variant(); + return; + } + + ByteArray varr=*p_args[0]; + Variant ret; + { + ByteArray::Read r=varr.read(); + Error err = decode_variant(ret,r.ptr(),varr.size(),NULL); + if (err!=OK) { + ERR_PRINT("Not enough bytes for decoding.."); + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::RAW_ARRAY; + r_ret=Variant(); + return; + } + + } + + r_ret=ret; + + } break; case GEN_RANGE: { switch(p_arg_count) { @@ -1358,6 +1412,18 @@ MethodInfo GDFunctions::get_info(Function p_func) { mi.return_val.type=Variant::NIL; return mi; } break; + case VAR_TO_BYTES: { + MethodInfo mi("var2bytes",PropertyInfo(Variant::NIL,"var")); + mi.return_val.type=Variant::RAW_ARRAY; + return mi; + + } break; + case BYTES_TO_VAR: { + + MethodInfo mi("bytes2var:Variant",PropertyInfo(Variant::RAW_ARRAY,"bytes")); + mi.return_val.type=Variant::NIL; + return mi; + } break; case GEN_RANGE: { MethodInfo mi("range",PropertyInfo(Variant::NIL,"...")); diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h index e6ef8b9ec8..8c88472567 100644 --- a/modules/gdscript/gd_functions.h +++ b/modules/gdscript/gd_functions.h @@ -89,6 +89,8 @@ public: TEXT_PRINTRAW, VAR_TO_STR, STR_TO_VAR, + VAR_TO_BYTES, + BYTES_TO_VAR, GEN_RANGE, RESOURCE_LOAD, INST2DICT, diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 73264b0a12..c4175e048d 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -267,6 +267,13 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ constant->value=tokenizer->get_token_constant(); tokenizer->advance(); expr=constant; + } else if (tokenizer->get_token()==GDTokenizer::TK_CONST_PI) { + + //constant defined by tokenizer + ConstantNode *constant = alloc_node<ConstantNode>(); + constant->value=Math_PI; + tokenizer->advance(); + expr=constant; } else if (tokenizer->get_token()==GDTokenizer::TK_PR_PRELOAD) { //constant defined by tokenizer diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 9b9b0e4b8c..d753a9f167 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -33,17 +33,6 @@ #include "os/file_access.h" #include "io/file_access_encrypted.h" -/* TODO: - - *populate globals - *do checks as close to debugger as possible (but don't do debugger) - *const check plz - *check arguments and default arguments in GDFunction - -get property list in instance? - *missing opcodes - -const checks - -make thread safe - */ @@ -232,6 +221,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a r_err.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_err.argument=_argument_count; + return Variant(); } else if (p_argcount < _argument_count - _default_arg_count) { @@ -1603,6 +1593,28 @@ void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { }*/ #endif + +bool GDScript::get_property_default_value(const StringName& p_property, Variant &r_value) const { + +#ifdef TOOLS_ENABLED + + //for (const Map<StringName,Variant>::Element *I=member_default_values.front();I;I=I->next()) { + // print_line("\t"+String(String(I->key())+":"+String(I->get()))); + //} + const Map<StringName,Variant>::Element *E=member_default_values_cache.find(p_property); + if (E) { + r_value=E->get(); + return true; + } + + if (base_cache.is_valid()) { + return base_cache->get_property_default_value(p_property,r_value); + } +#endif + return false; + +} + ScriptInstance* GDScript::instance_create(Object *p_this) { @@ -1740,16 +1752,21 @@ bool GDScript::_update_exports() { } } - Ref<GDScript> bf = ResourceLoader::load(path); + if (path!=get_path()) { + + Ref<GDScript> bf = ResourceLoader::load(path); - if (bf.is_valid()) { + if (bf.is_valid()) { - //print_line("parent is: "+bf->get_path()); - base_cache=bf; - bf->inheriters_cache.insert(get_instance_ID()); + //print_line("parent is: "+bf->get_path()); + base_cache=bf; + bf->inheriters_cache.insert(get_instance_ID()); - //bf->_update_exports(p_instances,true,false); + //bf->_update_exports(p_instances,true,false); + } + } else { + ERR_PRINT(("Path extending itself in "+path).utf8().get_data()); } } diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 173997a1fe..cf8f762a86 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -352,6 +352,8 @@ public: Vector<uint8_t> get_as_byte_code() const; + bool get_property_default_value(const StringName& p_property,Variant& r_value) const; + virtual ScriptLanguage *get_language() const; GDScript(); diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index bebdef83aa..377ef06694 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -111,6 +111,7 @@ const char* GDTokenizer::token_names[TK_MAX]={ "'?'", "':'", "'\\n'", +"PI", "Error", "EOF", "Cursor"}; @@ -260,6 +261,7 @@ void GDTokenizerText::_advance() { } INCPOS(1); + line++; while(GETCHAR(0)==' ' || GETCHAR(0)=='\t') { INCPOS(1); @@ -877,6 +879,7 @@ void GDTokenizerText::_advance() { {TK_CF_RETURN,"return"}, {TK_CF_PASS,"pass"}, {TK_SELF,"self"}, + {TK_CONST_PI,"PI"}, {TK_ERROR,NULL} }; @@ -1043,7 +1046,7 @@ void GDTokenizerText::advance(int p_amount) { ////////////////////////////////////////////////////////////////////////////////////////////////////// -#define BYTECODE_VERSION 8 +#define BYTECODE_VERSION 10 Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) { diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index bbd1ec5b72..aaff573090 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -119,6 +119,7 @@ public: TK_QUESTION_MARK, TK_COLON, TK_NEWLINE, + TK_CONST_PI, TK_ERROR, TK_EOF, TK_CURSOR, //used for code completion diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/AndroidManifest.xml.template index c95c86c060..02645aff7f 100644 --- a/platform/android/AndroidManifest.xml.template +++ b/platform/android/AndroidManifest.xml.template @@ -3,7 +3,7 @@ package="com.godot.game" android:versionCode="1" android:versionName="1.0" - android:installLocation="preferExternal" + android:installLocation="auto" > <supports-screens android:smallScreens="true" android:normalScreens="true" diff --git a/platform/windows/joystick.h b/platform/windows/joystick.h index ad62059a73..332e86fbb8 100644 --- a/platform/windows/joystick.h +++ b/platform/windows/joystick.h @@ -44,6 +44,9 @@ if(x != NULL) \ } #endif +#ifndef XUSER_MAX_COUNT +#define XUSER_MAX_COUNT 4 +#endif class joystick_windows { diff --git a/platform/x11/joystick_linux.cpp b/platform/x11/joystick_linux.cpp index 050fdac2b8..6eb3671bc0 100644 --- a/platform/x11/joystick_linux.cpp +++ b/platform/x11/joystick_linux.cpp @@ -52,8 +52,13 @@ joystick_linux::Joystick::Joystick() { void joystick_linux::Joystick::reset() { dpad = 0; fd = -1; + + InputDefault::JoyAxis jx; + jx.min = -1; + jx.value = 0.0f; for (int i=0; i < MAX_ABS; i++) { abs_map[i] = -1; + curr_axis[i] = jx; } } @@ -390,7 +395,7 @@ uint32_t joystick_linux::process_joysticks(uint32_t p_event_id) { default: if (joy->abs_map[ev.code] != -1) { InputDefault::JoyAxis value = axis_correct(libevdev_get_abs_info(dev, ev.code), ev.value); - p_event_id = input->joy_axis(p_event_id, i, joy->abs_map[ev.code], value); + joy->curr_axis[joy->abs_map[ev.code]] = value; } break; } @@ -398,6 +403,12 @@ uint32_t joystick_linux::process_joysticks(uint32_t p_event_id) { } rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); } + for (int j = 0; j < MAX_ABS; j++) { + int index = joy->abs_map[j]; + if (index != -1) { + p_event_id = input->joy_axis(p_event_id, i, index, joy->curr_axis[index]); + } + } } joy_mutex->unlock(); return p_event_id; diff --git a/platform/x11/joystick_linux.h b/platform/x11/joystick_linux.h index 9d22a6c754..ee9bd0352a 100644 --- a/platform/x11/joystick_linux.h +++ b/platform/x11/joystick_linux.h @@ -54,6 +54,7 @@ private: }; struct Joystick { + InputDefault::JoyAxis curr_axis[MAX_ABS]; int key_map[MAX_KEY - BT_MISC]; int abs_map[MAX_ABS]; int dpad; diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 0887fd9df2..437e41eead 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -447,6 +447,9 @@ void OS_X11::finalize() { // memdelete(debugger_connection_console); //} +#ifdef JOYDEV_ENABLED + memdelete(joystick); +#endif memdelete(input); memdelete(sample_manager); @@ -463,9 +466,6 @@ void OS_X11::finalize() { physics_2d_server->finish(); memdelete(physics_2d_server); -#ifdef JOYDEV_ENABLED - memdelete(joystick); -#endif XUnmapWindow( x11_display, x11_window ); XDestroyWindow( x11_display, x11_window ); @@ -619,6 +619,7 @@ void OS_X11::set_wm_fullscreen(bool p_enabled) { xev.xclient.data.l[2] = 0; XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + } int OS_X11::get_screen_count() const { @@ -887,7 +888,16 @@ void OS_X11::set_window_maximized(bool p_enabled) { XGetWindowAttributes(x11_display,DefaultRootWindow(x11_display),&xwa); current_videomode.width = xwa.width; current_videomode.height = xwa.height; -*/ +//*/ + +// current_videomode.width = wm_max_horz; +// current_videomode.height = wm_max_vert; + + //Size2 ss = get_screen_size(get_current_screen()); + //current_videomode.width=ss.width; + //current_videomode.height=ss.height; + + maximized = p_enabled; } diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 8f6df43c76..35b453d71d 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -389,8 +389,8 @@ Matrix32 CanvasItem::get_global_transform_with_canvas() const { if (last_valid->canvas_layer) return last_valid->canvas_layer->get_transform() * xform; - else - return xform; + else if (is_inside_tree()) + return get_viewport()->get_canvas_transform() * xform; } Matrix32 CanvasItem::get_global_transform() const { @@ -548,6 +548,7 @@ void CanvasItem::_notification(int p_what) { get_parent()->cast_to<CanvasItem>()->children_items.erase(C); C=NULL; } + global_invalid=true; } break; case NOTIFICATION_DRAW: { diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index dd8aa9e8b1..71a45024c4 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1250,7 +1250,7 @@ void KinematicBody2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&KinematicBody2D::get_collider_velocity); ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody2D::_get_collider); ObjectTypeDB::bind_method(_MD("get_collider_shape"),&KinematicBody2D::get_collider_shape); - ObjectTypeDB::bind_method(_MD("get_collider_metadata"),&KinematicBody2D::get_collider_metadata); + ObjectTypeDB::bind_method(_MD("get_collider_metadata:Variant"),&KinematicBody2D::get_collider_metadata); ObjectTypeDB::bind_method(_MD("set_collision_margin","pixels"),&KinematicBody2D::set_collision_margin); ObjectTypeDB::bind_method(_MD("get_collision_margin","pixels"),&KinematicBody2D::get_collision_margin); diff --git a/scene/2d/screen_button.cpp b/scene/2d/screen_button.cpp index 0254eb2836..d7f9b191fe 100644 --- a/scene/2d/screen_button.cpp +++ b/scene/2d/screen_button.cpp @@ -161,7 +161,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) { if (finger_pressed==-1 || p_event.screen_touch.index==finger_pressed) { - Point2 coord = (get_global_transform()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y)); + Point2 coord = (get_global_transform_with_canvas()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y)); bool touched=false; if (bitmask.is_valid()) { @@ -238,7 +238,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) { if (finger_pressed!=-1) return; //already fingering - Point2 coord = (get_global_transform()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y)); + Point2 coord = (get_global_transform_with_canvas()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y)); bool touched=false; if (bitmask.is_valid()) { diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 644129db89..3e78fef147 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -125,7 +125,7 @@ bool Camera::_get(const StringName& p_name,Variant &r_ret) const { r_ret= int(keep_aspect); else if (p_name=="current") { - if (is_inside_tree() && get_tree()->is_editor_hint()) { + if (is_inside_tree() && get_tree()->is_node_being_edited(this)) { r_ret=current; } else { r_ret=is_current(); @@ -192,12 +192,11 @@ void Camera::_update_camera() { // here goes listener stuff // if (viewport_ptr && is_inside_scene() && is_current()) -// viewport_ptr->_camera_transform_changed_notify(); +// get_viewport()->_camera_transform_changed_notify(); if (is_inside_tree() && is_current()) { - if (viewport_ptr) { - viewport_ptr->_camera_transform_changed_notify(); - } + get_viewport()->_camera_transform_changed_notify(); + } if (is_current() && get_world().is_valid()) { @@ -213,29 +212,10 @@ void Camera::_notification(int p_what) { case NOTIFICATION_ENTER_WORLD: { - viewport_ptr=NULL; - - { //find viewport stuff - Node *parent=get_parent(); - while(parent) { - - Viewport* viewport = parent->cast_to<Viewport>(); - - if (viewport) { - viewport_ptr=viewport; - break; - } - parent=parent->get_parent(); - } - - } - - camera_group = "_vp_cameras"+itos(get_viewport()->get_instance_ID()); - add_to_group(camera_group); - if (viewport_ptr) - viewport_ptr->cameras.insert(this); - if (current) + bool first_camera = get_viewport()->cameras.size()==0; + get_viewport()->cameras.insert(this); + if (!get_tree()->is_node_being_edited(this) && (current || first_camera)) make_current(); @@ -246,17 +226,17 @@ void Camera::_notification(int p_what) { } break; case NOTIFICATION_EXIT_WORLD: { - if (is_current()) { - clear_current(); - current=true; //keep it true + if (!get_tree()->is_node_being_edited(this)) { + if (is_current()) { + clear_current(); + current=true; //keep it true - } else { - current=false; + } else { + current=false; + } } - if (viewport_ptr) - viewport_ptr->cameras.erase(this); - viewport_ptr=NULL; - remove_from_group(camera_group); + + get_viewport()->cameras.erase(this); } break; @@ -324,25 +304,12 @@ void Camera::make_current() { if (!is_inside_tree()) return; - if (viewport_ptr) { - viewport_ptr->_set_camera(this); - } + get_viewport()->_set_camera(this); //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,camera_group,"_camera_make_current",this); } -void Camera::_camera_make_next_current(Node *p_exclude) { - - if (this==p_exclude) - return; - if (!is_inside_tree()) - return; - if (get_viewport()->get_camera()!=NULL) - return; - - make_current(); -} void Camera::clear_current() { @@ -351,12 +318,20 @@ void Camera::clear_current() { if (!is_inside_tree()) return; - if (viewport_ptr) { - if (viewport_ptr->get_camera()==this) { - viewport_ptr->_set_camera(NULL); - //a group is used beause this needs to be in order to be deterministic - get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,camera_group,"_camera_make_next_current",this); + if (get_viewport()->get_camera()==this) { + get_viewport()->_set_camera(NULL); + //a group is used beause this needs to be in order to be deterministic + + for (Set<Camera*>::Element *E=get_viewport()->cameras.front();E;E=E->next()) { + if (this==E->get()) + continue; + if (!E->get()->is_inside_tree()) + continue; + if (get_viewport()->get_camera()!=NULL) + return; + + E->get()->make_current(); } } @@ -364,9 +339,9 @@ void Camera::clear_current() { bool Camera::is_current() const { - if (is_inside_tree()) { - if (viewport_ptr) - return viewport_ptr->get_camera()==this; + if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) { + + return get_viewport()->get_camera()==this; } else return current; @@ -481,12 +456,12 @@ Vector3 Camera::project_local_ray_normal(const Point2& p_pos) const { #if 0 - Size2 viewport_size = viewport_ptr->get_visible_rect().size; + Size2 viewport_size = get_viewport()->get_visible_rect().size; Vector2 cpos = p_pos; #else - Size2 viewport_size = viewport_ptr->get_camera_rect_size(); - Vector2 cpos = viewport_ptr->get_camera_coords(p_pos); + Size2 viewport_size = get_viewport()->get_camera_rect_size(); + Vector2 cpos = get_viewport()->get_camera_coords(p_pos); #endif Vector3 ray; @@ -514,12 +489,12 @@ Vector3 Camera::project_ray_origin(const Point2& p_pos) const { } #if 0 - Size2 viewport_size = viewport_ptr->get_visible_rect().size; + Size2 viewport_size = get_viewport()->get_visible_rect().size; Vector2 cpos = p_pos; #else - Size2 viewport_size = viewport_ptr->get_camera_rect_size(); - Vector2 cpos = viewport_ptr->get_camera_coords(p_pos); + Size2 viewport_size = get_viewport()->get_camera_rect_size(); + Vector2 cpos = get_viewport()->get_camera_coords(p_pos); #endif ERR_FAIL_COND_V( viewport_size.y == 0, Vector3() ); @@ -566,7 +541,7 @@ Point2 Camera::unproject_position(const Vector3& p_pos) const { ERR_FAIL_COND_V(!is_inside_tree(),Vector2()); } - Size2 viewport_size = viewport_ptr->get_visible_rect().size; + Size2 viewport_size = get_viewport()->get_visible_rect().size; CameraMatrix cm; @@ -597,7 +572,7 @@ Vector3 Camera::project_position(const Point2& p_point) const { ERR_FAIL_COND_V(!is_inside_tree(),Vector3()); } - Size2 viewport_size = viewport_ptr->get_visible_rect().size; + Size2 viewport_size = get_viewport()->get_visible_rect().size; CameraMatrix cm; @@ -692,7 +667,6 @@ void Camera::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_environment:Environment"),&Camera::get_environment); ObjectTypeDB::bind_method(_MD("set_keep_aspect_mode","mode"),&Camera::set_keep_aspect_mode); ObjectTypeDB::bind_method(_MD("get_keep_aspect_mode"),&Camera::get_keep_aspect_mode); - ObjectTypeDB::bind_method(_MD("_camera_make_next_current"),&Camera::_camera_make_next_current); //ObjectTypeDB::bind_method( _MD("_camera_make_current"),&Camera::_camera_make_current ); BIND_CONSTANT( PROJECTION_PERSPECTIVE ); @@ -745,7 +719,7 @@ Vector<Plane> Camera::get_frustum() const { ERR_FAIL_COND_V(!is_inside_world(),Vector<Plane>()); - Size2 viewport_size = viewport_ptr->get_visible_rect().size; + Size2 viewport_size = get_viewport()->get_visible_rect().size; CameraMatrix cm; if (mode==PROJECTION_PERSPECTIVE) cm.set_perspective(fov,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH); @@ -789,7 +763,6 @@ Camera::Camera() { near=0; far=0; current=false; - viewport_ptr=NULL; force_change=false; mode=PROJECTION_PERSPECTIVE; set_perspective(60.0,0.1,100.0); diff --git a/scene/3d/camera.h b/scene/3d/camera.h index dcb7a21961..02ca6ffb9a 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -68,18 +68,15 @@ private: RID camera; RID scenario_id; - String camera_group; + //String camera_group; uint32_t layers; - Viewport *viewport_ptr; Ref<Environment> environment; virtual bool _can_gizmo_scale() const; virtual RES _get_gizmo_geometry() const; - void _camera_make_next_current(Node *p_exclude); - //void _camera_make_current(Node *p_camera); friend class Viewport; diff --git a/scene/audio/stream_player.cpp b/scene/audio/stream_player.cpp index 74d84b8b08..0180ed4a1d 100644 --- a/scene/audio/stream_player.cpp +++ b/scene/audio/stream_player.cpp @@ -170,6 +170,7 @@ void StreamPlayer::stop() { stop_request=false; playback->stop(); resampler.flush(); + emit_signal("finished"); //set_idle_process(false); } @@ -378,6 +379,8 @@ void StreamPlayer::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") ); ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/loop_restart_time"), _SCS("set_loop_restart_time"), _SCS("get_loop_restart_time") ); ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/buffering_ms"), _SCS("set_buffering_msec"), _SCS("get_buffering_msec") ); + + ADD_SIGNAL(MethodInfo("finished")); } diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 59f2f34b82..b9ce46d738 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -137,8 +137,10 @@ void Button::_notification(int p_what) { text_ofs.y+=font->get_ascent(); font->draw( ci, text_ofs.floor(), text, color,clip_text?text_clip:-1); if (!_icon.is_null()) { + + int valign = size.height-style->get_minimum_size().y; - _icon->draw(ci,Point2(style->get_offset().x, Math::floor( (size.height-_icon->get_height())/2.0 ) ),is_disabled()?Color(1,1,1,0.4):Color(1,1,1) ); + _icon->draw(ci,style->get_offset()+Point2(0, Math::floor( (valign-_icon->get_height())/2.0 ) ),is_disabled()?Color(1,1,1,0.4):Color(1,1,1) ); } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 95b79cc940..0780a4bdaf 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2067,6 +2067,8 @@ void Node::_bind_methods() { BIND_CONSTANT( NOTIFICATION_UNPARENTED ); BIND_CONSTANT( NOTIFICATION_PAUSED ); BIND_CONSTANT( NOTIFICATION_UNPAUSED ); + BIND_CONSTANT( NOTIFICATION_INSTANCED ); + BIND_CONSTANT( PAUSE_MODE_INHERIT ); diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index da1d6b3204..a18eb1249f 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -620,6 +620,14 @@ void SceneTree::set_editor_hint(bool p_enabled) { editor_hint=p_enabled; } +bool SceneTree::is_node_being_edited(const Node* p_node) const { +#ifdef TOOLS_ENABLED + return editor_hint && edited_scene_root && edited_scene_root->is_a_parent_of(p_node); +#else + return false; +#endif +} + bool SceneTree::is_editor_hint() const { return editor_hint; @@ -965,6 +973,10 @@ Array SceneTree::_get_nodes_in_group(const StringName& p_group) { return ret; } +bool SceneTree::has_group(const StringName& p_identifier) const { + + return group_map.has(p_identifier); +} void SceneTree::get_nodes_in_group(const StringName& p_group,List<Node*> *p_list) { @@ -1589,6 +1601,7 @@ void SceneTree::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_nodes_in_group","group"),&SceneTree::_get_nodes_in_group); ObjectTypeDB::bind_method(_MD("get_root:Viewport"),&SceneTree::get_root); + ObjectTypeDB::bind_method(_MD("has_group","name"),&SceneTree::has_group); ObjectTypeDB::bind_method(_MD("set_auto_accept_quit","enabled"),&SceneTree::set_auto_accept_quit); diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index 9ff9bb5747..c6fc124345 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -279,6 +279,8 @@ public: void set_editor_hint(bool p_enabled); bool is_editor_hint() const; + bool is_node_being_edited(const Node* p_node) const; + void set_pause(bool p_enabled); bool is_paused() const; @@ -318,6 +320,8 @@ public: void queue_delete(Object *p_object); void get_nodes_in_group(const StringName& p_group,List<Node*> *p_list); + bool has_group(const StringName& p_identifier) const; + void set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 84b65fc4d6..6c4fe1be79 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -221,7 +221,7 @@ static ResourceFormatLoaderImage *resource_loader_image=NULL; static ResourceFormatLoaderWAV *resource_loader_wav=NULL; -static ResourceFormatLoaderBitMap *resource_loader_bitmap=NULL; + #ifdef TOOLS_ENABLED @@ -249,8 +249,6 @@ void register_scene_types() { resource_loader_wav = memnew( ResourceFormatLoaderWAV ); ResourceLoader::add_resource_format_loader( resource_loader_wav ); - resource_loader_bitmap = memnew( ResourceFormatLoaderBitMap ); - ResourceLoader::add_resource_format_loader( resource_loader_bitmap ); #ifdef TOOLS_ENABLED @@ -631,7 +629,6 @@ void unregister_scene_types() { memdelete( resource_loader_image ); memdelete( resource_loader_wav ); - memdelete( resource_loader_bitmap ); #ifdef TOOLS_ENABLED diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp index 7cbc145084..f5bfce3ef8 100644 --- a/scene/resources/bit_mask.cpp +++ b/scene/resources/bit_mask.cpp @@ -204,57 +204,3 @@ BitMap::BitMap() { ////////////////////////////////////// - -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 ); - - - Image image; - - Error err = ImageLoader::load_image(p_path,&image); - - ERR_EXPLAIN("Failed loading image for BitMap: "+p_path); - ERR_FAIL_COND_V(err, RES()); - - bitmap->create_from_image_alpha(image); - if (r_error) - *r_error=OK; - - return bitmap; - -} - -bool ResourceFormatLoaderBitMap::handles_type(const String& p_type) const { - - return (p_type=="BitMap"); -} - -void ResourceFormatLoaderBitMap::get_recognized_extensions(List<String> *p_extensions) const { - - ImageLoader::get_recognized_extensions(p_extensions); -} - -String ResourceFormatLoaderBitMap::get_resource_type(const String &p_path) const { - - List<String> extensions; - ImageLoader::get_recognized_extensions(&extensions); - String ext=p_path.extension().to_lower(); - for(List<String>::Element *E=extensions.front();E;E=E->next()) { - if (E->get()==ext) - return "BitMap"; - } - return ""; -} - - -ResourceFormatLoaderBitMap::ResourceFormatLoaderBitMap() { - - -} - - diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h index 66623f55c8..b245ea1542 100644 --- a/scene/resources/bit_mask.h +++ b/scene/resources/bit_mask.h @@ -62,16 +62,5 @@ public: BitMap(); }; -class ResourceFormatLoaderBitMap : 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; - - ResourceFormatLoaderBitMap(); -}; #endif // BIT_MASK_H diff --git a/scene/resources/sample.cpp b/scene/resources/sample.cpp index 0354cbc3b2..4b25a2c490 100644 --- a/scene/resources/sample.cpp +++ b/scene/resources/sample.cpp @@ -210,11 +210,11 @@ void Sample::_bind_methods(){ ADD_PROPERTY( PropertyInfo( Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), _SCS("_set_data"), _SCS("_get_data") ); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "stereo"), _SCS(""), _SCS("is_stereo") ); - ADD_PROPERTY( PropertyInfo( Variant::INT, "length"), _SCS(""), _SCS("get_length") ); + ADD_PROPERTY( PropertyInfo( Variant::INT, "length",PROPERTY_HINT_RANGE,"0,999999999"), _SCS(""), _SCS("get_length") ); ADD_PROPERTY( PropertyInfo( Variant::INT, "mix_rate", PROPERTY_HINT_RANGE,"1,192000,1" ), _SCS("set_mix_rate"), _SCS("get_mix_rate") ); ADD_PROPERTY( PropertyInfo( Variant::INT, "loop_format", PROPERTY_HINT_ENUM,"None,Forward,PingPong" ), _SCS("set_loop_format"), _SCS("get_loop_format") ); - ADD_PROPERTY( PropertyInfo( Variant::INT, "loop_begin", PROPERTY_HINT_RANGE,"0,"+itos(99999999)+",1"), _SCS("set_loop_begin"), _SCS("get_loop_begin") ); - ADD_PROPERTY( PropertyInfo( Variant::INT, "loop_end", PROPERTY_HINT_RANGE,"0,"+itos(99999999)+",1"), _SCS("set_loop_end"), _SCS("get_loop_end") ); + ADD_PROPERTY( PropertyInfo( Variant::INT, "loop_begin", PROPERTY_HINT_RANGE,"0,"+itos(999999999)+",1"), _SCS("set_loop_begin"), _SCS("get_loop_begin") ); + ADD_PROPERTY( PropertyInfo( Variant::INT, "loop_end", PROPERTY_HINT_RANGE,"0,"+itos(999999999)+",1"), _SCS("set_loop_end"), _SCS("get_loop_end") ); BIND_CONSTANT( FORMAT_PCM8 ); BIND_CONSTANT( FORMAT_PCM16 ); diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp index bfac852481..b0ed99cb48 100644 --- a/servers/physics/body_sw.cpp +++ b/servers/physics/body_sw.cpp @@ -380,6 +380,8 @@ void BodySW::set_space(SpaceSW *p_space){ } + first_integration=true; + } void BodySW::_compute_area_gravity_and_dampenings(const AreaSW *p_area) { @@ -479,7 +481,7 @@ void BodySW::integrate_forces(real_t p_step) { do_motion=true; } else { - if (!omit_force_integration) { + if (!omit_force_integration && !first_integration) { //overriden by direct state query Vector3 force=gravity*mass; @@ -512,6 +514,7 @@ void BodySW::integrate_forces(real_t p_step) { applied_force=Vector3(); applied_torque=Vector3(); + first_integration=false; //motion=linear_velocity*p_step; @@ -749,6 +752,7 @@ BodySW::BodySW() : CollisionObjectSW(TYPE_BODY), active_list(this), inertia_upda island_next=NULL; island_list_next=NULL; first_time_kinematic=false; + first_integration=false; _set_static(false); contact_count=0; diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h index 7369b4cecf..c958177a19 100644 --- a/servers/physics/body_sw.h +++ b/servers/physics/body_sw.h @@ -79,6 +79,8 @@ class BodySW : public CollisionObjectSW { bool omit_force_integration; bool active; + bool first_integration; + bool continuous_cd; bool can_sleep; bool first_time_kinematic; diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index 129ce708d7..f1f94f3485 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -29,6 +29,7 @@ #include "body_2d_sw.h" #include "space_2d_sw.h" #include "area_2d_sw.h" +#include "physics_2d_server_sw.h" void Body2DSW::_update_inertia() { @@ -378,6 +379,7 @@ void Body2DSW::set_space(Space2DSW *p_space){ } + first_integration=false; } void Body2DSW::_compute_area_gravity_and_dampenings(const Area2DSW *p_area) { @@ -471,7 +473,7 @@ void Body2DSW::integrate_forces(real_t p_step) { //} } else { - if (!omit_force_integration) { + if (!omit_force_integration && !first_integration) { //overriden by direct state query Vector2 force=gravity*mass; @@ -506,6 +508,7 @@ void Body2DSW::integrate_forces(real_t p_step) { //motion=linear_velocity*p_step; + first_integration=false; biased_angular_velocity=0; biased_linear_velocity=Vector2(); @@ -681,6 +684,7 @@ Body2DSW::Body2DSW() : CollisionObject2DSW(TYPE_BODY), active_list(this), inerti gravity_scale=1.0; using_one_way_cache=false; one_way_collision_max_depth=0.1; + first_integration=false; still_time=0; continuous_cd_mode=Physics2DServer::CCD_MODE_DISABLED; @@ -701,3 +705,24 @@ Physics2DDirectSpaceState* Physics2DDirectBodyStateSW::get_space_state() { return body->get_space()->get_direct_state(); } + + +Variant Physics2DDirectBodyStateSW::get_contact_collider_shape_metadata(int p_contact_idx) const { + + ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,Variant()); + + if (!Physics2DServerSW::singletonsw->body_owner.owns(body->contacts[p_contact_idx].collider)) { + + return Variant(); + } + Body2DSW *other = Physics2DServerSW::singletonsw->body_owner.get(body->contacts[p_contact_idx].collider); + + int sidx = body->contacts[p_contact_idx].collider_shape; + if (sidx<0 || sidx>=other->get_shape_count()) { + + return Variant(); + } + + + return other->get_shape_metadata(sidx); +} diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index ae64875567..4bd462ac00 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -81,6 +81,7 @@ class Body2DSW : public CollisionObject2DSW { bool active; bool can_sleep; bool first_time_kinematic; + bool first_integration; bool using_one_way_cache; void _update_inertia(); virtual void _shapes_changed(); @@ -369,7 +370,7 @@ public: virtual Vector2 get_contact_collider_pos(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,Vector2()); return body->contacts[p_contact_idx].collider_pos; } virtual ObjectID get_contact_collider_id(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,0); return body->contacts[p_contact_idx].collider_instance_id; } virtual int get_contact_collider_shape(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,0); return body->contacts[p_contact_idx].collider_shape; } - virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,Variant()); return body->get_shape_metadata(body->contacts[p_contact_idx].collider_shape); } + virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const; virtual Vector2 get_contact_collider_velocity_at_pos(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,Vector2()); return body->contacts[p_contact_idx].collider_velocity_at_pos; } diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index d17d499723..c571331498 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -1322,8 +1322,11 @@ int Physics2DServerSW::get_process_info(ProcessInfo p_info) { } +Physics2DServerSW *Physics2DServerSW::singletonsw=NULL; + Physics2DServerSW::Physics2DServerSW() { + singletonsw=this; BroadPhase2DSW::create_func=BroadPhase2DHashGrid::_create; // BroadPhase2DSW::create_func=BroadPhase2DBasic::_create; diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index 5cdcf9225a..28acf4e2d1 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -42,6 +42,7 @@ class Physics2DServerSW : public Physics2DServer { OBJ_TYPE( Physics2DServerSW, Physics2DServer ); friend class Physics2DDirectSpaceStateSW; +friend class Physics2DDirectBodyStateSW; bool active; int iterations; bool doing_sync; @@ -65,7 +66,7 @@ friend class Physics2DDirectSpaceStateSW; mutable RID_Owner<Body2DSW> body_owner; mutable RID_Owner<Joint2DSW> joint_owner; - + static Physics2DServerSW *singletonsw; // void _clear_query(Query2DSW *p_query); diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 90174d48ee..9ba6bdd5ba 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -192,7 +192,7 @@ int Physics2DDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Matri if (p_result_max<=0) return 0; - Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape); + Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.get(p_shape); ERR_FAIL_COND_V(!shape,0); Rect2 aabb = p_xform.xform(shape->get_aabb()); @@ -239,7 +239,7 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32 - Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape); + Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.get(p_shape); ERR_FAIL_COND_V(!shape,false); Rect2 aabb = p_xform.xform(shape->get_aabb()); @@ -367,7 +367,7 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Matrix32& p_s if (p_result_max<=0) return 0; - Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape); + Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.get(p_shape); ERR_FAIL_COND_V(!shape,0); Rect2 aabb = p_shape_xform.xform(shape->get_aabb()); @@ -474,7 +474,7 @@ static void _rest_cbk_result(const Vector2& p_point_A,const Vector2& p_point_B,v bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,float p_margin,ShapeRestInfo *r_info, const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask) { - Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape); + Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.get(p_shape); ERR_FAIL_COND_V(!shape,0); Rect2 aabb = p_shape_xform.xform(shape->get_aabb()); diff --git a/tools/doc/doc_data.cpp b/tools/doc/doc_data.cpp index 96fd3f6b68..a039c58ff4 100644 --- a/tools/doc/doc_data.cpp +++ b/tools/doc/doc_data.cpp @@ -584,7 +584,10 @@ void DocData::generate(bool p_basic_types) { md.name=mi.name; if (mi.return_val.name!="") md.return_type=mi.return_val.name; - else + else if (mi.name.find(":")!=-1) { + md.return_type=mi.name.get_slice(":",1); + md.name=mi.name.get_slice(":",0); + } else md.return_type=Variant::get_type_name(mi.return_val.type); for(int i=0;i<mi.arguments.size();i++) { @@ -594,8 +597,9 @@ void DocData::generate(bool p_basic_types) { ArgumentDoc ad; ad.name=pi.name; + if (pi.type==Variant::NIL) - ad.type="var"; + ad.type="Variant"; else ad.type=Variant::get_type_name( pi.type ); diff --git a/tools/editor/code_editor.cpp b/tools/editor/code_editor.cpp index 59167abc22..fe863bfebc 100644 --- a/tools/editor/code_editor.cpp +++ b/tools/editor/code_editor.cpp @@ -612,6 +612,7 @@ CodeTextEditor::CodeTextEditor() { if (!font_overrode) text_editor->add_font_override("font",get_font("source","Fonts")); + text_editor->set_show_line_numbers(true); text_editor->set_brace_matching(true); text_editor->set_auto_indent(true); diff --git a/tools/editor/editor_file_system.cpp b/tools/editor/editor_file_system.cpp index 673607706a..c7c1a48e34 100644 --- a/tools/editor/editor_file_system.cpp +++ b/tools/editor/editor_file_system.cpp @@ -37,6 +37,31 @@ EditorFileSystem *EditorFileSystem::singleton=NULL; +void EditorFileSystemDirectory::sort_files() { + + files.sort_custom<FileInfoSort>(); +} + +int EditorFileSystemDirectory::find_file_index(const String& p_file) const { + + for(int i=0;i<files.size();i++) { + if (files[i]->file==p_file) + return i; + } + return -1; + +} +int EditorFileSystemDirectory::find_dir_index(const String& p_dir) const{ + + + for(int i=0;i<subdirs.size();i++) { + if (subdirs[i]->name==p_dir) + return i; + } + + return -1; +} + int EditorFileSystemDirectory::get_subdir_count() const { @@ -59,7 +84,7 @@ String EditorFileSystemDirectory::get_file(int p_idx) const{ ERR_FAIL_INDEX_V(p_idx,files.size(),""); - return files[p_idx].file; + return files[p_idx]->file; } String EditorFileSystemDirectory::get_path() const { @@ -91,22 +116,22 @@ String EditorFileSystemDirectory::get_file_path(int p_idx) const { bool EditorFileSystemDirectory::get_file_meta(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,files.size(),""); - return files[p_idx].meta.enabled; + return files[p_idx]->meta.enabled; } Vector<String> EditorFileSystemDirectory::get_file_deps(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>()); - return files[p_idx].meta.deps; + return files[p_idx]->meta.deps; } Vector<String> EditorFileSystemDirectory::get_missing_sources(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>()); Vector<String> missing; - for(int i=0;i<files[p_idx].meta.sources.size();i++) { - if (files[p_idx].meta.sources[i].missing) - missing.push_back(files[p_idx].meta.sources[i].path); + for(int i=0;i<files[p_idx]->meta.sources.size();i++) { + if (files[p_idx]->meta.sources[i].missing) + missing.push_back(files[p_idx]->meta.sources[i].path); } return missing; @@ -116,8 +141,8 @@ Vector<String> EditorFileSystemDirectory::get_missing_sources(int p_idx) const { bool EditorFileSystemDirectory::is_missing_sources(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,files.size(),false); - for(int i=0;i<files[p_idx].meta.sources.size();i++) { - if (files[p_idx].meta.sources[i].missing) + for(int i=0;i<files[p_idx]->meta.sources.size();i++) { + if (files[p_idx]->meta.sources[i].missing) return true; } @@ -127,7 +152,7 @@ bool EditorFileSystemDirectory::is_missing_sources(int p_idx) const { StringName EditorFileSystemDirectory::get_file_type(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,files.size(),""); - return files[p_idx].type; + return files[p_idx]->type; } String EditorFileSystemDirectory::get_name() { @@ -157,11 +182,17 @@ void EditorFileSystemDirectory::_bind_methods() { EditorFileSystemDirectory::EditorFileSystemDirectory() { + modified_time=0; parent=NULL; } EditorFileSystemDirectory::~EditorFileSystemDirectory() { + for(int i=0;i<files.size();i++) { + + memdelete(files[i]); + } + for(int i=0;i<subdirs.size();i++) { memdelete(subdirs[i]); @@ -173,19 +204,6 @@ EditorFileSystemDirectory::~EditorFileSystemDirectory() { - - -EditorFileSystem::DirItem::~DirItem() { - - for(int i=0;i<dirs.size();i++) { - memdelete(dirs[i]); - } - - for(int i=0;i<files.size();i++) { - memdelete(files[i]); - } -} - EditorFileSystemDirectory::ImportMeta EditorFileSystem::_get_meta(const String& p_path) { Ref<ResourceImportMetadata> imd = ResourceLoader::load_import_metadata(p_path); @@ -214,160 +232,16 @@ EditorFileSystemDirectory::ImportMeta EditorFileSystem::_get_meta(const String& return m; } -EditorFileSystem::DirItem* EditorFileSystem::_scan_dir(DirAccess *da,Set<String> &extensions,String p_name,float p_from,float p_range,const String& p_path,HashMap<String,FileCache> &file_cache,HashMap<String,DirCache> &dir_cache,EditorProgressBG& p_prog) { - if (abort_scan) - return NULL; - - if (p_path!=String()) { - if (FileAccess::exists(("res://"+p_path).plus_file("engine.cfg"))) { - return NULL; - } - } - - List<String> dirs; - List<String> files; - Set<String> pngs; - - String path=p_path; - if (path.ends_with("/")) - path=path.substr(0,path.length()-1); - String global_path = Globals::get_singleton()->get_resource_path().plus_file(path); - - path="res://"+path; - uint64_t mtime = FileAccess::get_modified_time(global_path); - - DirCache *dc = dir_cache.getptr(path); - - - if (false && dc && dc->modification_time==mtime) { - //use the cached files, since directory did not change - for (Set<String>::Element *E=dc->subdirs.front();E;E=E->next()) { - dirs.push_back(E->get()); - } - for (Set<String>::Element *E=dc->files.front();E;E=E->next()) { - files.push_back(E->get()); - } - - } else { - //use the filesystem, some files may have changed - Error err = da->change_dir(global_path); - if (err!=OK) { - print_line("Can't change to: "+path); - ERR_FAIL_COND_V(err!=OK,NULL); - } +void EditorFileSystem::_scan_filesystem() { - - da->list_dir_begin(); - while (true) { - - bool isdir; - String f = da->get_next(&isdir); - if (f=="") - break; - if (isdir) { - dirs.push_back(f); - } else { - String ext = f.extension().to_lower(); - if (extensions.has(ext)) - files.push_back(f); - - } - - } - - da->list_dir_end(); - files.sort(); - dirs.sort(); - - } - - - - //print_line(da->get_current_dir()+": dirs: "+itos(dirs.size())+" files:"+itos(files.size()) ); - - //find subdirs - Vector<DirItem*> subdirs; - - //String current = da->get_current_dir(); - float idx=0; - for (List<String>::Element *E=dirs.front();E;E=E->next(),idx+=1.0) { - - String d = E->get(); - if (d.begins_with(".")) //ignore hidden and . / .. - continue; - - //ERR_CONTINUE( da->change_dir(d)!= OK ); - DirItem *sdi = _scan_dir(da,extensions,d,p_from+(idx/dirs.size())*p_range,p_range/dirs.size(),p_path+d+"/",file_cache,dir_cache,p_prog); - if (sdi) { - subdirs.push_back(sdi); - } - //da->change_dir(current); - } - - - if (subdirs.empty() && files.empty()) { - total=p_from+p_range; - p_prog.step(total*100); - return NULL; //give up, nothing to do here - } - - DirItem *di = memnew( DirItem ); - di->path=path; - di->name=p_name; - di->dirs=subdirs; - di->modified_time=mtime; - - //add files - for (List<String>::Element *E=files.front();E;E=E->next()) { - - SceneItem * si = memnew( SceneItem ); - si->file=E->get(); - si->path="res://"+p_path+si->file; - FileCache *fc = file_cache.getptr(si->path); - uint64_t mt = FileAccess::get_modified_time(si->path); - - if (fc && fc->modification_time == mt) { - - si->meta=fc->meta; - si->type=fc->type; - si->modified_time=fc->modification_time; - } else { - si->meta=_get_meta(si->path); - si->type=ResourceLoader::get_resource_type(si->path); - si->modified_time=mt; - - } - - if (si->meta.enabled) { - md_count++; - if (_check_meta_sources(si->meta)) { - sources_changed.push_back(si->path); - } - } - di->files.push_back(si); - } - - total=p_from+p_range; - p_prog.step(total*100); - - return di; -} - - -void EditorFileSystem::_scan_scenes() { - - ERR_FAIL_COND(!scanning || scandir); + ERR_FAIL_COND(!scanning || new_filesystem); //read .fscache - HashMap<String,FileCache> file_cache; - HashMap<String,DirCache> dir_cache; - DirCache *dc=NULL; String cpath; sources_changed.clear(); - - + file_cache.clear(); String project=Globals::get_singleton()->get_resource_path(); @@ -387,26 +261,7 @@ void EditorFileSystem::_scan_scenes() { ERR_CONTINUE( split.size() != 3); String name = split[1]; - dir_cache[name]=DirCache(); - dc=&dir_cache[name]; - dc->modification_time=split[2].to_int64(); - - if (name!="res://") { - - cpath=name+"/"; - - int sp=name.find_last("/"); - if (sp==5) - sp=6; - String pd = name.substr(0,sp); - DirCache *dcp = dir_cache.getptr(pd); - ERR_CONTINUE(!dcp); - dcp->subdirs.insert(name.get_file()); - } else { - - cpath=name; - } - + cpath=name; } else { Vector<String> split = l.split("::"); @@ -414,12 +269,8 @@ void EditorFileSystem::_scan_scenes() { String name = split[0]; String file; - if (!name.begins_with("res://")) { - file=name; - name=cpath+name; - } else { - file=name.get_file(); - } + file=name; + name=cpath.plus_file(name); FileCache fc; fc.type=split[1]; @@ -453,8 +304,6 @@ void EditorFileSystem::_scan_scenes() { file_cache[name]=fc; - ERR_CONTINUE(!dc); - dc->files.insert(file); } } @@ -465,39 +314,31 @@ void EditorFileSystem::_scan_scenes() { + EditorProgressBG scan_progress("efs","ScanFS",1000); + ScanProgress sp; + sp.low=0; + sp.hi=1; + sp.progress=&scan_progress; - total=0; - DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - //da->change_dir( Globals::get_singleton()->get_resource_path() ); + new_filesystem = memnew( EditorFileSystemDirectory ); + new_filesystem->parent=NULL; + DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES); + d->change_dir("res://"); + _scan_new_dir(new_filesystem,d,sp); - List<String> extensionsl; - ResourceLoader::get_recognized_extensions_for_type("",&extensionsl); - Set<String> extensions; - for(List<String>::Element *E = extensionsl.front();E;E=E->next()) { + file_cache.clear(); //clear caches, no longer needed - extensions.insert(E->get()); - } - - EditorProgressBG scan_progress("efs","ScanFS",100); - - md_count=0; - scandir=_scan_dir(da,extensions,"",0,1,"",file_cache,dir_cache,scan_progress); - memdelete(da); - if (abort_scan && scandir) { - memdelete(scandir); - scandir=NULL; - - } + memdelete(d); //save back the findings // String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("file_cache"); f=FileAccess::open(fscache,FileAccess::WRITE); - _save_type_cache_fs(scandir,f); + _save_filesystem_cache(new_filesystem,f); f->close(); memdelete(f); @@ -510,7 +351,95 @@ void EditorFileSystem::_scan_scenes() { void EditorFileSystem::_thread_func(void *_userdata) { EditorFileSystem *sd = (EditorFileSystem*)_userdata; - sd->_scan_scenes(); + sd->_scan_filesystem(); + +} + +bool EditorFileSystem::_update_scan_actions() { + + sources_changed.clear(); + + bool fs_changed=false; + + for (List<ItemAction>::Element *E=scan_actions.front();E;E=E->next()) { + + ItemAction&ia = E->get(); + + switch(ia.action) { + case ItemAction::ACTION_NONE: { + + } break; + case ItemAction::ACTION_DIR_ADD: { + + //print_line("*ACTION ADD DIR: "+ia.new_dir->get_name()); + int idx=0; + for(int i=0;i<ia.dir->subdirs.size();i++) { + + if (ia.new_dir->name<ia.dir->subdirs[i]->name) + break; + idx++; + } + if (idx==ia.dir->subdirs.size()) { + ia.dir->subdirs.push_back(ia.new_dir); + } else { + ia.dir->subdirs.insert(idx,ia.new_dir); + } + + fs_changed=true; + } break; + case ItemAction::ACTION_DIR_REMOVE: { + + ERR_CONTINUE(!ia.dir->parent); + //print_line("*ACTION REMOVE DIR: "+ia.dir->get_name()); + ia.dir->parent->subdirs.erase(ia.dir); + memdelete( ia.dir ); + fs_changed=true; + } break; + case ItemAction::ACTION_FILE_ADD: { + + int idx=0; + for(int i=0;i<ia.dir->files.size();i++) { + + if (ia.new_file->file<ia.dir->files[i]->file) + break; + idx++; + } + if (idx==ia.dir->files.size()) { + ia.dir->files.push_back(ia.new_file); + } else { + ia.dir->files.insert(idx,ia.new_file); + } + + fs_changed=true; + //print_line("*ACTION ADD FILE: "+ia.new_file->file); + + } break; + case ItemAction::ACTION_FILE_REMOVE: { + + int idx = ia.dir->find_file_index(ia.file); + ERR_CONTINUE(idx==-1); + memdelete( ia.dir->files[idx] ); + ia.dir->files.remove(idx); + + fs_changed=true; + //print_line("*ACTION REMOVE FILE: "+ia.file); + + } break; + case ItemAction::ACTION_FILE_SOURCES_CHANGED: { + + int idx = ia.dir->find_file_index(ia.file); + ERR_CONTINUE(idx==-1); + String full_path = ia.dir->get_file_path(idx); + sources_changed.push_back(full_path); + + } break; + + } + } + + scan_actions.clear(); + + return fs_changed; } @@ -526,19 +455,15 @@ void EditorFileSystem::scan() { abort_scan=false; if (!use_threads) { scanning=true; - _scan_scenes(); - if (rootdir) - memdelete(rootdir); - rootdir=scandir; + scan_total=0; + _scan_filesystem(); if (filesystem) memdelete(filesystem); // file_type_cache.clear(); - filesystem=_update_tree(rootdir); - - if (rootdir) - memdelete(rootdir); - rootdir=NULL; - scanning=false; + filesystem=new_filesystem; + new_filesystem=NULL; + _update_scan_actions(); + scanning=false; emit_signal("filesystem_changed"); emit_signal("sources_changed",sources_changed.size()>0); @@ -548,6 +473,7 @@ void EditorFileSystem::scan() { set_process(true); Thread::Settings s; scanning=true; + scan_total=0; s.priority=Thread::PRIORITY_LOW; thread = Thread::create(_thread_func,this,s); //tree->hide(); @@ -559,14 +485,10 @@ void EditorFileSystem::scan() { } -bool EditorFileSystem::_check_meta_sources(EditorFileSystemDirectory::ImportMeta & p_meta,EditorProgressBG *ep) { +bool EditorFileSystem::_check_meta_sources(EditorFileSystemDirectory::ImportMeta & p_meta) { if (p_meta.enabled) { - if (ep) { - ep->step(ss_amount++); - } - for(int j=0;j<p_meta.sources.size();j++) { @@ -584,9 +506,9 @@ bool EditorFileSystem::_check_meta_sources(EditorFileSystemDirectory::ImportMeta if (mt!=p_meta.sources[j].modified_time) { //scan String md5 = FileAccess::get_md5(src); - print_line("checking: "+src); - print_line("md5: "+md5); - print_line("vs: "+p_meta.sources[j].md5); + //print_line("checking: "+src); + //print_line("md5: "+md5); + //print_line("vs: "+p_meta.sources[j].md5); if (md5!=p_meta.sources[j].md5) { //really changed return true; @@ -599,18 +521,300 @@ bool EditorFileSystem::_check_meta_sources(EditorFileSystemDirectory::ImportMeta return false; } -void EditorFileSystem::_scan_sources(EditorFileSystemDirectory *p_dir,EditorProgressBG *ep) { +void EditorFileSystem::ScanProgress::update(int p_current,int p_total) const { + + float ratio = low + ((hi-low)/p_total)*p_current; + progress->step(ratio*1000); + EditorFileSystem::singleton->scan_total=ratio; +} + +EditorFileSystem::ScanProgress EditorFileSystem::ScanProgress::get_sub(int p_current,int p_total) const{ + + ScanProgress sp=*this; + float slice = (sp.hi-sp.low)/p_total; + sp.low+=slice*p_current; + sp.hi=slice; + return sp; + + +} + + +void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir,DirAccess *da,const ScanProgress& p_progress) { + + List<String> dirs; + List<String> files; + + String cd = da->get_current_dir(); + + p_dir->modified_time = FileAccess::get_modified_time(cd); + + + da->list_dir_begin(); + while (true) { + + bool isdir; + String f = da->get_next(&isdir); + if (f=="") + break; + + if (isdir) { + + if (f.begins_with(".")) //ignore hidden and . / .. + continue; + + if (FileAccess::exists(cd.plus_file(f).plus_file("engine.cfg"))) // skip if another project inside this + continue; + + dirs.push_back(f); + + } else { + + files.push_back(f); + } + + } + + da->list_dir_end(); + + dirs.sort(); + files.sort(); + + int total = dirs.size()+files.size(); + int idx=0; + + for (List<String>::Element *E=dirs.front();E;E=E->next(),idx++) { + + if (da->change_dir(E->get())==OK) { + + EditorFileSystemDirectory *efd = memnew( EditorFileSystemDirectory ); + + efd->parent=p_dir; + efd->name=E->get(); + + _scan_new_dir(efd,da,p_progress.get_sub(idx,total)); + + int idx=0; + for(int i=0;i<p_dir->subdirs.size();i++) { + + if (efd->name<p_dir->subdirs[i]->name) + break; + idx++; + } + if (idx==p_dir->subdirs.size()) { + p_dir->subdirs.push_back(efd); + } else { + p_dir->subdirs.insert(idx,efd); + } + + da->change_dir(".."); + } else { + ERR_PRINTS("Can't go into subdir: "+E->get()); + } + + p_progress.update(idx,total); + + } + + for (List<String>::Element*E=files.front();E;E=E->next(),idx++) { + + String ext = E->get().extension().to_lower(); + if (!valid_extensions.has(ext)) + continue; //invalid + + EditorFileSystemDirectory::FileInfo *fi = memnew( EditorFileSystemDirectory::FileInfo ); + fi->file=E->get(); + + String path = cd.plus_file(fi->file); + + FileCache *fc = file_cache.getptr(path); + uint64_t mt = FileAccess::get_modified_time(path); + + if (fc && fc->modification_time == mt) { + + fi->meta=fc->meta; + fi->type=fc->type; + fi->modified_time=fc->modification_time; + } else { + fi->meta=_get_meta(path); + fi->type=ResourceLoader::get_resource_type(path); + fi->modified_time=mt; + + } + + if (fi->meta.enabled) { + if (_check_meta_sources(fi->meta)) { + ItemAction ia; + ia.action=ItemAction::ACTION_FILE_SOURCES_CHANGED; + ia.dir=p_dir; + ia.file=E->get(); + scan_actions.push_back(ia); + } + } + + p_dir->files.push_back(fi); + p_progress.update(idx,total); + } + +} + + +void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir,const ScanProgress& p_progress) { + + uint64_t current_mtime = FileAccess::get_modified_time(p_dir->get_path()); + + bool updated_dir=false; + + //print_line("dir: "+p_dir->get_path()+" MODTIME: "+itos(p_dir->modified_time)+" CTIME: "+itos(current_mtime)); + + if (current_mtime!=p_dir->modified_time) { + + updated_dir=true; + p_dir->modified_time=current_mtime; + //ooooops, dir changed, see what's going on + + //first mark everything as veryfied + + for(int i=0;i<p_dir->files.size();i++) { + + p_dir->files[i]->verified=false; + } + + for(int i=0;i<p_dir->subdirs.size();i++) { + + p_dir->get_subdir(i)->verified=false; + } + + //then scan files and directories and check what's different + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + String cd = p_dir->get_path(); + da->change_dir(cd); + da->list_dir_begin(); + while (true) { + + bool isdir; + String f = da->get_next(&isdir); + if (f=="") + break; + + if (isdir) { + + if (f.begins_with(".")) //ignore hidden and . / .. + continue; + + int idx = p_dir->find_dir_index(f); + if (idx==-1) { + + if (FileAccess::exists(cd.plus_file(f).plus_file("engine.cfg"))) // skip if another project inside this + continue; + + EditorFileSystemDirectory *efd = memnew( EditorFileSystemDirectory ); + + efd->parent=p_dir; + efd->name=f; + DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES); + d->change_dir(cd.plus_file(f)); + _scan_new_dir(efd,d,p_progress.get_sub(1,1)); + memdelete(d); + + + ItemAction ia; + ia.action=ItemAction::ACTION_DIR_ADD; + ia.dir=p_dir; + ia.file=f; + ia.new_dir=efd; + scan_actions.push_back(ia); + } else { + p_dir->subdirs[idx]->verified=true; + } + + + } else { + String ext = f.extension().to_lower(); + if (!valid_extensions.has(ext)) + continue; //invalid + + int idx = p_dir->find_file_index(f); + + if (idx==-1) { + //never seen this file, add actition to add it + EditorFileSystemDirectory::FileInfo *fi = memnew( EditorFileSystemDirectory::FileInfo ); + fi->file=f; + + String path = cd.plus_file(fi->file); + fi->modified_time=FileAccess::get_modified_time(path); + fi->meta=_get_meta(path); + fi->type=ResourceLoader::get_resource_type(path); + + { + ItemAction ia; + ia.action=ItemAction::ACTION_FILE_ADD; + ia.dir=p_dir; + ia.file=f; + ia.new_file=fi; + scan_actions.push_back(ia); + } + + //take the chance and scan sources + if (_check_meta_sources(fi->meta)) { + + ItemAction ia; + ia.action=ItemAction::ACTION_FILE_SOURCES_CHANGED; + ia.dir=p_dir; + ia.file=f; + scan_actions.push_back(ia); + } + + } else { + p_dir->files[idx]->verified=true; + } + + + } + + } + da->list_dir_end(); + memdelete(da); + + + + + } for(int i=0;i<p_dir->files.size();i++) { - if (_check_meta_sources(p_dir->files[i].meta,ep)) { - sources_changed.push_back(p_dir->get_file_path(i)); + if (updated_dir && !p_dir->files[i]->verified) { + //this file was removed, add action to remove it + ItemAction ia; + ia.action=ItemAction::ACTION_FILE_REMOVE; + ia.dir=p_dir; + ia.file=p_dir->files[i]->file; + scan_actions.push_back(ia); + continue; + + } + if (_check_meta_sources(p_dir->files[i]->meta)) { + ItemAction ia; + ia.action=ItemAction::ACTION_FILE_SOURCES_CHANGED; + ia.dir=p_dir; + ia.file=p_dir->files[i]->file; + scan_actions.push_back(ia); } } for(int i=0;i<p_dir->subdirs.size();i++) { - _scan_sources(p_dir->get_subdir(i),ep); + if (updated_dir && !p_dir->subdirs[i]->verified) { + //this directory was removed, add action to remove it + ItemAction ia; + ia.action=ItemAction::ACTION_DIR_REMOVE; + ia.dir=p_dir->subdirs[i]; + scan_actions.push_back(ia); + continue; + + } + _scan_fs_changes(p_dir->get_subdir(i),p_progress); } } @@ -619,9 +823,12 @@ void EditorFileSystem::_thread_func_sources(void *_userdata) { EditorFileSystem *efs = (EditorFileSystem*)_userdata; if (efs->filesystem) { - EditorProgressBG pr("sources","ScanSources",efs->md_count); - efs->ss_amount=0; - efs->_scan_sources(efs->filesystem,&pr); + EditorProgressBG pr("sources","ScanSources",1000); + ScanProgress sp; + sp.progress=≺ + sp.hi=1; + sp.low=0; + efs->_scan_fs_changes(efs->filesystem,sp); } efs->scanning_sources_done=true; } @@ -643,8 +850,17 @@ void EditorFileSystem::scan_sources() { abort_scan=false; if (!use_threads) { - if (filesystem) - _scan_sources(filesystem,NULL); + if (filesystem) { + EditorProgressBG pr("sources","ScanSources",1000); + ScanProgress sp; + sp.progress=≺ + sp.hi=1; + sp.low=0; + scan_total=0; + _scan_fs_changes(filesystem,sp); + if (_update_scan_actions()) + emit_signal("filesystem_changed"); + } scanning_sources=false; scanning_sources_done=true; emit_signal("sources_changed",sources_changed.size()>0); @@ -652,8 +868,8 @@ void EditorFileSystem::scan_sources() { ERR_FAIL_COND(thread_sources); set_process(true); + scan_total=0; Thread::Settings s; - ss_amount=0; s.priority=Thread::PRIORITY_LOW; thread_sources = Thread::create(_thread_func_sources,this,s); //tree->hide(); @@ -665,53 +881,14 @@ void EditorFileSystem::scan_sources() { } -EditorFileSystemDirectory* EditorFileSystem::_update_tree(DirItem *p_item) { - - EditorFileSystemDirectory *efd = memnew( EditorFileSystemDirectory ); - - if (!p_item) - return efd; //empty likely - efd->name=p_item->name; - - for(int i=0;i<p_item->files.size();i++) { - - String s = p_item->files[i]->type; - //if (p_item->files[i]->meta) - // s="*"+s; - -// file_type_cache[p_item->files[i]->path]=s; - if (p_item->files[i]->type=="") - continue; //ignore because it's invalid - EditorFileSystemDirectory::FileInfo fi; - fi.file=p_item->files[i]->file; - fi.type=p_item->files[i]->type; - fi.meta=p_item->files[i]->meta; - fi.modified_time=p_item->files[i]->modified_time; - - efd->files.push_back(fi); - - } - - for(int i=0;i<p_item->dirs.size();i++) { - - EditorFileSystemDirectory *efsd =_update_tree(p_item->dirs[i]); - efsd->parent=efd; - efd->subdirs.push_back( efsd ); - - } - - - return efd; -} - void EditorFileSystem::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_TREE: { - _load_type_cache(); - scan(); + + scan(); } break; case NOTIFICATION_EXIT_TREE: { if (use_threads && thread) { @@ -727,13 +904,13 @@ void EditorFileSystem::_notification(int p_what) { set_process(false); } - if (rootdir) - memdelete(rootdir); - rootdir=NULL; if (filesystem) memdelete(filesystem); + if (new_filesystem) + memdelete(new_filesystem); filesystem=NULL; + new_filesystem=NULL; } break; case NOTIFICATION_PROCESS: { @@ -751,6 +928,8 @@ void EditorFileSystem::_notification(int p_what) { Thread::wait_to_finish(thread_sources); memdelete(thread_sources); thread_sources=NULL; + if (_update_scan_actions()) + emit_signal("filesystem_changed"); //print_line("sources changed: "+itos(sources_changed.size())); emit_signal("sources_changed",sources_changed.size()>0); } @@ -758,21 +937,14 @@ void EditorFileSystem::_notification(int p_what) { set_process(false); - if (rootdir) - memdelete(rootdir); if (filesystem) memdelete(filesystem); - rootdir=scandir; - scandir=NULL; -// file_type_cache.clear(); - filesystem=_update_tree(rootdir); - - if (rootdir) - memdelete(rootdir); - rootdir=NULL; + filesystem=new_filesystem; + new_filesystem=NULL; Thread::wait_to_finish(thread); memdelete(thread); thread=NULL; + _update_scan_actions(); emit_signal("filesystem_changed"); emit_signal("sources_changed",sources_changed.size()>0); //print_line("initial sources changed: "+itos(sources_changed.size())); @@ -794,7 +966,7 @@ bool EditorFileSystem::is_scanning() const { } float EditorFileSystem::get_scanning_progress() const { - return total; + return scan_total; } EditorFileSystemDirectory *EditorFileSystem::get_filesystem() { @@ -802,12 +974,12 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem() { return filesystem; } -void EditorFileSystem::_save_type_cache_fs(DirItem *p_dir,FileAccess *p_file) { +void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory*p_dir,FileAccess *p_file) { if (!p_dir) return; //none - p_file->store_line("::"+p_dir->path+"::"+String::num(p_dir->modified_time)); + p_file->store_line("::"+p_dir->get_path()+"::"+String::num(p_dir->modified_time)); for(int i=0;i<p_dir->files.size();i++) { @@ -832,126 +1004,96 @@ void EditorFileSystem::_save_type_cache_fs(DirItem *p_dir,FileAccess *p_file) { p_file->store_line(s); } - for(int i=0;i<p_dir->dirs.size();i++) { + for(int i=0;i<p_dir->subdirs.size();i++) { - _save_type_cache_fs(p_dir->dirs[i],p_file); + _save_filesystem_cache(p_dir->subdirs[i],p_file); } } -void EditorFileSystem::_load_type_cache(){ - - GLOBAL_LOCK_FUNCTION - - -#if 0 - //this is not good, removed for now as it interferes with metadata stored in files - - String project=Globals::get_singleton()->get_resource_path(); - FileAccess *f =FileAccess::open(project+"/types.cache",FileAccess::READ); - - if (!f) { - - WARN_PRINT("Can't open types.cache."); - return; - } - - file_type_cache.clear(); - while(!f->eof_reached()) { - - String path=f->get_line(); - if (f->eof_reached()) - break; - String type=f->get_line(); - file_type_cache[path]=type; - } - - memdelete(f); -#endif -} bool EditorFileSystem::_find_file(const String& p_file,EditorFileSystemDirectory ** r_d, int &r_file_pos) const { //todo make faster - if (!filesystem || scanning) - return false; + if (!filesystem || scanning) + return false; - String f = Globals::get_singleton()->localize_path(p_file); + String f = Globals::get_singleton()->localize_path(p_file); - if (!f.begins_with("res://")) - return false; - f=f.substr(6,f.length()); - f=f.replace("\\","/"); + if (!f.begins_with("res://")) + return false; + f=f.substr(6,f.length()); + f=f.replace("\\","/"); - Vector<String> path = f.split("/"); + Vector<String> path = f.split("/"); - if (path.size()==0) - return false; - String file=path[path.size()-1]; - path.resize(path.size()-1); + if (path.size()==0) + return false; + String file=path[path.size()-1]; + path.resize(path.size()-1); - EditorFileSystemDirectory *fs=filesystem; + EditorFileSystemDirectory *fs=filesystem; - for(int i=0;i<path.size();i++) { + for(int i=0;i<path.size();i++) { - int idx=-1; - for(int j=0;j<fs->get_subdir_count();j++) { + int idx=-1; + for(int j=0;j<fs->get_subdir_count();j++) { - if (fs->get_subdir(j)->get_name()==path[i]) { - idx=j; - break; - } - } + if (fs->get_subdir(j)->get_name()==path[i]) { + idx=j; + break; + } + } - if (idx==-1) { - //does not exist, create i guess? - EditorFileSystemDirectory *efsd = memnew( EditorFileSystemDirectory ); - efsd->name=path[i]; - int idx2=0; - for(int j=0;j<fs->get_subdir_count();j++) { + if (idx==-1) { + //does not exist, create i guess? + EditorFileSystemDirectory *efsd = memnew( EditorFileSystemDirectory ); + efsd->name=path[i]; + int idx2=0; + for(int j=0;j<fs->get_subdir_count();j++) { - if (efsd->name<fs->get_subdir(j)->get_name()) - break; - idx2++; - } + if (efsd->name<fs->get_subdir(j)->get_name()) + break; + idx2++; + } - if (idx2==fs->get_subdir_count()) - fs->subdirs.push_back(efsd); - else - fs->subdirs.insert(idx2,efsd); - fs=efsd; - } else { + if (idx2==fs->get_subdir_count()) + fs->subdirs.push_back(efsd); + else + fs->subdirs.insert(idx2,efsd); + fs=efsd; + } else { - fs=fs->get_subdir(idx); + fs=fs->get_subdir(idx); + } } - } - int cpos=-1; - for(int i=0;i<fs->files.size();i++) { + int cpos=-1; + for(int i=0;i<fs->files.size();i++) { - if (fs->files[i].file==file) { - cpos=i; - break; + if (fs->files[i]->file==file) { + cpos=i; + break; + } } - } r_file_pos=cpos; *r_d=fs; - if (cpos!=-1) { + if (cpos!=-1) { - return true; - } else { + return true; + } else { - return false; - } + return false; + } } @@ -967,7 +1109,7 @@ String EditorFileSystem::get_file_type(const String& p_file) const { } - return fs->files[cpos].type; + return fs->files[cpos]->type; } @@ -1024,16 +1166,16 @@ EditorFileSystemDirectory *EditorFileSystem::get_path(const String& p_path) { void EditorFileSystem::_resource_saved(const String& p_path){ - print_line("resource saved: "+p_path); + //print_line("resource saved: "+p_path); EditorFileSystem::get_singleton()->update_file(p_path); } String EditorFileSystem::_find_first_from_source(EditorFileSystemDirectory* p_dir,const String &p_src) const { for(int i=0;i<p_dir->files.size();i++) { - for(int j=0;j<p_dir->files[i].meta.sources.size();j++) { + for(int j=0;j<p_dir->files[i]->meta.sources.size();j++) { - if (p_dir->files[i].meta.sources[j].path==p_src) + if (p_dir->files[i]->meta.sources[j].path==p_src) return p_dir->get_file_path(i); } } @@ -1070,6 +1212,7 @@ void EditorFileSystem::update_file(const String& p_file) { if (!FileAccess::exists(p_file)) { //was removed + memdelete( fs->files[cpos] ); fs->files.remove(cpos); call_deferred("emit_signal","filesystem_changed"); //update later return; @@ -1083,13 +1226,13 @@ void EditorFileSystem::update_file(const String& p_file) { int idx=0; for(int i=0;i<fs->files.size();i++) { - if (p_file<fs->files[i].file) + if (p_file<fs->files[i]->file) break; idx++; } - EditorFileSystemDirectory::FileInfo fi; - fi.file=p_file.get_file(); + EditorFileSystemDirectory::FileInfo *fi = memnew( EditorFileSystemDirectory::FileInfo ); + fi->file=p_file.get_file(); if (idx==fs->files.size()) { fs->files.push_back(fi); @@ -1102,10 +1245,10 @@ void EditorFileSystem::update_file(const String& p_file) { } - print_line("UPDATING: "+p_file); - fs->files[cpos].type=type; - fs->files[cpos].modified_time=FileAccess::get_modified_time(p_file); - fs->files[cpos].meta=_get_meta(p_file); + //print_line("UPDATING: "+p_file); + fs->files[cpos]->type=type; + fs->files[cpos]->modified_time=FileAccess::get_modified_time(p_file); + fs->files[cpos]->meta=_get_meta(p_file); call_deferred("emit_signal","filesystem_changed"); //update later @@ -1128,15 +1271,22 @@ EditorFileSystem::EditorFileSystem() { thread = NULL; scanning=false; - scandir=NULL; - rootdir=NULL; use_threads=true; thread_sources=NULL; + new_filesystem=NULL; scanning_sources=false; ResourceSaver::set_save_callback(_resource_saved); + List<String> extensionsl; + ResourceLoader::get_recognized_extensions_for_type("",&extensionsl); + for(List<String>::Element *E = extensionsl.front();E;E=E->next()) { + + valid_extensions.insert(E->get()); + } + + scan_total=0; } EditorFileSystem::~EditorFileSystem() { diff --git a/tools/editor/editor_file_system.h b/tools/editor/editor_file_system.h index 0db2dc150e..d11fa0cfb1 100644 --- a/tools/editor/editor_file_system.h +++ b/tools/editor/editor_file_system.h @@ -42,6 +42,8 @@ class EditorFileSystemDirectory : public Object { OBJ_TYPE( EditorFileSystemDirectory,Object ); String name; + uint64_t modified_time; + bool verified; //used for checking changes EditorFileSystemDirectory *parent; Vector<EditorFileSystemDirectory*> subdirs; @@ -68,11 +70,20 @@ class EditorFileSystemDirectory : public Object { String file; StringName type; uint64_t modified_time; - ImportMeta meta; + bool verified; //used for checking changes + + }; + + struct FileInfoSort { + bool operator()(const FileInfo *p_a,const FileInfo *p_b) const { + return p_a->file<p_b->file; + } }; - Vector<FileInfo> files; + void sort_files(); + + Vector<FileInfo*> files; static void _bind_methods(); @@ -96,6 +107,9 @@ public: EditorFileSystemDirectory *get_parent(); + int find_file_index(const String& p_file) const; + int find_dir_index(const String& p_dir) const; + EditorFileSystemDirectory(); ~EditorFileSystemDirectory(); @@ -107,45 +121,47 @@ class EditorFileSystem : public Node { _THREAD_SAFE_CLASS_ - struct SceneItem { + + struct ItemAction { + + enum Action { + ACTION_NONE, + ACTION_DIR_ADD, + ACTION_DIR_REMOVE, + ACTION_FILE_ADD, + ACTION_FILE_REMOVE, + ACTION_FILE_SOURCES_CHANGED + }; + + Action action; + EditorFileSystemDirectory *dir; String file; - String path; - String type; - uint64_t modified_time; - EditorFileSystemDirectory::ImportMeta meta; - }; + EditorFileSystemDirectory *new_dir; + EditorFileSystemDirectory::FileInfo *new_file; - struct DirItem { + ItemAction() { action=ACTION_NONE; dir=NULL; new_dir=NULL; new_file=NULL; } - uint64_t modified_time; - String path; - String name; - Vector<DirItem*> dirs; - Vector<SceneItem*> files; - ~DirItem(); }; - float total; bool use_threads; Thread *thread; static void _thread_func(void *_userdata); - DirItem *scandir; - DirItem *rootdir; + EditorFileSystemDirectory *new_filesystem; bool abort_scan; bool scanning; + float scan_total; - EditorFileSystemDirectory* _update_tree(DirItem *p_item); - void _scan_scenes(); - void _load_type_cache(); + void _scan_filesystem(); EditorFileSystemDirectory *filesystem; static EditorFileSystem *singleton; + /* Used for reading the filesystem cache file */ struct FileCache { String type; @@ -154,34 +170,43 @@ class EditorFileSystem : public Node { Vector<String> deps; }; - struct DirCache { + HashMap<String,FileCache> file_cache; - uint64_t modification_time; - Set<String> files; - Set<String> subdirs; - }; + struct ScanProgress { + float low; + float hi; + mutable EditorProgressBG *progress; + void update(int p_current,int p_total) const; + ScanProgress get_sub(int p_current,int p_total) const; + }; static EditorFileSystemDirectory::ImportMeta _get_meta(const String& p_path); - bool _check_meta_sources(EditorFileSystemDirectory::ImportMeta & p_meta,EditorProgressBG *ep=NULL); + bool _check_meta_sources(EditorFileSystemDirectory::ImportMeta & p_meta); - DirItem* _scan_dir(DirAccess *da,Set<String> &extensions,String p_name,float p_from,float p_range,const String& p_path,HashMap<String,FileCache> &file_cache,HashMap<String,DirCache> &dir_cache,EditorProgressBG& p_prog); - void _save_type_cache_fs(DirItem *p_dir,FileAccess *p_file); + void _save_filesystem_cache(EditorFileSystemDirectory *p_dir,FileAccess *p_file); bool _find_file(const String& p_file,EditorFileSystemDirectory ** r_d, int &r_file_pos) const; - void _scan_sources(EditorFileSystemDirectory *p_dir,EditorProgressBG *ep); + void _scan_fs_changes(EditorFileSystemDirectory *p_dir, const ScanProgress &p_progress); int md_count; + Set<String> valid_extensions; + + void _scan_new_dir(EditorFileSystemDirectory *p_dir,DirAccess *da,const ScanProgress& p_progress); Thread *thread_sources; bool scanning_sources; bool scanning_sources_done; - int ss_amount; + static void _thread_func_sources(void *_userdata); + List<String> sources_changed; + List<ItemAction> scan_actions; + + bool _update_scan_actions(); static void _resource_saved(const String& p_path); String _find_first_from_source(EditorFileSystemDirectory* p_dir,const String &p_src) const; diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 9151e63df6..bdfab50e15 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -415,7 +415,7 @@ void EditorNode::_rebuild_import_menu() { PopupMenu* p = import_menu->get_popup(); p->clear(); - p->add_item("Sub-Scene", FILE_IMPORT_SUBSCENE); + p->add_item("Node from scene", FILE_IMPORT_SUBSCENE); p->add_separator(); for (int i = 0; i < editor_import_export->get_import_plugin_count(); i++) { p->add_item(editor_import_export->get_import_plugin(i)->get_visible_name(), IMPORT_PLUGIN_BASE + i); @@ -5953,6 +5953,7 @@ EditorNode::EditorNode() { resource_preview->add_preview_generator( Ref<EditorScriptPreviewPlugin>( memnew(EditorScriptPreviewPlugin ))); resource_preview->add_preview_generator( Ref<EditorSamplePreviewPlugin>( memnew(EditorSamplePreviewPlugin ))); resource_preview->add_preview_generator( Ref<EditorMeshPreviewPlugin>( memnew(EditorMeshPreviewPlugin ))); + resource_preview->add_preview_generator( Ref<EditorBitmapPreviewPlugin>( memnew(EditorBitmapPreviewPlugin ))); circle_step_msec=OS::get_singleton()->get_ticks_msec(); circle_step_frame=OS::get_singleton()->get_frames_drawn(); diff --git a/tools/editor/io_plugins/editor_font_import_plugin.cpp b/tools/editor/io_plugins/editor_font_import_plugin.cpp index 7bb2b5b77d..9b4ca246e7 100644 --- a/tools/editor/io_plugins/editor_font_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_font_import_plugin.cpp @@ -621,6 +621,7 @@ public: source->get_file_dialog()->set_mode(EditorFileDialog::MODE_OPEN_FILE); source->get_file_dialog()->add_filter("*.ttf;TrueType"); source->get_file_dialog()->add_filter("*.otf;OpenType"); + source->get_file_dialog()->add_filter("*.fnt;BMFont"); source->get_line_edit()->connect("text_entered",this,"_src_changed"); vbl->add_margin_child("Source Font:",source); @@ -876,10 +877,31 @@ static unsigned char get_SDF_radial( Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata>& p_from, const String &p_existing) { + + Ref<ResourceImportMetadata> from = p_from; ERR_FAIL_COND_V(from->get_source_count()!=1,Ref<Font>()); String src_path = EditorImportPlugin::expand_source_path(from->get_source_path(0)); + + if (src_path.extension().to_lower()=="fnt") { + + if (ResourceLoader::load(src_path).is_valid()) { + EditorNode::get_singleton()->show_warning("Path: "+src_path+"\nIs a Godot font file, please supply a BMFont type file instead."); + return Ref<Font>(); + } + + Ref<Font> font; + font.instance(); + Error err = font->create_from_fnt(src_path); + if (err) { + EditorNode::get_singleton()->show_warning("Path: "+src_path+"\nFailed opening as BMFont file."); + return Ref<Font>(); + } + + return font; + } + int size = from->get_option("font/size"); #ifdef FREETYPE_ENABLED diff --git a/tools/editor/plugins/editor_preview_plugins.cpp b/tools/editor/plugins/editor_preview_plugins.cpp index 5f52d4c3e7..a0ce294219 100644 --- a/tools/editor/plugins/editor_preview_plugins.cpp +++ b/tools/editor/plugins/editor_preview_plugins.cpp @@ -6,6 +6,7 @@ #include "scene/resources/material.h" #include "scene/resources/sample.h" #include "scene/resources/mesh.h" +#include "scene/resources/bit_mask.h" bool EditorTexturePreviewPlugin::handles(const String& p_type) const { @@ -58,6 +59,81 @@ EditorTexturePreviewPlugin::EditorTexturePreviewPlugin() { } +//////////////////////////////////////////////////////////////////////////// + +bool EditorBitmapPreviewPlugin::handles(const String& p_type) const { + + return ObjectTypeDB::is_type(p_type,"BitMap"); +} + +Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES& p_from) { + + Ref<BitMap> bm =p_from; + + if (bm->get_size()==Size2()) { + return Ref<Texture>(); + } + + DVector<uint8_t> data; + + data.resize(bm->get_size().width*bm->get_size().height); + + { + DVector<uint8_t>::Write w=data.write(); + + for(int i=0;i<bm->get_size().width;i++) { + for(int j=0;j<bm->get_size().height;j++) { + if (bm->get_bit(Point2i(i,j))) { + w[j*bm->get_size().width+i]=255; + } else { + w[j*bm->get_size().width+i]=0; + + } + } + + } + } + + + Image img(bm->get_size().width,bm->get_size().height,0,Image::FORMAT_GRAYSCALE,data); + + int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size"); + if (img.is_compressed()) { + if (img.decompress()!=OK) + return Ref<Texture>(); + } else if (img.get_format()!=Image::FORMAT_RGB && img.get_format()!=Image::FORMAT_RGBA) { + img.convert(Image::FORMAT_RGBA); + } + + int width,height; + if (img.get_width() > thumbnail_size && img.get_width() >= img.get_height()) { + + width=thumbnail_size; + height = img.get_height() * thumbnail_size / img.get_width(); + } else if (img.get_height() > thumbnail_size && img.get_height() >= img.get_width()) { + + height=thumbnail_size; + width = img.get_width() * thumbnail_size / img.get_height(); + } else { + + width=img.get_width(); + height=img.get_height(); + } + + img.resize(width,height); + + Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture )); + + ptex->create_from_image(img,0); + return ptex; + +} + +EditorBitmapPreviewPlugin::EditorBitmapPreviewPlugin() { + + +} + /////////////////////////////////////////////////////////////////////////// diff --git a/tools/editor/plugins/editor_preview_plugins.h b/tools/editor/plugins/editor_preview_plugins.h index 98071e2a0e..b3bfda8045 100644 --- a/tools/editor/plugins/editor_preview_plugins.h +++ b/tools/editor/plugins/editor_preview_plugins.h @@ -13,6 +13,17 @@ public: }; +class EditorBitmapPreviewPlugin : public EditorResourcePreviewGenerator { +public: + + virtual bool handles(const String& p_type) const; + virtual Ref<Texture> generate(const RES& p_from); + + EditorBitmapPreviewPlugin(); +}; + + + class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator { Ref<Texture> _gen_from_imd(Ref<ResourceImportMetadata> p_imd); diff --git a/tools/editor/plugins/path_2d_editor_plugin.cpp b/tools/editor/plugins/path_2d_editor_plugin.cpp index a2cc0ed09c..509edbe5f8 100644 --- a/tools/editor/plugins/path_2d_editor_plugin.cpp +++ b/tools/editor/plugins/path_2d_editor_plugin.cpp @@ -534,6 +534,7 @@ void Path2DEditor::edit(Node *p_path2d) { if (!node->is_connected("visibility_changed", this, "_node_visibility_changed")) node->connect("visibility_changed", this, "_node_visibility_changed"); + } else { if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw")) @@ -614,6 +615,7 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) { editor=p_editor; undo_redo = editor->get_undo_redo(); + mode=MODE_EDIT; action=ACTION_NONE; #if 0 diff --git a/tools/editor/plugins/polygon_2d_editor_plugin.cpp b/tools/editor/plugins/polygon_2d_editor_plugin.cpp index fc71a64dbd..3e9c58d604 100644 --- a/tools/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/tools/editor/plugins/polygon_2d_editor_plugin.cpp @@ -755,7 +755,6 @@ void Polygon2DEditor::edit(Node *p_collision_polygon) { canvas_item_editor=CanvasItemEditor::get_singleton(); } - if (p_collision_polygon) { node=p_collision_polygon->cast_to<Polygon2D>(); diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index f536077f9a..8903e12319 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -1617,6 +1617,8 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { case InputEvent::KEY: { const InputEventKey &k = p_event.key; + if (!k.pressed) + break; switch(k.scancode) { case KEY_S: { @@ -1677,7 +1679,8 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { } break; case KEY_KP_5: { - orthogonal = !orthogonal; + + //orthogonal = !orthogonal; _menu_option(orthogonal?VIEW_PERSPECTIVE:VIEW_ORTHOGONAL); _update_name(); diff --git a/tools/editor/plugins/sprite_frames_editor_plugin.cpp b/tools/editor/plugins/sprite_frames_editor_plugin.cpp index 306c69533a..048df2d682 100644 --- a/tools/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/tools/editor/plugins/sprite_frames_editor_plugin.cpp @@ -345,7 +345,7 @@ void SpriteFramesEditor::_update_library() { ti->set_text(0,"Frame "+itos(i)+" (empty)"); } else { - ti->set_text(0,"Frame "+itos(i)); + ti->set_text(0,"Frame "+itos(i)+" ("+frames->get_frame(i)->get_name()+")"); ti->set_icon(0,frames->get_frame(i)); } if (frames->get_frame(i).is_valid()) diff --git a/tools/editor/project_settings.cpp b/tools/editor/project_settings.cpp index 09d2e4bd01..b61fcfa780 100644 --- a/tools/editor/project_settings.cpp +++ b/tools/editor/project_settings.cpp @@ -107,6 +107,8 @@ void ProjectSettings::_action_persist_toggle() { String name="input/"+ti->get_text(0); bool prev = Globals::get_singleton()->is_persisting(name); + print_line("prev persist: "+itos(prev)); + print_line("new persist: "+itos(ti->is_checked(0))); if (prev==ti->is_checked(0)) return; @@ -156,12 +158,14 @@ void ProjectSettings::_device_input_add() { } break; case InputEvent::JOYSTICK_MOTION: { - ie.joy_motion.axis = device_index->get_selected(); + ie.joy_motion.axis = device_index->get_selected()>>1; + ie.joy_motion.axis_value = device_index->get_selected()&1?1:-1; + for(int i=0;i<arr.size();i++) { InputEvent aie=arr[i]; - if (aie.device == ie.device && aie.type==InputEvent::JOYSTICK_MOTION && aie.joy_motion.axis==ie.joy_motion.axis) { + if (aie.device == ie.device && aie.type==InputEvent::JOYSTICK_MOTION && aie.joy_motion.axis==ie.joy_motion.axis && aie.joy_motion.axis_value==ie.joy_motion.axis_value) { return; } } @@ -295,9 +299,10 @@ void ProjectSettings::_add_item(int p_item){ device_id->set_val(0); device_index_label->set_text("Joy Button Axis:"); device_index->clear(); - for(int i=0;i<8;i++) { + for(int i=0;i<24;i++) { + - device_index->add_item("Axis "+itos(i)); + device_index->add_item("Axis "+itos(i/2)+" "+(i&1?"+":"-")); } device_input->popup_centered(Size2(350,95)); @@ -425,7 +430,7 @@ void ProjectSettings::_update_actions() { continue; TreeItem *item=input_editor->create_item(root); - item->set_cell_mode(0,TreeItem::CELL_MODE_CHECK); + //item->set_cell_mode(0,TreeItem::CELL_MODE_CHECK); item->set_text(0,name); item->add_button(0,get_icon("Add","EditorIcons"),1); if (!Globals::get_singleton()->get_input_presets().find(pi.name)) { @@ -434,7 +439,7 @@ void ProjectSettings::_update_actions() { } item->set_custom_bg_color(0,get_color("prop_subsection","Editor")); item->set_editable(0,true); - item->set_checked(0,pi.usage&PROPERTY_USAGE_CHECKED); + //item->set_checked(0,pi.usage&PROPERTY_USAGE_CHECKED); @@ -494,7 +499,7 @@ void ProjectSettings::_update_actions() { } break; case InputEvent::JOYSTICK_MOTION: { - String str = "Device "+itos(ie.device)+", Axis "+itos(ie.joy_motion.axis)+"."; + String str = "Device "+itos(ie.device)+", Axis "+itos(ie.joy_motion.axis)+" "+(ie.joy_motion.axis_value<0?"-.":"+."); action->set_text(0,str); action->set_icon(0,get_icon("JoyAxis","EditorIcons")); } break; @@ -696,9 +701,20 @@ void ProjectSettings::_save() { void ProjectSettings::_settings_prop_edited(const String& p_name) { - if (!Globals::get_singleton()->is_persisting(p_name)) { - String full_item = globals_editor->get_full_item_path(p_name); + String full_item = globals_editor->get_full_item_path(p_name); + + if (!Globals::get_singleton()->is_persisting(full_item)) { Globals::get_singleton()->set_persisting(full_item,true); + + { + //small usability workaround, if anything related to resolution scaling or size is modified, change all of them together + if (full_item=="display/width" || full_item=="display/height" || full_item=="display/stretch_mode") { + Globals::get_singleton()->set_persisting("display/height",true); + Globals::get_singleton()->set_persisting("display/width",true); + } + } + + // globals_editor->update_property(p_name); globals_editor->get_property_editor()->update_tree(); } diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index 6b56f2adf0..fc5fce1d47 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -927,6 +927,7 @@ void CustomPropertyEditor::_node_path_selected(NodePath p_path) { if (!node) { v=p_path; emit_signal("variant_changed"); + call_deferred("hide"); //to not mess with dialogs return; } @@ -938,6 +939,7 @@ void CustomPropertyEditor::_node_path_selected(NodePath p_path) { v=p_path; emit_signal("variant_changed"); + call_deferred("hide"); //to not mess with dialogs } @@ -1040,6 +1042,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) { v=NodePath(); emit_signal("variant_changed"); + hide(); } } break; case Variant::OBJECT: { @@ -2110,6 +2113,65 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p } +void PropertyEditor::_check_reload_status(const String&p_name, TreeItem* item) { + + bool has_reload=false; + int found=-1; + + for(int i=0;i<item->get_button_count(1);i++) { + + if (item->get_button_id(1,i)==3) { + found=i; + break; + } + } + + if (_might_be_in_instance()) { + + + Variant vorig; + Dictionary d=item->get_metadata(0); + int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0; + + + if (_get_instanced_node_original_property(p_name,vorig) || usage) { + Variant v = obj->get(p_name); + + bool changed = _is_property_different(v,vorig,usage); + + if ((found!=-1)!=changed) { + + if (changed) { + + has_reload=true; + } else { + + } + + } + + } + + + + } + + if (!has_reload && !obj->get_script().is_null()) { + Ref<Script> scr = obj->get_script(); + Variant orig_value; + if (scr->get_property_default_value(p_name,orig_value)) { + if (orig_value!=obj->get(p_name)) { + has_reload=true; + } + } + } + + if (found!=-1 && !has_reload) { + item->erase_button(1,found); + } else if (found==-1 && has_reload) { + item->add_button(1,get_icon("Reload","EditorIcons"),3); + } +} void PropertyEditor::_notification(int p_what) { @@ -2151,43 +2213,8 @@ void PropertyEditor::_notification(int p_what) { if (!item) continue; - 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); - - int found=-1; - for(int i=0;i<item->get_button_count(1);i++) { - - if (item->get_button_id(1,i)==3) { - found=i; - break; - } - } - - bool changed = _is_property_different(v,vorig,usage); - - if ((found!=-1)!=changed) { - - if (changed) { - - item->add_button(1,get_icon("Reload","EditorIcons"),3); - } else { - - item->erase_button(1,found); - } - - } - - } + _check_reload_status(*k,item); - } Dictionary d=item->get_metadata(0); set_item_text(item,d["type"],d["name"],d["hint"],d["hint_text"]); } @@ -2254,23 +2281,30 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) { if (name!=String()) { + + _check_reload_status(name,p_item); +#if 0 + bool has_reload=false; + + int found=-1; + for(int i=0;i<p_item->get_button_count(1);i++) { + + if (p_item->get_button_id(1,i)==3) { + found=i; + break; + } + } + if (_might_be_in_instance()) { Variant vorig; Dictionary d=p_item->get_metadata(0); int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0; + if (_get_instanced_node_original_property(name,vorig) || usage) { Variant v = obj->get(name); - 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); @@ -2278,10 +2312,11 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) { if (changed) { - p_item->add_button(1,get_icon("Reload","EditorIcons"),3); + has_reload=true; + } else { - p_item->erase_button(1,found); + //p_item->erase_button(1,found); } } @@ -2290,6 +2325,22 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) { } + if (!has_reload && !obj->get_script().is_null()) { + Ref<Script> scr = obj->get_script(); + Variant orig_value; + if (scr->get_property_default_value(name,orig_value)) { + if (orig_value!=obj->get(name)) { + has_reload=true; + } + } + } + + if (!has_reload && found!=-1) { + p_item->erase_button(1,found); + } else if (has_reload && found==-1) { + p_item->add_button(1,get_icon("Reload","EditorIcons"),3); + } +#endif Dictionary d=p_item->get_metadata(0); set_item_text(p_item,d["type"],d["name"],d["hint"],d["hint_text"]); } @@ -3030,6 +3081,7 @@ void PropertyEditor::update_tree() { } } + bool has_reload=false; if (_might_be_in_instance()) { Variant vorig; @@ -3042,11 +3094,24 @@ void PropertyEditor::update_tree() { if (_is_property_different(v,vorig,usage)) { //print_line("FOR "+String(p.name)+" RELOAD WITH: "+String(v)+"("+Variant::get_type_name(v.get_type())+")=="+String(vorig)+"("+Variant::get_type_name(vorig.get_type())+")"); item->add_button(1,get_icon("Reload","EditorIcons"),3); + has_reload=true; } } } + if (!has_reload && !obj->get_script().is_null()) { + Ref<Script> scr = obj->get_script(); + Variant orig_value; + if (scr->get_property_default_value(p.name,orig_value)) { + if (orig_value!=obj->get(p.name)) { + item->add_button(1,get_icon("Reload","EditorIcons"),3); + } + } + } + + + } } @@ -3337,8 +3402,6 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) { call_deferred("_set_range_def",ti,prop,ti->get_range(p_column)+1.0); } else if (p_button==3) { - if (!_might_be_in_instance()) - return; if (!d.has("name")) return; @@ -3346,11 +3409,21 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) { Variant vorig; - if (_get_instanced_node_original_property(prop,vorig)) { + if (_might_be_in_instance() && _get_instanced_node_original_property(prop,vorig)) { _edit_set(prop,vorig); + return; } + if (!obj->get_script().is_null()) { + Ref<Script> scr = obj->get_script(); + Variant orig_value; + if (scr->get_property_default_value(prop,orig_value)) { + _edit_set(prop,orig_value); + } + } + + } else { Dictionary d = ti->get_metadata(0); diff --git a/tools/editor/property_editor.h b/tools/editor/property_editor.h index f76b76c3a2..4f03c0381f 100644 --- a/tools/editor/property_editor.h +++ b/tools/editor/property_editor.h @@ -114,6 +114,7 @@ class CustomPropertyEditor : public Popup { void _action_pressed(int p_which); void _type_create_selected(int p_idx); + void _color_changed(const Color& p_color); void _draw_easing(); void _menu_option(int p_which); @@ -192,6 +193,7 @@ class PropertyEditor : public Control { virtual void _changed_callback(Object *p_changed,const char * p_what); virtual void _changed_callbacks(Object *p_changed,const String& p_callback); + void _check_reload_status(const String&p_name,TreeItem* item); void _edit_button(Object *p_item, int p_column, int p_button); diff --git a/tools/editor/reparent_dialog.cpp b/tools/editor/reparent_dialog.cpp index 0bbf461029..97b27603b2 100644 --- a/tools/editor/reparent_dialog.cpp +++ b/tools/editor/reparent_dialog.cpp @@ -62,7 +62,7 @@ void ReparentDialog::_reparent() { if (tree->get_selected()) { - emit_signal("reparent",tree->get_selected()->get_path(),node_only->is_pressed()); + emit_signal("reparent",tree->get_selected()->get_path(),keep_transform->is_pressed()); hide(); } } @@ -78,7 +78,7 @@ void ReparentDialog::_bind_methods() { ObjectTypeDB::bind_method("_reparent",&ReparentDialog::_reparent); ObjectTypeDB::bind_method("_cancel",&ReparentDialog::_cancel); - ADD_SIGNAL( MethodInfo("reparent",PropertyInfo(Variant::NODE_PATH,"path"),PropertyInfo(Variant::BOOL,"only_node"))); + ADD_SIGNAL( MethodInfo("reparent",PropertyInfo(Variant::NODE_PATH,"path"),PropertyInfo(Variant::BOOL,"keep_global_xform"))); } @@ -101,15 +101,18 @@ ReparentDialog::ReparentDialog() { //label->set_pos( Point2( 15,8) ); //label->set_text("Reparent Location (Select new Parent):"); - node_only = memnew( CheckButton ); - add_child(node_only); - node_only->hide(); + keep_transform = memnew( CheckBox ); + keep_transform->set_text("Keep Global Transform"); + keep_transform->set_pressed(true); + vbc->add_child(keep_transform); + //vbc->add_margin_child("Options:",node_only);; //cancel->connect("pressed", this,"_cancel"); get_ok()->set_text("Reparent"); + } diff --git a/tools/editor/reparent_dialog.h b/tools/editor/reparent_dialog.h index a55be57c16..296102e4b9 100644 --- a/tools/editor/reparent_dialog.h +++ b/tools/editor/reparent_dialog.h @@ -32,6 +32,7 @@ #include "scene/gui/dialogs.h" #include "scene/gui/button.h" #include "scene/gui/check_button.h" +#include "scene/gui/check_box.h" #include "tools/editor/scene_tree_editor.h" #include "scene/gui/line_edit.h" /** @@ -42,12 +43,14 @@ class ReparentDialog : public ConfirmationDialog { OBJ_TYPE( ReparentDialog, ConfirmationDialog ); SceneTreeEditor *tree; - CheckButton *node_only; + CheckBox *keep_transform; + void update_tree(); void _reparent(); void _cancel(); - + + protected: void _notification(int p_what); diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp index 35219a7c63..75f1597b20 100644 --- a/tools/editor/scene_tree_dock.cpp +++ b/tools/editor/scene_tree_dock.cpp @@ -889,7 +889,7 @@ bool SceneTreeDock::_validate_no_foreign() { return true; } -void SceneTreeDock::_node_reparent(NodePath p_path,bool p_node_only) { +void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) { Node *node = scene_tree->get_selected(); @@ -948,6 +948,23 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_node_only) { editor_data->get_undo_redo().add_do_method(sed,"live_debug_reparent_node",edited_scene->get_path_to(node),edited_scene->get_path_to(new_parent),new_name,-1); editor_data->get_undo_redo().add_undo_method(sed,"live_debug_reparent_node",NodePath(String(edited_scene->get_path_to(new_parent))+"/"+new_name),edited_scene->get_path_to(node->get_parent()),node->get_name(),node->get_index()); + if (p_keep_global_xform) { + if (node->cast_to<Node2D>()) + editor_data->get_undo_redo().add_do_method(node,"set_global_transform",node->cast_to<Node2D>()->get_global_transform()); + if (node->cast_to<Spatial>()) + editor_data->get_undo_redo().add_do_method(node,"set_global_transform",node->cast_to<Spatial>()->get_global_transform()); + if (node->cast_to<Control>()) { + bool can_do_it=false; + Control *c=node->cast_to<Control>(); + if (c->get_parent()->cast_to<Container>()) + can_do_it=false; + for(int i=0;i<4;i++) { + if (c->get_anchor(Margin(i))!=ANCHOR_BEGIN) + can_do_it=false; + } + editor_data->get_undo_redo().add_do_method(node,"set_global_pos",node->cast_to<Control>()->get_global_pos()); + } + } editor_data->get_undo_redo().add_do_method(this,"_set_owners",edited_scene,owners); @@ -982,6 +999,26 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_node_only) { if (editor->get_animation_editor()->get_root()==node) editor_data->get_undo_redo().add_undo_method(editor->get_animation_editor(),"set_root",node); + if (p_keep_global_xform) { + if (node->cast_to<Node2D>()) + editor_data->get_undo_redo().add_undo_method(node,"set_transform",node->cast_to<Node2D>()->get_transform()); + if (node->cast_to<Spatial>()) + editor_data->get_undo_redo().add_undo_method(node,"set_transform",node->cast_to<Spatial>()->get_transform()); + if (node->cast_to<Control>()) { + bool can_do_it=false; + Control *c=node->cast_to<Control>(); + if (c->get_parent()->cast_to<Container>()) + can_do_it=false; + for(int i=0;i<4;i++) { + if (c->get_anchor(Margin(i))!=ANCHOR_BEGIN) + can_do_it=false; + } + editor_data->get_undo_redo().add_undo_method(node,"set_pos",node->cast_to<Control>()->get_pos()); + } + } + + + } perform_node_renames(NULL,&path_renames); diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h index b7e96be5c7..aad12a2340 100644 --- a/tools/editor/scene_tree_dock.h +++ b/tools/editor/scene_tree_dock.h @@ -99,7 +99,7 @@ class SceneTreeDock : public VBoxContainer { EditorNode *editor; Node *_duplicate(Node *p_node, Map<Node*,Node*> &duplimap); - void _node_reparent(NodePath p_path,bool p_node_only); + void _node_reparent(NodePath p_path, bool p_keep_global_xform); void _set_owners(Node *p_owner, const Array& p_nodes); void _load_request(const String& p_path); void _script_open_request(const Ref<Script>& p_script); diff --git a/tools/export/blender25/io_scene_dae/export_dae.py b/tools/export/blender25/io_scene_dae/export_dae.py index b846f0e2d8..7ee0e179b8 100644 --- a/tools/export/blender25/io_scene_dae/export_dae.py +++ b/tools/export/blender25/io_scene_dae/export_dae.py @@ -921,7 +921,7 @@ class DaeExporter: if (node.parent.type=="ARMATURE"): armature=node.parent if (armcount>1): - self.operator.report({'WARNING'},'Object "'+node.name+'" refers to more than one armature! This is unsopported.') + self.operator.report({'WARNING'},'Object "'+node.name+'" refers to more than one armature! This is unsupported.') if (armcount==0): self.operator.report({'WARNING'},'Object "'+node.name+'" is child of an armature, but has no armature modifier.') |