This commit is contained in:
Juan Linietsky 2014-12-20 12:32:32 -03:00
commit 9783f6fc96
15 changed files with 503 additions and 131 deletions

View file

@ -112,8 +112,8 @@ func reset_tween():
tween.interpolate_property(sprite, "transform/rot", 360, 0, 2, state.trans, state.eases, 2)
if get_node("modes/callback").is_pressed():
tween.interpolate_callback(self, "on_callback", 0.5, "0.5 second's after")
tween.interpolate_callback(self, "on_callback", 1.2, "1.2 second's after")
tween.interpolate_callback(self, 0.5, "on_callback", "0.5 second's after")
tween.interpolate_callback(self, 0.2, "on_callback", "1.2 second's after")
if get_node("modes/follow").is_pressed():
follow.show()

View file

@ -7,6 +7,7 @@ Export('env')
SConscript('unix/SCsub');
SConscript('alsa/SCsub');
SConscript('pulseaudio/SCsub');
SConscript('windows/SCsub');
SConscript('gles2/SCsub');
SConscript('gles1/SCsub');

5
drivers/pulseaudio/SCsub Normal file
View file

@ -0,0 +1,5 @@
Import('env')
env.add_source_files(env.drivers_sources,"*.cpp")
Export('env')

View file

@ -0,0 +1,194 @@
/*************************************************************************/
/* audio_driver_alsa.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "audio_driver_pulseaudio.h"
#ifdef PULSEAUDIO_ENABLED
#include <pulse/error.h>
#include "globals.h"
Error AudioDriverPulseAudio::init() {
active = false;
thread_exited = false;
exit_thread = false;
pcm_open = false;
samples_in = NULL;
samples_out = NULL;
mix_rate = 44100;
output_format = OUTPUT_STEREO;
channels = 2;
pa_sample_spec spec;
spec.format = PA_SAMPLE_S16LE;
spec.channels = channels;
spec.rate = mix_rate;
int error_code;
pulse = pa_simple_new(NULL, // default server
"Godot", // application name
PA_STREAM_PLAYBACK,
NULL, // default device
"Sound", // stream description
&spec,
NULL, // use default channel map
NULL, // use default buffering attributes
&error_code
);
if (pulse == NULL) {
fprintf(stderr, "PulseAudio ERR: %s\n", pa_strerror(error_code));\
ERR_FAIL_COND_V(pulse == NULL, ERR_CANT_OPEN);
}
int latency = GLOBAL_DEF("audio/output_latency", 25);
buffer_size = nearest_power_of_2(latency * mix_rate / 1000);
samples_in = memnew_arr(int32_t, buffer_size * channels);
samples_out = memnew_arr(int16_t, buffer_size * channels);
mutex = Mutex::create();
thread = Thread::create(AudioDriverPulseAudio::thread_func, this);
return OK;
}
void AudioDriverPulseAudio::thread_func(void* p_udata) {
AudioDriverPulseAudio* ad = (AudioDriverPulseAudio*)p_udata;
while (!ad->exit_thread) {
if (!ad->active) {
for (unsigned int i=0; i < ad->buffer_size * ad->channels; i++) {
ad->samples_out[i] = 0;
}
} else {
ad->lock();
ad->audio_server_process(ad->buffer_size, ad->samples_in);
ad->unlock();
for (unsigned int i=0; i < ad->buffer_size * ad->channels;i ++) {
ad->samples_out[i] = ad->samples_in[i] >> 16;
}
}
// pa_simple_write always consumes the entire buffer
int error_code;
int byte_size = ad->buffer_size * sizeof(int16_t) * ad->channels;
if (pa_simple_write(ad->pulse, ad->samples_out, byte_size, &error_code) < 0) {
// can't recover here
fprintf(stderr, "PulseAudio failed and can't recover: %s\n", pa_strerror(error_code));
ad->active = false;
ad->exit_thread = true;
break;
}
}
ad->thread_exited = true;
}
void AudioDriverPulseAudio::start() {
active = true;
}
int AudioDriverPulseAudio::get_mix_rate() const {
return mix_rate;
}
AudioDriverSW::OutputFormat AudioDriverPulseAudio::get_output_format() const {
return output_format;
}
void AudioDriverPulseAudio::lock() {
if (!thread || !mutex)
return;
mutex->lock();
}
void AudioDriverPulseAudio::unlock() {
if (!thread || !mutex)
return;
mutex->unlock();
}
void AudioDriverPulseAudio::finish() {
if (!thread)
return;
exit_thread = true;
Thread::wait_to_finish(thread);
if (pulse)
pa_simple_free(pulse);
if (samples_in) {
memdelete_arr(samples_in);
memdelete_arr(samples_out);
};
memdelete(thread);
if (mutex) {
memdelete(mutex);
mutex = NULL;
}
thread = NULL;
}
AudioDriverPulseAudio::AudioDriverPulseAudio() {
mutex = NULL;
thread = NULL;
pulse = NULL;
}
AudioDriverPulseAudio::~AudioDriverPulseAudio() {
}
#endif

View file

@ -0,0 +1,79 @@
/*************************************************************************/
/* audio_driver_pulseaudio.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "servers/audio/audio_server_sw.h"
#ifdef PULSEAUDIO_ENABLED
#include "core/os/thread.h"
#include "core/os/mutex.h"
#include <pulse/simple.h>
class AudioDriverPulseAudio : public AudioDriverSW {
Thread* thread;
Mutex* mutex;
pa_simple* pulse;
int32_t* samples_in;
int16_t* samples_out;
static void thread_func(void* p_udata);
unsigned int mix_rate;
OutputFormat output_format;
unsigned int buffer_size;
int channels;
bool active;
bool thread_exited;
mutable bool exit_thread;
bool pcm_open;
public:
const char* get_name() const {
return "PulseAudio";
};
virtual Error init();
virtual void start();
virtual int get_mix_rate() const;
virtual OutputFormat get_output_format() const;
virtual void lock();
virtual void unlock();
virtual void finish();
AudioDriverPulseAudio();
~AudioDriverPulseAudio();
};
#endif

View file

@ -147,6 +147,7 @@ void Main::print_help(const char* p_binary) {
OS::get_singleton()->print(", ");
OS::get_singleton()->print("%s",OS::get_singleton()->get_audio_driver_name(i));
}
OS::get_singleton()->print(")\n");
OS::get_singleton()->print("\t-rthread <mode>\t : Render Thread Mode ('unsafe', 'safe', 'separate).");
OS::get_singleton()->print(")\n");
OS::get_singleton()->print("\t-s,-script [script] : Run a script.\n");

View file

@ -1440,8 +1440,8 @@ GDInstance* GDScript::_create_instance(const Variant** p_args,int p_argcount,Obj
if (err.error!=Variant::CallError::CALL_OK) {
instance->script=Ref<GDScript>();
instance->owner->set_script_instance(NULL);
instances.erase(p_owner);
memdelete(instance);
ERR_FAIL_COND_V(err.error!=Variant::CallError::CALL_OK, NULL); //error consrtucting
}

View file

@ -114,6 +114,14 @@ def configure(env):
env.Append(CPPFLAGS=['-DOPENGL_ENABLED','-DGLEW_ENABLED'])
env.Append(CPPFLAGS=["-DALSA_ENABLED"])
if not os.system("pkg-config --exists libpulse-simple"):
print("Enabling PulseAudio")
env.Append(CPPFLAGS=["-DPULSEAUDIO_ENABLED"])
env.ParseConfig('pkg-config --cflags --libs libpulse-simple')
else:
print("PulseAudio development libraries not found, disabling driver")
env.Append(CPPFLAGS=['-DX11_ENABLED','-DUNIX_ENABLED','-DGLES2_ENABLED','-DGLES1_ENABLED','-DGLES_OVER_GL'])
env.Append(LIBS=['GL', 'GLU', 'pthread','asound','z']) #TODO detect linux/BSD!
#env.Append(CPPFLAGS=['-DMPC_FIXED_POINT'])

View file

@ -74,6 +74,18 @@ OS::VideoMode OS_X11::get_default_video_mode() const {
return OS::VideoMode(800,600,false);
}
int OS_X11::get_audio_driver_count() const {
return AudioDriverManagerSW::get_driver_count();
}
const char *OS_X11::get_audio_driver_name(int p_driver) const {
AudioDriverSW* driver = AudioDriverManagerSW::get_driver(p_driver);
ERR_FAIL_COND_V( !driver, "" );
return AudioDriverManagerSW::get_driver(p_driver)->get_name();
}
void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
last_button_state=0;
@ -1450,6 +1462,10 @@ OS_X11::OS_X11() {
AudioDriverManagerSW::add_driver(&driver_alsa);
#endif
#ifdef PULSEAUDIO_ENABLED
AudioDriverManagerSW::add_driver(&driver_pulseaudio);
#endif
minimized = false;
xim_style=NULL;
mouse_mode=MOUSE_MODE_VISIBLE;

View file

@ -43,6 +43,7 @@
#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/alsa/audio_driver_alsa.h"
#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
#include <X11/keysym.h>
@ -129,6 +130,10 @@ class OS_X11 : public OS_Unix {
AudioDriverALSA driver_alsa;
#endif
#ifdef PULSEAUDIO_ENABLED
AudioDriverPulseAudio driver_pulseaudio;
#endif
enum {
JOYSTICKS_MAX = 8,
MAX_JOY_AXIS = 32768, // I've no idea
@ -160,7 +165,10 @@ protected:
virtual int get_video_driver_count() const;
virtual const char * get_video_driver_name(int p_driver) const;
virtual VideoMode get_default_video_mode() const;
virtual int get_audio_driver_count() const;
virtual const char * get_audio_driver_name(int p_driver) const;
virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
virtual void finalize();

View file

@ -124,32 +124,34 @@ void Tween::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_tween_process_mode"),&Tween::get_tween_process_mode);
ObjectTypeDB::bind_method(_MD("start"),&Tween::start );
ObjectTypeDB::bind_method(_MD("reset","node","key"),&Tween::reset );
ObjectTypeDB::bind_method(_MD("reset","object","key"),&Tween::reset );
ObjectTypeDB::bind_method(_MD("reset_all"),&Tween::reset_all );
ObjectTypeDB::bind_method(_MD("stop","node","key"),&Tween::stop );
ObjectTypeDB::bind_method(_MD("stop","object","key"),&Tween::stop );
ObjectTypeDB::bind_method(_MD("stop_all"),&Tween::stop_all );
ObjectTypeDB::bind_method(_MD("resume","node","key"),&Tween::resume );
ObjectTypeDB::bind_method(_MD("resume","object","key"),&Tween::resume );
ObjectTypeDB::bind_method(_MD("resume_all"),&Tween::resume_all );
ObjectTypeDB::bind_method(_MD("remove","node","key"),&Tween::remove );
ObjectTypeDB::bind_method(_MD("remove","object","key"),&Tween::remove );
ObjectTypeDB::bind_method(_MD("remove_all"),&Tween::remove_all );
ObjectTypeDB::bind_method(_MD("seek","time"),&Tween::seek );
ObjectTypeDB::bind_method(_MD("tell"),&Tween::tell );
ObjectTypeDB::bind_method(_MD("get_runtime"),&Tween::get_runtime );
ObjectTypeDB::bind_method(_MD("interpolate_property","node","property","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_property, DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("interpolate_method","node","method","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_method, DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("interpolate_callback","node","callback","times_in_sec","args"),&Tween::interpolate_callback, DEFVAL(Variant()) );
ObjectTypeDB::bind_method(_MD("follow_property","node","property","initial_val","target","target_property","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_property, DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("follow_method","node","method","initial_val","target","target_method","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_method, DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("targeting_property","node","property","initial","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_property, DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("targeting_method","node","method","initial","initial_method","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_method, DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("interpolate_property","object","property","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_property, DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("interpolate_method","object","method","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_method, DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("interpolate_callback","object","times_in_sec","callback","args"),&Tween::interpolate_callback, DEFVAL(Variant()) );
ObjectTypeDB::bind_method(_MD("follow_property","object","property","initial_val","target","target_property","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_property, DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("follow_method","object","method","initial_val","target","target_method","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_method, DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("targeting_property","object","property","initial","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_property, DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("targeting_method","object","method","initial","initial_method","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_method, DEFVAL(0) );
ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key")) );
ADD_SIGNAL( MethodInfo("tween_step", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) );
ADD_SIGNAL( MethodInfo("tween_complete", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key")) );
ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) );
ADD_SIGNAL( MethodInfo("tween_step", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) );
ADD_SIGNAL( MethodInfo("tween_complete", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) );
ADD_PROPERTY( PropertyInfo( Variant::INT, "playback/process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_tween_process_mode"), _SCS("get_tween_process_mode"));
//ADD_PROPERTY( PropertyInfo( Variant::BOOL, "activate"), _SCS("set_active"), _SCS("is_active"));
BIND_CONSTANT(TWEEN_PROCESS_FIXED);
BIND_CONSTANT(TWEEN_PROCESS_IDLE);
BIND_CONSTANT(TRANS_LINEAR);
BIND_CONSTANT(TRANS_SINE);
@ -181,19 +183,19 @@ Variant& Tween::_get_initial_val(InterpolateData& p_data) {
case TARGETING_PROPERTY:
case TARGETING_METHOD: {
Node *node = get_node(p_data.target);
ERR_FAIL_COND_V(node == NULL,p_data.initial_val);
Object *object = ObjectDB::get_instance(p_data.target_id);
ERR_FAIL_COND_V(object == NULL,p_data.initial_val);
static Variant initial_val;
if(p_data.type == TARGETING_PROPERTY) {
bool valid = false;
initial_val = node->get(p_data.target_key, &valid);
initial_val = object->get(p_data.target_key, &valid);
ERR_FAIL_COND_V(!valid,p_data.initial_val);
} else {
Variant::CallError error;
initial_val = node->call(p_data.target_key, NULL, 0, error);
initial_val = object->call(p_data.target_key, NULL, 0, error);
ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK,p_data.initial_val);
}
return initial_val;
@ -213,7 +215,7 @@ Variant& Tween::_get_delta_val(InterpolateData& p_data) {
case FOLLOW_PROPERTY:
case FOLLOW_METHOD: {
Node *target = get_node(p_data.target);
Object *target = ObjectDB::get_instance(p_data.target_id);
ERR_FAIL_COND_V(target == NULL,p_data.initial_val);
Variant final_val;
@ -264,6 +266,11 @@ Variant Tween::_run_equation(InterpolateData& p_data) {
switch(initial_val.get_type())
{
case Variant::BOOL:
result = ((int) _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int) initial_val, (int) delta_val, p_data.times_in_sec)) >= 0.5;
break;
case Variant::INT:
result = (int) _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int) initial_val, (int) delta_val, p_data.times_in_sec);
break;
@ -409,7 +416,7 @@ Variant Tween::_run_equation(InterpolateData& p_data) {
bool Tween::_apply_tween_value(InterpolateData& p_data, Variant& value) {
Object *object = get_node(p_data.path);
Object *object = ObjectDB::get_instance(p_data.id);
ERR_FAIL_COND_V(object == NULL, false);
switch(p_data.type) {
@ -452,6 +459,7 @@ void Tween::_tween_process(float p_delta) {
return;
p_delta *= speed_scale;
pending_update ++;
// if repeat and all interpolates was finished then reset all interpolates
if(repeat) {
bool all_finished = true;
@ -476,7 +484,7 @@ void Tween::_tween_process(float p_delta) {
if(!data.active || data.finish)
continue;
Object *object = get_node(data.path);
Object *object = ObjectDB::get_instance(data.id);
if(object == NULL)
continue;
@ -523,6 +531,7 @@ void Tween::_tween_process(float p_delta) {
if(data.finish)
emit_signal("tween_complete",object,data.key);
}
pending_update --;
}
void Tween::set_tween_process_mode(TweenProcessMode p_mode) {
@ -598,16 +607,17 @@ bool Tween::start() {
return true;
}
bool Tween::reset(Node *p_node, String p_key) {
bool Tween::reset(Object *p_object, String p_key) {
pending_update ++;
for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
InterpolateData& data = E->get();
Node *node = get_node(data.path);
if(node == NULL)
Object *object = ObjectDB::get_instance(data.id);
if(object == NULL)
continue;
if(node == p_node && data.key == p_key) {
if(object == p_object && data.key == p_key) {
data.elapsed = 0;
data.finish = false;
@ -615,11 +625,13 @@ bool Tween::reset(Node *p_node, String p_key) {
_apply_tween_value(data, data.initial_val);
}
}
pending_update --;
return true;
}
bool Tween::reset_all() {
pending_update ++;
for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
InterpolateData& data = E->get();
@ -628,20 +640,23 @@ bool Tween::reset_all() {
if(data.delay == 0)
_apply_tween_value(data, data.initial_val);
}
pending_update --;
return true;
}
bool Tween::stop(Node *p_node, String p_key) {
bool Tween::stop(Object *p_object, String p_key) {
pending_update ++;
for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
InterpolateData& data = E->get();
Node *node = get_node(data.path);
if(node == NULL)
Object *object = ObjectDB::get_instance(data.id);
if(object == NULL)
continue;
if(node == p_node && data.key == p_key)
if(object == p_object && data.key == p_key)
data.active = false;
}
pending_update --;
return true;
}
@ -650,28 +665,32 @@ bool Tween::stop_all() {
set_active(false);
_set_process(false);
pending_update ++;
for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
InterpolateData& data = E->get();
data.active = false;
}
pending_update --;
return true;
}
bool Tween::resume(Node *p_node, String p_key) {
bool Tween::resume(Object *p_object, String p_key) {
set_active(true);
_set_process(true);
pending_update ++;
for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
InterpolateData& data = E->get();
Node *node = get_node(data.path);
if(node == NULL)
Object *object = ObjectDB::get_instance(data.id);
if(object == NULL)
continue;
if(node == p_node && data.key == p_key)
if(object == p_object && data.key == p_key)
data.active = true;
}
pending_update --;
return true;
}
@ -680,23 +699,26 @@ bool Tween::resume_all() {
set_active(true);
_set_process(true);
pending_update ++;
for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
InterpolateData& data = E->get();
data.active = true;
}
pending_update --;
return true;
}
bool Tween::remove(Node *p_node, String p_key) {
bool Tween::remove(Object *p_object, String p_key) {
ERR_FAIL_COND_V(pending_update != 0, false);
for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
InterpolateData& data = E->get();
Node *node = get_node(data.path);
if(node == NULL)
Object *object = ObjectDB::get_instance(data.id);
if(object == NULL)
continue;
if(node == p_node && data.key == p_key) {
if(object == p_object && data.key == p_key) {
interpolates.erase(E);
return true;
}
@ -706,6 +728,7 @@ bool Tween::remove(Node *p_node, String p_key) {
bool Tween::remove_all() {
ERR_FAIL_COND_V(pending_update != 0, false);
set_active(false);
_set_process(false);
interpolates.clear();
@ -714,6 +737,7 @@ bool Tween::remove_all() {
bool Tween::seek(real_t p_time) {
pending_update ++;
for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
InterpolateData& data = E->get();
@ -744,11 +768,13 @@ bool Tween::seek(real_t p_time) {
_apply_tween_value(data, result);
}
pending_update --;
return true;
}
real_t Tween::tell() const {
pending_update ++;
real_t pos = 0;
for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
@ -756,11 +782,13 @@ real_t Tween::tell() const {
if(data.elapsed > pos)
pos = data.elapsed;
}
pending_update --;
return pos;
}
real_t Tween::get_runtime() const {
pending_update ++;
real_t runtime = 0;
for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
@ -769,6 +797,7 @@ real_t Tween::get_runtime() const {
if(t > runtime)
runtime = t;
}
pending_update --;
return runtime;
}
@ -779,6 +808,12 @@ bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final
Variant& delta_val = p_delta_val;
switch(initial_val.get_type()) {
case Variant::BOOL:
//delta_val = p_final_val;
delta_val = (int) p_final_val - (int) p_initial_val;
break;
case Variant::INT:
delta_val = (int) final_val - (int) initial_val;
break;
@ -873,7 +908,7 @@ bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final
return true;
}
bool Tween::interpolate_property(Node *p_node
bool Tween::interpolate_property(Object *p_object
, String p_property
, Variant p_initial_val
, Variant p_final_val
@ -882,11 +917,12 @@ bool Tween::interpolate_property(Node *p_node
, EaseType p_ease_type
, real_t p_delay
) {
ERR_FAIL_COND_V(pending_update != 0, false);
// convert INT to REAL is better for interpolaters
if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
ERR_FAIL_COND_V(p_node == NULL, false);
ERR_FAIL_COND_V(p_object == NULL, false);
ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false);
ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
@ -894,7 +930,7 @@ bool Tween::interpolate_property(Node *p_node
ERR_FAIL_COND_V(p_delay < 0, false);
bool prop_valid = false;
p_node->get(p_property,&prop_valid);
p_object->get(p_property,&prop_valid);
ERR_FAIL_COND_V(!prop_valid, false);
InterpolateData data;
@ -903,7 +939,7 @@ bool Tween::interpolate_property(Node *p_node
data.finish = false;
data.elapsed = 0;
data.path = p_node->get_path();
data.id = p_object->get_instance_ID();
data.key = p_property;
data.initial_val = p_initial_val;
data.final_val = p_final_val;
@ -919,7 +955,7 @@ bool Tween::interpolate_property(Node *p_node
return true;
}
bool Tween::interpolate_method(Node *p_node
bool Tween::interpolate_method(Object *p_object
, String p_method
, Variant p_initial_val
, Variant p_final_val
@ -928,18 +964,19 @@ bool Tween::interpolate_method(Node *p_node
, EaseType p_ease_type
, real_t p_delay
) {
ERR_FAIL_COND_V(pending_update != 0, false);
// convert INT to REAL is better for interpolaters
if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
ERR_FAIL_COND_V(p_node == NULL, false);
ERR_FAIL_COND_V(p_object == NULL, false);
ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false);
ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
ERR_FAIL_COND_V(p_delay < 0, false);
ERR_FAIL_COND_V(!p_node->has_method(p_method), false);
ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
InterpolateData data;
data.active = true;
@ -947,7 +984,7 @@ bool Tween::interpolate_method(Node *p_node
data.finish = false;
data.elapsed = 0;
data.path = p_node->get_path();
data.id = p_object->get_instance_ID();
data.key = p_method;
data.initial_val = p_initial_val;
data.final_val = p_final_val;
@ -963,16 +1000,17 @@ bool Tween::interpolate_method(Node *p_node
return true;
}
bool Tween::interpolate_callback(Node *p_node
, String p_callback
bool Tween::interpolate_callback(Object *p_object
, real_t p_times_in_sec
, String p_callback
, Variant p_arg
) {
ERR_FAIL_COND_V(p_node == NULL, false);
ERR_FAIL_COND_V(pending_update != 0, false);
ERR_FAIL_COND_V(p_object == NULL, false);
ERR_FAIL_COND_V(p_times_in_sec < 0, false);
ERR_FAIL_COND_V(!p_node->has_method(p_callback), false);
ERR_FAIL_COND_V(!p_object->has_method(p_callback), false);
InterpolateData data;
data.active = true;
@ -980,30 +1018,33 @@ bool Tween::interpolate_callback(Node *p_node
data.finish = false;
data.elapsed = 0;
data.path = p_node->get_path();
data.id = p_object->get_instance_ID();
data.key = p_callback;
data.times_in_sec = p_times_in_sec;
data.delay = 0;
data.arg = p_arg;
pending_update ++;
interpolates.push_back(data);
pending_update --;
return true;
}
bool Tween::follow_property(Node *p_node
bool Tween::follow_property(Object *p_object
, String p_property
, Variant p_initial_val
, Node *p_target
, Object *p_target
, String p_target_property
, real_t p_times_in_sec
, TransitionType p_trans_type
, EaseType p_ease_type
, real_t p_delay
) {
ERR_FAIL_COND_V(pending_update != 0, false);
// convert INT to REAL is better for interpolaters
if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
ERR_FAIL_COND_V(p_node == NULL, false);
ERR_FAIL_COND_V(p_object == NULL, false);
ERR_FAIL_COND_V(p_target == NULL, false);
ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
@ -1011,7 +1052,7 @@ bool Tween::follow_property(Node *p_node
ERR_FAIL_COND_V(p_delay < 0, false);
bool prop_valid = false;
p_node->get(p_property,&prop_valid);
p_object->get(p_property,&prop_valid);
ERR_FAIL_COND_V(!prop_valid, false);
bool target_prop_valid = false;
@ -1028,10 +1069,10 @@ bool Tween::follow_property(Node *p_node
data.finish = false;
data.elapsed = 0;
data.path = p_node->get_path();
data.id = p_object->get_instance_ID();
data.key = p_property;
data.initial_val = p_initial_val;
data.target = p_target->get_path();
data.target_id = p_target->get_instance_ID();
data.target_key = p_target_property;
data.times_in_sec = p_times_in_sec;
data.trans_type = p_trans_type;
@ -1042,27 +1083,28 @@ bool Tween::follow_property(Node *p_node
return true;
}
bool Tween::follow_method(Node *p_node
bool Tween::follow_method(Object *p_object
, String p_method
, Variant p_initial_val
, Node *p_target
, Object *p_target
, String p_target_method
, real_t p_times_in_sec
, TransitionType p_trans_type
, EaseType p_ease_type
, real_t p_delay
) {
ERR_FAIL_COND_V(pending_update != 0, false);
// convert INT to REAL is better for interpolaters
if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
ERR_FAIL_COND_V(p_node == NULL, false);
ERR_FAIL_COND_V(p_object == NULL, false);
ERR_FAIL_COND_V(p_target == NULL, false);
ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
ERR_FAIL_COND_V(p_delay < 0, false);
ERR_FAIL_COND_V(!p_node->has_method(p_method), false);
ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
ERR_FAIL_COND_V(!p_target->has_method(p_target_method), false);
Variant::CallError error;
@ -1079,10 +1121,10 @@ bool Tween::follow_method(Node *p_node
data.finish = false;
data.elapsed = 0;
data.path = p_node->get_path();
data.id = p_object->get_instance_ID();
data.key = p_method;
data.initial_val = p_initial_val;
data.target = p_target->get_path();
data.target_id = p_target->get_instance_ID();
data.target_key = p_target_method;
data.times_in_sec = p_times_in_sec;
data.trans_type = p_trans_type;
@ -1093,9 +1135,9 @@ bool Tween::follow_method(Node *p_node
return true;
}
bool Tween::targeting_property(Node *p_node
bool Tween::targeting_property(Object *p_object
, String p_property
, Node *p_initial
, Object *p_initial
, String p_initial_property
, Variant p_final_val
, real_t p_times_in_sec
@ -1103,10 +1145,11 @@ bool Tween::targeting_property(Node *p_node
, EaseType p_ease_type
, real_t p_delay
) {
ERR_FAIL_COND_V(pending_update != 0, false);
// convert INT to REAL is better for interpolaters
if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
ERR_FAIL_COND_V(p_node == NULL, false);
ERR_FAIL_COND_V(p_object == NULL, false);
ERR_FAIL_COND_V(p_initial == NULL, false);
ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
@ -1114,7 +1157,7 @@ bool Tween::targeting_property(Node *p_node
ERR_FAIL_COND_V(p_delay < 0, false);
bool prop_valid = false;
p_node->get(p_property,&prop_valid);
p_object->get(p_property,&prop_valid);
ERR_FAIL_COND_V(!prop_valid, false);
bool initial_prop_valid = false;
@ -1131,9 +1174,9 @@ bool Tween::targeting_property(Node *p_node
data.finish = false;
data.elapsed = 0;
data.path = p_node->get_path();
data.id = p_object->get_instance_ID();
data.key = p_property;
data.target = p_initial->get_path();
data.target_id = p_initial->get_instance_ID();
data.target_key = p_initial_property;
data.initial_val = initial_val;
data.final_val = p_final_val;
@ -1150,9 +1193,9 @@ bool Tween::targeting_property(Node *p_node
}
bool Tween::targeting_method(Node *p_node
bool Tween::targeting_method(Object *p_object
, String p_method
, Node *p_initial
, Object *p_initial
, String p_initial_method
, Variant p_final_val
, real_t p_times_in_sec
@ -1160,17 +1203,18 @@ bool Tween::targeting_method(Node *p_node
, EaseType p_ease_type
, real_t p_delay
) {
ERR_FAIL_COND_V(pending_update != 0, false);
// convert INT to REAL is better for interpolaters
if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
ERR_FAIL_COND_V(p_node == NULL, false);
ERR_FAIL_COND_V(p_object == NULL, false);
ERR_FAIL_COND_V(p_initial == NULL, false);
ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
ERR_FAIL_COND_V(p_delay < 0, false);
ERR_FAIL_COND_V(!p_node->has_method(p_method), false);
ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
ERR_FAIL_COND_V(!p_initial->has_method(p_initial_method), false);
Variant::CallError error;
@ -1187,9 +1231,9 @@ bool Tween::targeting_method(Node *p_node
data.finish = false;
data.elapsed = 0;
data.path = p_node->get_path();
data.id = p_object->get_instance_ID();
data.key = p_method;
data.target = p_initial->get_path();
data.target_id = p_initial->get_instance_ID();
data.target_key = p_initial_method;
data.initial_val = initial_val;
data.final_val = p_final_val;
@ -1213,6 +1257,7 @@ Tween::Tween() {
active=false;
repeat=false;
speed_scale=1;
pending_update=0;
}
Tween::~Tween() {

View file

@ -54,15 +54,17 @@ public:
TRANS_CIRC,
TRANS_BOUNCE,
TRANS_BACK,
TRANS_COUNT,
TRANS_COUNT,
};
enum EaseType {
EASE_IN,
EASE_OUT,
EASE_IN_OUT,
EASE_OUT_IN,
EASE_COUNT,
EASE_OUT_IN,
EASE_COUNT,
};
private:
@ -82,12 +84,12 @@ private:
InterpolateType type;
bool finish;
real_t elapsed;
NodePath path;
ObjectID id;
StringName key;
Variant initial_val;
Variant delta_val;
Variant final_val;
NodePath target;
ObjectID target_id;
StringName target_key;
real_t times_in_sec;
TransitionType trans_type;
@ -102,6 +104,7 @@ private:
bool active;
bool repeat;
float speed_scale;
mutable int pending_update;
List<InterpolateData> interpolates;
@ -142,20 +145,20 @@ public:
float get_speed() const;
bool start();
bool reset(Node *p_node, String p_key);
bool reset(Object *p_node, String p_key);
bool reset_all();
bool stop(Node *p_node, String p_key);
bool stop(Object *p_node, String p_key);
bool stop_all();
bool resume(Node *p_node, String p_key);
bool resume(Object *p_node, String p_key);
bool resume_all();
bool remove(Node *p_node, String p_key);
bool remove(Object *p_node, String p_key);
bool remove_all();
bool seek(real_t p_time);
real_t tell() const;
real_t get_runtime() const;
bool interpolate_property(Node *p_node
bool interpolate_property(Object *p_node
, String p_property
, Variant p_initial_val
, Variant p_final_val
@ -165,7 +168,7 @@ public:
, real_t p_delay = 0
);
bool interpolate_method(Node *p_node
bool interpolate_method(Object *p_node
, String p_method
, Variant p_initial_val
, Variant p_final_val
@ -175,16 +178,16 @@ public:
, real_t p_delay = 0
);
bool interpolate_callback(Node *p_node
, String p_callback
bool interpolate_callback(Object *p_node
, real_t p_times_in_sec
, String p_callback
, Variant p_arg = Variant()
);
bool follow_property(Node *p_node
bool follow_property(Object *p_node
, String p_property
, Variant p_initial_val
, Node *p_target
, Object *p_target
, String p_target_property
, real_t p_times_in_sec
, TransitionType p_trans_type
@ -192,10 +195,10 @@ public:
, real_t p_delay = 0
);
bool follow_method(Node *p_node
bool follow_method(Object *p_node
, String p_method
, Variant p_initial_val
, Node *p_target
, Object *p_target
, String p_target_method
, real_t p_times_in_sec
, TransitionType p_trans_type
@ -203,9 +206,9 @@ public:
, real_t p_delay = 0
);
bool targeting_property(Node *p_node
bool targeting_property(Object *p_node
, String p_property
, Node *p_initial
, Object *p_initial
, String p_initial_property
, Variant p_final_val
, real_t p_times_in_sec
@ -214,9 +217,9 @@ public:
, real_t p_delay = 0
);
bool targeting_method(Node *p_node
bool targeting_method(Object *p_node
, String p_method
, Node *p_initial
, Object *p_initial
, String p_initial_method
, Variant p_final_val
, real_t p_times_in_sec

View file

@ -1921,27 +1921,6 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
} break;
case KEY_K:{
if (!k.mod.command || k.mod.shift || k.mod.alt) {
scancode_handled=false;
break;
}
else {
if (selection.active) {
int ini = selection.from_line;
int end = selection.to_line;
for (int i=ini; i<= end; i++)
{
_insert_text(i,0,"#");
}
}
else{
_insert_text(cursor.line,0,"#");
}
update();
}
break;}
case KEY_U:{
if (!k.mod.command || k.mod.shift || k.mod.alt) {
scancode_handled=false;

View file

@ -1599,7 +1599,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
edit_menu->get_popup()->add_item("Move Down",EDIT_MOVE_LINE_DOWN,KEY_MASK_ALT|KEY_DOWN);
edit_menu->get_popup()->add_item("Indent Left",EDIT_INDENT_LEFT,KEY_MASK_ALT|KEY_LEFT);
edit_menu->get_popup()->add_item("Indent Right",EDIT_INDENT_RIGHT,KEY_MASK_ALT|KEY_RIGHT);
edit_menu->get_popup()->add_item("Toggle Comment",EDIT_TOGGLE_COMMENT,KEY_MASK_CMD|KEY_SLASH);
edit_menu->get_popup()->add_item("Toggle Comment",EDIT_TOGGLE_COMMENT,KEY_MASK_CMD|KEY_K);
edit_menu->get_popup()->add_item("Clone Down",EDIT_CLONE_DOWN,KEY_MASK_CMD|KEY_B);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_item("Complete Symbol",EDIT_COMPLETE,KEY_MASK_CMD|KEY_SPACE);

View file

@ -212,17 +212,50 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!_validate_no_foreign())
break;
Node * node=scene_tree->get_selected();
ERR_FAIL_COND(!node->get_parent());
int current_pos = node->get_index();
int next_pos = current_pos + ((p_tool==TOOL_MOVE_DOWN)?1:-1);
bool MOVING_DOWN = (p_tool == TOOL_MOVE_DOWN);
bool MOVING_UP = !MOVING_DOWN;
if (next_pos< 0 || next_pos>=node->get_parent()->get_child_count())
break; // invalid position
Node *common_parent = scene_tree->get_selected()->get_parent();
List<Node*> selection = editor_selection->get_selected_node_list();
selection.sort_custom<Node::Comparator>(); // sort by index
if (MOVING_DOWN)
selection.invert();
int lowest_id = common_parent->get_child_count() - 1;
int highest_id = 0;
for (List<Node*>::Element *E = selection.front(); E; E = E->next()) {
int index = E->get()->get_index();
if (index > highest_id) highest_id = index;
if (index < lowest_id) lowest_id = index;
if (E->get()->get_parent() != common_parent)
common_parent = NULL;
}
if (!common_parent || (MOVING_DOWN && highest_id >= common_parent->get_child_count() - MOVING_DOWN) || (MOVING_UP && lowest_id == 0))
break; // one or more nodes can not be moved
if (selection.size() == 1) editor_data->get_undo_redo().create_action("Move Node In Parent");
if (selection.size() > 1) editor_data->get_undo_redo().create_action("Move Nodes In Parent");
for (int i = 0; i < selection.size(); i++) {
Node *top_node = selection[i];
Node *bottom_node = selection[selection.size() - 1 - i];
ERR_FAIL_COND(!top_node->get_parent());
ERR_FAIL_COND(!bottom_node->get_parent());
int top_node_pos = top_node->get_index();
int bottom_node_pos = bottom_node->get_index();
int top_node_pos_next = top_node_pos + (MOVING_DOWN ? 1 : -1);
int bottom_node_pos_next = bottom_node_pos + (MOVING_DOWN ? 1 : -1);
editor_data->get_undo_redo().add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next);
editor_data->get_undo_redo().add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos);
}
editor_data->get_undo_redo().create_action("Move Node In Parent");
editor_data->get_undo_redo().add_do_method(node->get_parent(),"move_child",node,next_pos);
editor_data->get_undo_redo().add_undo_method(node->get_parent(),"move_child",node,current_pos);
editor_data->get_undo_redo().commit_action();
} break;