From 734d539a7dbef428402fb232ca7623a215ac3f64 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe Date: Tue, 5 May 2015 15:34:40 -0300 Subject: [PATCH 01/15] Change the order of the filter --- core/globals.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/globals.cpp b/core/globals.cpp index b128914de59..23d8c16ace0 100644 --- a/core/globals.cpp +++ b/core/globals.cpp @@ -1381,7 +1381,7 @@ Globals::Globals() { set("application/name","" ); set("application/main_scene",""); - custom_prop_info["application/main_scene"]=PropertyInfo(Variant::STRING,"application/main_scene",PROPERTY_HINT_FILE,"xml,res,scn,xscn"); + custom_prop_info["application/main_scene"]=PropertyInfo(Variant::STRING,"application/main_scene",PROPERTY_HINT_FILE,"scn,res,xscn,xml"); set("application/disable_stdout",false); set("application/use_shared_user_dir",true); From 670d77813f8ded38685eee98f83dc796227a59b7 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 00:41:41 +0200 Subject: [PATCH 02/15] PhysicsServerSW::body_is_shape_set_as_trigger - missing return statement --- servers/physics/physics_server_sw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index 2b4a137e118..03d5b7afa16 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -551,7 +551,7 @@ bool PhysicsServerSW::body_is_shape_set_as_trigger(RID p_body, int p_shape_idx) ERR_FAIL_COND_V(!body,false); ERR_FAIL_INDEX_V(p_shape_idx,body->get_shape_count(),false); - body->is_shape_set_as_trigger(p_shape_idx); + return body->is_shape_set_as_trigger(p_shape_idx); } From edce27fc0328531461f68dd974a72c759e4bcc85 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 00:43:24 +0200 Subject: [PATCH 03/15] minor fixes in drivers mpc and vorbis. --- drivers/mpc/mpc_reader.c | 1 + drivers/vorbis/psy.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mpc/mpc_reader.c b/drivers/mpc/mpc_reader.c index e1d151fe502..550c5ecb542 100644 --- a/drivers/mpc/mpc_reader.c +++ b/drivers/mpc/mpc_reader.c @@ -36,6 +36,7 @@ #include #include "internal.h" #include +#include // memset() #define STDIO_MAGIC 0xF34B963C ///< Just a random safe-check value... typedef struct mpc_reader_stdio_t { diff --git a/drivers/vorbis/psy.c b/drivers/vorbis/psy.c index 9a86151cecc..29d28243724 100644 --- a/drivers/vorbis/psy.c +++ b/drivers/vorbis/psy.c @@ -1160,7 +1160,7 @@ void _vp_couple_quantize_normalize(int blobno, However, this is a temporary patch. by Aoyumi @ 2004/04/18 */ - /*float derate = (1.0 - de*((float)(j-limit+i) / (float)(n-limit))); + /*float derate = (1.0 - de*((float)(j-limit+i) / (float)(n-limit))); */ /* elliptical if(reM[j]+reA[j]<0){ reM[j] = - (qeM[j] = (fabs(reM[j])+fabs(reA[j]))*derate*derate); From d177e0f64a03fdafd3401456639834c76dfbf32b Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 00:46:02 +0200 Subject: [PATCH 04/15] fixed issue with format string in PCKPacker::flush --- tools/pck/pck_packer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pck/pck_packer.cpp b/tools/pck/pck_packer.cpp index 09611b3a93c..d398fefb5f4 100644 --- a/tools/pck/pck_packer.cpp +++ b/tools/pck/pck_packer.cpp @@ -136,7 +136,7 @@ Error PCKPacker::flush(bool p_verbose) { count += 1; if (p_verbose) { if (count % 100 == 0) { - printf("%i/%i (%.2f\%)\r", count, files.size(), float(count) / files.size() * 100); + printf("%i/%i (%.2f)\r", count, files.size(), float(count) / files.size() * 100); fflush(stdout); }; }; From dcc93a33fdc8c1362545107a604e67e60a061489 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 00:49:00 +0200 Subject: [PATCH 05/15] fixed SpatialEditor::_init_indications. loopcounter "i" used ambiguous --- tools/editor/plugins/spatial_editor_plugin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 4dae60399be..ac2ea9799e5 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -3172,11 +3172,11 @@ void SpatialEditor::_init_indicators() { int arrow_sides=6; - for(int i = 0; i < 7 ; i++) { + for(int k = 0; k < 7 ; k++) { - Matrix3 ma(ivec,Math_PI*2*float(i)/arrow_sides); - Matrix3 mb(ivec,Math_PI*2*float(i+1)/arrow_sides); + Matrix3 ma(ivec,Math_PI*2*float(k)/arrow_sides); + Matrix3 mb(ivec,Math_PI*2*float(k+1)/arrow_sides); for(int j=0;j Date: Wed, 6 May 2015 00:51:49 +0200 Subject: [PATCH 06/15] added notes to resolve undefined behavior of calculations in tweening interpolators in future. --- scene/animation/tween_interpolaters.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scene/animation/tween_interpolaters.cpp b/scene/animation/tween_interpolaters.cpp index c052d752f84..9128d220def 100644 --- a/scene/animation/tween_interpolaters.cpp +++ b/scene/animation/tween_interpolaters.cpp @@ -285,18 +285,18 @@ namespace cubic { namespace circ { static real_t in(real_t t, real_t b, real_t c, real_t d) { - return -c * (sqrt(1 - (t /= d) * t) - 1) + b; + return -c * (sqrt(1 - (t /= d) * t) - 1) + b; // TODO: ehrich: operation with t is undefined } static real_t out(real_t t, real_t b, real_t c, real_t d) { - return c * sqrt(1 - (t = t / d - 1) * t) + b; + return c * sqrt(1 - (t = t / d - 1) * t) + b; // TODO: ehrich: operation with t is undefined } static real_t in_out(real_t t, real_t b, real_t c, real_t d) { if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b; - return c / 2 * (sqrt(1 - t * (t -= 2)) + 1) + b; + return c / 2 * (sqrt(1 - t * (t -= 2)) + 1) + b; // TODO: ehrich: operation with t is undefined } static real_t out_in(real_t t, real_t b, real_t c, real_t d) @@ -364,15 +364,15 @@ namespace back { static real_t out(real_t t, real_t b, real_t c, real_t d) { float s = 1.70158f; - return c * ((t = t / d- 1) * t * ((s + 1) * t + s) + 1) + b; + return c * ((t = t / d- 1) * t * ((s + 1) * t + s) + 1) + b; // TODO: ehrich: operation with t is undefined } static real_t in_out(real_t t, real_t b, real_t c, real_t d) { float s = 1.70158f; - if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b; + if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b; // TODO: ehrich: operation with s is undefined float postFix = t -= 2; - return c / 2 * ((postFix) * t * (((s *= (1.525f)) + 1) * t + s) + 2) + b; + return c / 2 * ((postFix) * t * (((s *= (1.525f)) + 1) * t + s) + 2) + b; // TODO: ehrich: operation with s is undefined } static real_t out_in(real_t t, real_t b, real_t c, real_t d) From 897a1aade5332753d9fda950d80495798cdc85b4 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 00:56:59 +0200 Subject: [PATCH 07/15] optional formal changes --- core/io/resource_format_xml.cpp | 2 +- core/math/math_funcs.cpp | 7 ++++--- platform/x11/os_x11.cpp | 4 ++-- scene/2d/camera_2d.cpp | 3 +-- scene/gui/line_edit.cpp | 2 +- scene/gui/text_edit.cpp | 4 ++-- servers/physics/collision_object_sw.h | 4 +++- servers/visual/rasterizer.h | 10 +++++----- servers/visual/visual_server_raster.cpp | 2 +- tools/docdump/doc_dump.cpp | 2 +- tools/editor/animation_editor.cpp | 2 +- tools/editor/editor_file_system.cpp | 8 ++++---- .../editor/io_plugins/editor_texture_import_plugin.cpp | 2 ++ tools/editor/plugins/shader_graph_editor_plugin.cpp | 1 - tools/editor/spatial_editor_gizmos.cpp | 3 ++- 15 files changed, 30 insertions(+), 26 deletions(-) diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp index 9de33e7ef35..3e625ba6fd7 100644 --- a/core/io/resource_format_xml.cpp +++ b/core/io/resource_format_xml.cpp @@ -1850,7 +1850,7 @@ void ResourceFormatSaverXMLInstance::escape(String& p_str) { p_str=p_str.replace(">","<"); p_str=p_str.replace("'","'"); p_str=p_str.replace("\"","""); - for (int i=1;i<32;i++) { + for (char i=1;i<32;i++) { char chr[2]={i,0}; const char hexn[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp index 6ad5c7499b4..3c94ac5bc78 100644 --- a/core/math/math_funcs.cpp +++ b/core/math/math_funcs.cpp @@ -36,8 +36,9 @@ uint32_t Math::default_seed=1; #define PHI 0x9e3779b9 -static uint32_t Q[4096], c = 362436; - +#if 0 +static uint32_t Q[4096]; +#endif uint32_t Math::rand_from_seed(uint32_t *seed) { @@ -269,7 +270,7 @@ bool Math::is_inf(double p_val) { uint32_t Math::larger_prime(uint32_t p_val) { - static const int primes[] = { + static const uint32_t primes[] = { 5, 13, 23, diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 67ec33f3a37..28427fa2f03 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -317,8 +317,8 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi /* set the name and class hints for the window manager to use */ classHint = XAllocClassHint(); if (classHint) { - classHint->res_name = "Godot"; - classHint->res_class = "Godot"; + classHint->res_name = (char *)"Godot"; + classHint->res_class = (char *)"Godot"; } XSetClassHint(x11_display, x11_window, classHint); XFree(classHint); diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 27a512845c0..70b88a66117 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -132,8 +132,7 @@ Matrix32 Camera2D::get_camera_transform() { } - Point2 screen_offset = (centered ? (screen_size * 0.5 * zoom) : Point2());; - screen_offset; + Point2 screen_offset = (centered ? (screen_size * 0.5 * zoom) : Point2()); float angle = get_global_transform().get_rotation(); if(rotating){ diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 14aa3da85ff..fec9e401f16 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -272,7 +272,7 @@ void LineEdit::_input_event(InputEvent p_event) { if (editable) { selection_delete(); - CharType ucodestr[2]={k.unicode,0}; + CharType ucodestr[2]={(CharType)k.unicode,0}; append_at_cursor(ucodestr); emit_signal("text_changed",text); _change_notify("text"); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 681c33652e1..db8fbf7a63d 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1440,7 +1440,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { } else { //different char, go back - const CharType chr[2] = {k.unicode, 0}; + const CharType chr[2] = {(CharType)k.unicode, 0}; if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { _consume_pair_symbol(chr[0]); } else { @@ -2062,7 +2062,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (readonly) break; - const CharType chr[2] = {k.unicode, 0}; + const CharType chr[2] = {(CharType)k.unicode, 0}; if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { _consume_pair_symbol(chr[0]); diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h index 70fc3e8fcb5..c018ab62248 100644 --- a/servers/physics/collision_object_sw.h +++ b/servers/physics/collision_object_sw.h @@ -34,8 +34,10 @@ #include "self_list.h" #include "broad_phase_sw.h" -#define MAX_OBJECT_DISTANCE 10000000 +#ifdef DEBUG_ENABLED +#define MAX_OBJECT_DISTANCE 10000000.0 #define MAX_OBJECT_DISTANCE_X2 (MAX_OBJECT_DISTANCE*MAX_OBJECT_DISTANCE) +#endif class SpaceSW; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 81862fb3a6d..79365f7db6e 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -863,17 +863,17 @@ public: if (polygon->indices != NULL) { r.pos=polygon->points[polygon->indices[0]]; - for (int i=1; icount; i++) { + for (int i=1; ipoints[polygon->indices[i]]); - }; + } } else { r.pos=polygon->points[0]; - for (int i=1; icount; i++) { + for (int i=1; ipoints[i]); - }; - }; + } + } } break; case CanvasItem::Command::TYPE_CIRCLE: { diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 6556f8bc425..a547da9b61b 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -7281,7 +7281,7 @@ void VisualServerRaster::_draw_viewports() { if (r.size.width==0) r.size.width=window_w; if (r.size.height==0) - r.size.height=window_w; + r.size.height=window_h; _draw_viewport(vp,r.pos.x,r.pos.y,r.size.width,r.size.height); diff --git a/tools/docdump/doc_dump.cpp b/tools/docdump/doc_dump.cpp index d10f6c9ce34..17aff3dc740 100644 --- a/tools/docdump/doc_dump.cpp +++ b/tools/docdump/doc_dump.cpp @@ -65,7 +65,7 @@ static String _escape_string(const String& p_str) { ret=ret.replace(">","<"); ret=ret.replace("'","'"); ret=ret.replace("\"","""); - for (int i=1;i<32;i++) { + for (char i=1;i<32;i++) { char chr[2]={i,0}; ret=ret.replace(chr,"&#"+String::num(i)+";"); diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp index 39eec4e69b1..63ab186a38b 100644 --- a/tools/editor/animation_editor.cpp +++ b/tools/editor/animation_editor.cpp @@ -1375,7 +1375,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { if (p_input.is_action("ui_up")) selected_track--; if (v_scroll->is_visible() && p_input.is_action("ui_page_up")) - selected_track--;; + selected_track--; if (selected_track<0) selected_track=0; diff --git a/tools/editor/editor_file_system.cpp b/tools/editor/editor_file_system.cpp index 94e887c3e71..8e96123c36d 100644 --- a/tools/editor/editor_file_system.cpp +++ b/tools/editor/editor_file_system.cpp @@ -940,19 +940,19 @@ String EditorFileSystem::get_file_type(const String& p_file) const { EditorFileSystemDirectory *EditorFileSystem::get_path(const String& p_path) { if (!filesystem || scanning) - return false; + return NULL; String f = Globals::get_singleton()->localize_path(p_path); if (!f.begins_with("res://")) - return false; + return NULL; f=f.substr(6,f.length()); f=f.replace("\\","/"); if (f==String()) - return filesystem; + return filesystem; if (f.ends_with("/")) f=f.substr(0,f.length()-1); @@ -960,7 +960,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_path(const String& p_path) { Vector path = f.split("/"); if (path.size()==0) - return false; + return NULL; EditorFileSystemDirectory *fs=filesystem; diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp index 64b5d5b3377..3add30d81e4 100644 --- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp @@ -51,6 +51,7 @@ static const char *flag_names[]={ NULL }; +#if 0 // not used static const char *flag_short_names[]={ "Stream", "FixBorder", @@ -65,6 +66,7 @@ static const char *flag_short_names[]={ "Anisoropic", NULL }; +#endif void EditorImportTextureOptions::set_format(EditorTextureImportPlugin::ImageFormat p_format) { diff --git a/tools/editor/plugins/shader_graph_editor_plugin.cpp b/tools/editor/plugins/shader_graph_editor_plugin.cpp index 1db901e56b0..03fcbffa24d 100644 --- a/tools/editor/plugins/shader_graph_editor_plugin.cpp +++ b/tools/editor/plugins/shader_graph_editor_plugin.cpp @@ -539,7 +539,6 @@ void GraphCurveMapEdit::_plot_curve(const Vector2& p_a,const Vector2& p_b,const if ((lastx != newx) || (lasty != newy)) { #if 0 - /* if(fix255) { /* use fixed array size (for the curve graph) */ diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp index f9d92c8d81a..521a10bbd0a 100644 --- a/tools/editor/spatial_editor_gizmos.cpp +++ b/tools/editor/spatial_editor_gizmos.cpp @@ -1257,7 +1257,8 @@ void SkeletonSpatialGizmo::redraw() { //find closest axis int closest=-1; - float closest_d; + float closest_d = 0.0; + for(int j=0;j<3;j++) { float dp = Math::abs(grests[parent].basis[j].normalized().dot(d)); if (j==0 || dp>closest_d) From b89cd136a9ce85d1ecf397e8129897a5bd2dd839 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 01:03:05 +0200 Subject: [PATCH 08/15] fixed ColorRgb attribute init order of struct --- drivers/pvr/ColorRgba.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pvr/ColorRgba.h b/drivers/pvr/ColorRgba.h index 6b46d65e3c9..07014205662 100644 --- a/drivers/pvr/ColorRgba.h +++ b/drivers/pvr/ColorRgba.h @@ -11,21 +11,21 @@ public: ColorRgb() - : r(0) + : b(0) , g(0) - , b(0) { + , r(0) { } ColorRgb(T red, T green, T blue) - : r(red) + : b(blue) , g(green) - , b(blue) { + , r(red) { } ColorRgb(const ColorRgb &x) - : r(x.r) + : b(x.b) , g(x.g) - , b(x.b) { + , r(x.r) { } ColorRgb operator *(int x) { From ac9263c680076eed36887a681cb59fdcce6c6f73 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 01:39:42 +0200 Subject: [PATCH 09/15] clearified parenthesis of if construct --- scene/gui/label.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 1751d335ee9..dac21275dcd 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -433,7 +433,7 @@ void Label::regenerate_word_cache() { } - if ((autowrap && line_width>=width && (last && last->char_pos >= 0 || not_latin)) || insert_newline) { + if ((autowrap && (line_width >= width) && ((last && last->char_pos >= 0) || not_latin)) || insert_newline) { if (not_latin) { if (current_word_size>0) { WordCache *wc = memnew( WordCache ); From 2f4c435bfaf4bf8c9353433ef00eff228169c013 Mon Sep 17 00:00:00 2001 From: yg2f Date: Wed, 6 May 2015 23:08:06 +0200 Subject: [PATCH 10/15] update rtaudio to latest version update rtaudio from latest version availbale on github --- drivers/rtaudio/RtAudio.cpp | 364 ++++++++++++++++++++++-------------- drivers/rtaudio/RtAudio.h | 3 +- 2 files changed, 230 insertions(+), 137 deletions(-) diff --git a/drivers/rtaudio/RtAudio.cpp b/drivers/rtaudio/RtAudio.cpp index 04e7b4422e7..8876f72e21d 100644 --- a/drivers/rtaudio/RtAudio.cpp +++ b/drivers/rtaudio/RtAudio.cpp @@ -46,6 +46,7 @@ #include #include #include +#include // Static variable definitions. const unsigned int RtApi::MAX_SAMPLE_RATES = 14; @@ -63,6 +64,22 @@ const unsigned int RtApi::SAMPLE_RATES[] = { #define MUTEX_DESTROY(A) DeleteCriticalSection(A) #define MUTEX_LOCK(A) EnterCriticalSection(A) #define MUTEX_UNLOCK(A) LeaveCriticalSection(A) + + #include "tchar.h" + + static std::string convertCharPointerToStdString(const char *text) + { + return std::string(text); + } + + static std::string convertCharPointerToStdString(const wchar_t *text) + { + int length = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, NULL, NULL); + std::string s( length-1, '\0' ); + WideCharToMultiByte(CP_UTF8, 0, text, -1, &s[0], length, NULL, NULL); + return s; + } + #elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) // pthread API #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL) @@ -184,7 +201,7 @@ RtAudio :: RtAudio( RtAudio::Api api ) getCompiledApi( apis ); for ( unsigned int i=0; igetDeviceCount() ) break; + if ( rtapi_ && rtapi_->getDeviceCount() ) break; } if ( rtapi_ ) return; @@ -766,9 +783,14 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device ) bool haveValueRange = false; info.sampleRates.clear(); for ( UInt32 i=0; i info.preferredSampleRate ) ) + info.preferredSampleRate = tmpSr; + + } else { haveValueRange = true; if ( rangeList[i].mMinimum > minimumRate ) minimumRate = rangeList[i].mMinimum; if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum; @@ -777,8 +799,12 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device ) if ( haveValueRange ) { for ( unsigned int k=0; k= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) + if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) { info.sampleRates.push_back( SAMPLE_RATES[k] ); + + if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[k]; + } } } @@ -1385,6 +1411,18 @@ void RtApiCore :: closeStream( void ) CoreHandle *handle = (CoreHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { + if (handle) { + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + + property.mSelector = kAudioDeviceProcessorOverload; + property.mScope = kAudioObjectPropertyScopeGlobal; + if (AudioObjectRemovePropertyListener( handle->id[0], &property, xrunListener, (void *) handle ) != noErr) { + errorText_ = "RtApiCore::closeStream(): error removing property listener!"; + error( RtAudioError::WARNING ); + } + } if ( stream_.state == STREAM_RUNNING ) AudioDeviceStop( handle->id[0], callbackHandler ); #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) @@ -1396,6 +1434,18 @@ void RtApiCore :: closeStream( void ) } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) { + if (handle) { + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + + property.mSelector = kAudioDeviceProcessorOverload; + property.mScope = kAudioObjectPropertyScopeGlobal; + if (AudioObjectRemovePropertyListener( handle->id[1], &property, xrunListener, (void *) handle ) != noErr) { + errorText_ = "RtApiCore::closeStream(): error removing property listener!"; + error( RtAudioError::WARNING ); + } + } if ( stream_.state == STREAM_RUNNING ) AudioDeviceStop( handle->id[1], callbackHandler ); #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) @@ -1989,7 +2039,9 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) // Get the current jack server sample rate. info.sampleRates.clear(); - info.sampleRates.push_back( jack_get_sample_rate( client ) ); + + info.preferredSampleRate = jack_get_sample_rate( client ); + info.sampleRates.push_back( info.preferredSampleRate ); // Count the available ports containing the client name as device // channels. Jack "input ports" equal RtAudio output channels. @@ -2769,8 +2821,12 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device ) info.sampleRates.clear(); for ( unsigned int i=0; i info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[i]; + } } // Determine supported data types ... just check first channel and assume rest are the same. @@ -2829,9 +2885,12 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ) -{ +{//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool isDuplexInput = mode == INPUT && stream_.mode == OUTPUT; + // For ASIO, a duplex stream MUST use the same driver. - if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] != device ) { + if ( isDuplexInput && stream_.device[0] != device ) { errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!"; return FAILURE; } @@ -2845,7 +2904,7 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } // Only load the driver once for duplex stream. - if ( mode != INPUT || stream_.mode != OUTPUT ) { + if ( !isDuplexInput ) { // The getDeviceInfo() function will not work when a stream is open // because ASIO does not allow multiple devices to run at the same // time. Thus, we'll probe the system before opening a stream and @@ -2866,22 +2925,26 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } } + // keep them before any "goto error", they are used for error cleanup + goto device boundary checks + bool buffersAllocated = false; + AsioHandle *handle = (AsioHandle *) stream_.apiHandle; + unsigned int nChannels; + + // Check the device channel count. long inputChannels, outputChannels; result = ASIOGetChannels( &inputChannels, &outputChannels ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ")."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) || ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ")."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } stream_.nDeviceChannels[mode] = channels; stream_.nUserChannels[mode] = channels; @@ -2890,30 +2953,27 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne // Verify the sample rate is supported. result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ")."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } // Get the current sample rate ASIOSampleRate currentRate; result = ASIOGetSampleRate( ¤tRate ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } // Set the sample rate only if necessary if ( currentRate != sampleRate ) { result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ")."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } } @@ -2924,10 +2984,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne else channelInfo.isInput = true; result = ASIOGetChannelInfo( &channelInfo ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } // Assuming WINDOWS host is always little-endian. @@ -2956,10 +3015,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } if ( stream_.deviceFormat[mode] == 0 ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } // Set the buffer size. For a duplex stream, this will end up @@ -2968,49 +3026,63 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne long minSize, maxSize, preferSize, granularity; result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } - if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; - else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; - else if ( granularity == -1 ) { - // Make sure bufferSize is a power of two. - int log2_of_min_size = 0; - int log2_of_max_size = 0; + if ( isDuplexInput ) { + // When this is the duplex input (output was opened before), then we have to use the same + // buffersize as the output, because it might use the preferred buffer size, which most + // likely wasn't passed as input to this. The buffer sizes have to be identically anyway, + // So instead of throwing an error, make them equal. The caller uses the reference + // to the "bufferSize" param as usual to set up processing buffers. - for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) { - if ( minSize & ((long)1 << i) ) log2_of_min_size = i; - if ( maxSize & ((long)1 << i) ) log2_of_max_size = i; - } + *bufferSize = stream_.bufferSize; - long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) ); - int min_delta_num = log2_of_min_size; - - for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) { - long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) ); - if (current_delta < min_delta) { - min_delta = current_delta; - min_delta_num = i; - } - } - - *bufferSize = ( (unsigned int)1 << min_delta_num ); - if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; + } else { + if ( *bufferSize == 0 ) *bufferSize = preferSize; + else if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; - } - else if ( granularity != 0 ) { - // Set to an even multiple of granularity, rounding up. - *bufferSize = (*bufferSize + granularity-1) / granularity * granularity; + else if ( granularity == -1 ) { + // Make sure bufferSize is a power of two. + int log2_of_min_size = 0; + int log2_of_max_size = 0; + + for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) { + if ( minSize & ((long)1 << i) ) log2_of_min_size = i; + if ( maxSize & ((long)1 << i) ) log2_of_max_size = i; + } + + long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) ); + int min_delta_num = log2_of_min_size; + + for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) { + long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) ); + if (current_delta < min_delta) { + min_delta = current_delta; + min_delta_num = i; + } + } + + *bufferSize = ( (unsigned int)1 << min_delta_num ); + if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; + else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; + } + else if ( granularity != 0 ) { + // Set to an even multiple of granularity, rounding up. + *bufferSize = (*bufferSize + granularity-1) / granularity * granularity; + } } - if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize ) { - drivers.removeCurrentDriver(); + /* + // we don't use it anymore, see above! + // Just left it here for the case... + if ( isDuplexInput && stream_.bufferSize != *bufferSize ) { errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!"; - return FAILURE; + goto error; } + */ stream_.bufferSize = *bufferSize; stream_.nBuffers = 2; @@ -3022,16 +3094,13 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne stream_.deviceInterleaved[mode] = false; // Allocate, if necessary, our AsioHandle structure for the stream. - AsioHandle *handle = (AsioHandle *) stream_.apiHandle; if ( handle == 0 ) { try { handle = new AsioHandle; } catch ( std::bad_alloc& ) { - //if ( handle == NULL ) { - drivers.removeCurrentDriver(); errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory."; - return FAILURE; + goto error; } handle->bufferInfos = 0; @@ -3046,15 +3115,14 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne // Create the ASIO internal buffers. Since RtAudio sets up input // and output separately, we'll have to dispose of previously // created output buffers for a duplex stream. - long inputLatency, outputLatency; if ( mode == INPUT && stream_.mode == OUTPUT ) { ASIODisposeBuffers(); if ( handle->bufferInfos ) free( handle->bufferInfos ); } // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure. - bool buffersAllocated = false; - unsigned int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1]; + unsigned int i; + nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1]; handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) ); if ( handle->bufferInfos == NULL ) { errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ")."; @@ -3075,18 +3143,37 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne infos->buffers[0] = infos->buffers[1] = 0; } + // prepare for callbacks + stream_.sampleRate = sampleRate; + stream_.device[mode] = device; + stream_.mode = isDuplexInput ? DUPLEX : mode; + + // store this class instance before registering callbacks, that are going to use it + asioCallbackInfo = &stream_.callbackInfo; + stream_.callbackInfo.object = (void *) this; + // Set up the ASIO callback structure and create the ASIO data buffers. asioCallbacks.bufferSwitch = &bufferSwitch; asioCallbacks.sampleRateDidChange = &sampleRateChanged; asioCallbacks.asioMessage = &asioMessages; asioCallbacks.bufferSwitchTimeInfo = NULL; result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks ); + if ( result != ASE_OK ) { + // Standard method failed. This can happen with strict/misbehaving drivers that return valid buffer size ranges + // but only accept the preferred buffer size as parameter for ASIOCreateBuffers. eg. Creatives ASIO driver + // in that case, let's be naïve and try that instead + *bufferSize = preferSize; + stream_.bufferSize = *bufferSize; + result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks ); + } + if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") creating buffers."; errorText_ = errorStream_.str(); goto error; } - buffersAllocated = true; + buffersAllocated = true; + stream_.state = STREAM_STOPPED; // Set flags for buffer conversion. stream_.doConvertBuffer[mode] = false; @@ -3109,11 +3196,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); - if ( mode == INPUT ) { - if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { - unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); - if ( bufferBytes <= bytesOut ) makeBuffer = false; - } + if ( isDuplexInput && stream_.deviceBuffer ) { + unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); + if ( bufferBytes <= bytesOut ) makeBuffer = false; } if ( makeBuffer ) { @@ -3127,18 +3212,8 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } } - stream_.sampleRate = sampleRate; - stream_.device[mode] = device; - stream_.state = STREAM_STOPPED; - asioCallbackInfo = &stream_.callbackInfo; - stream_.callbackInfo.object = (void *) this; - if ( stream_.mode == OUTPUT && mode == INPUT ) - // We had already set up an output stream. - stream_.mode = DUPLEX; - else - stream_.mode = mode; - // Determine device latencies + long inputLatency, outputLatency; result = ASIOGetLatencies( &inputLatency, &outputLatency ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency."; @@ -3158,32 +3233,38 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne return SUCCESS; error: - if ( buffersAllocated ) - ASIODisposeBuffers(); - drivers.removeCurrentDriver(); + if ( !isDuplexInput ) { + // the cleanup for error in the duplex input, is done by RtApi::openStream + // So we clean up for single channel only - if ( handle ) { - CloseHandle( handle->condition ); - if ( handle->bufferInfos ) - free( handle->bufferInfos ); - delete handle; - stream_.apiHandle = 0; - } + if ( buffersAllocated ) + ASIODisposeBuffers(); - for ( int i=0; i<2; i++ ) { - if ( stream_.userBuffer[i] ) { - free( stream_.userBuffer[i] ); - stream_.userBuffer[i] = 0; + drivers.removeCurrentDriver(); + + if ( handle ) { + CloseHandle( handle->condition ); + if ( handle->bufferInfos ) + free( handle->bufferInfos ); + + delete handle; + stream_.apiHandle = 0; + } + + + if ( stream_.userBuffer[mode] ) { + free( stream_.userBuffer[mode] ); + stream_.userBuffer[mode] = 0; + } + + if ( stream_.deviceBuffer ) { + free( stream_.deviceBuffer ); + stream_.deviceBuffer = 0; } } - if ( stream_.deviceBuffer ) { - free( stream_.deviceBuffer ); - stream_.deviceBuffer = 0; - } - return FAILURE; -} +}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RtApiAsio :: closeStream() { @@ -3635,12 +3716,12 @@ public: outIndex_( 0 ) {} ~WasapiBuffer() { - delete buffer_; + free( buffer_ ); } // sets the length of the internal ring buffer void setBufferSize( unsigned int bufferSize, unsigned int formatBytes ) { - delete buffer_; + free( buffer_ ); buffer_ = ( char* ) calloc( bufferSize, formatBytes ); @@ -3799,7 +3880,7 @@ void convertBufferWasapi( char* outBuffer, float sampleStep = 1.0f / sampleRatio; float inSampleFraction = 0.0f; - outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio ); + outSampleCount = ( unsigned int ) roundf( inSampleCount * sampleRatio ); // frame-by-frame, copy each relative input sample into it's corresponding output sample for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ ) @@ -3945,7 +4026,6 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) RtAudio::DeviceInfo info; unsigned int captureDeviceCount = 0; unsigned int renderDeviceCount = 0; - std::wstring deviceName; std::string defaultDeviceName; bool isCaptureDevice = false; @@ -4048,8 +4128,7 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) goto Exit; } - deviceName = defaultDeviceNameProp.pwszVal; - defaultDeviceName = std::string( deviceName.begin(), deviceName.end() ); + defaultDeviceName = convertCharPointerToStdString(defaultDeviceNameProp.pwszVal); // name hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore ); @@ -4066,8 +4145,7 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) goto Exit; } - deviceName = deviceNameProp.pwszVal; - info.name = std::string( deviceName.begin(), deviceName.end() ); + info.name =convertCharPointerToStdString(deviceNameProp.pwszVal); // is default if ( isCaptureDevice ) { @@ -4110,6 +4188,7 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) { info.sampleRates.push_back( SAMPLE_RATES[i] ); } + info.preferredSampleRate = deviceFormat->nSamplesPerSec; // native format info.nativeFormats = 0; @@ -5245,14 +5324,11 @@ unsigned int RtApiDs :: getDeviceCount( void ) error( RtAudioError::WARNING ); } - // Clean out any devices that may have disappeared. - std::vector< int > indices; - for ( unsigned int i=0; i(dsDevices.size()); } @@ -5308,8 +5384,12 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device ) info.sampleRates.clear(); for ( unsigned int k=0; k= (unsigned int) outCaps.dwMinSecondarySampleRate && - SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) + SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) { info.sampleRates.push_back( SAMPLE_RATES[k] ); + + if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[k]; + } } // Get format information. @@ -6264,6 +6344,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6271,6 +6352,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6279,6 +6361,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6286,6 +6369,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6307,6 +6391,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6399,6 +6484,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6412,6 +6498,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6448,6 +6535,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6509,6 +6597,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6523,6 +6612,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6544,6 +6634,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6582,21 +6673,6 @@ static unsigned __stdcall callbackHandler( void *ptr ) return 0; } -#include "tchar.h" - -static std::string convertTChar( LPCTSTR name ) -{ -#if defined( UNICODE ) || defined( _UNICODE ) - int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL); - std::string s( length-1, '\0' ); - WideCharToMultiByte(CP_UTF8, 0, name, -1, &s[0], length, NULL, NULL); -#else - std::string s( name ); -#endif - - return s; -} - static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, LPCTSTR description, LPCTSTR /*module*/, @@ -6638,7 +6714,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, } // If good device, then save its name and guid. - std::string name = convertTChar( description ); + std::string name = convertCharPointerToStdString( description ); //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" ) if ( lpguid == NULL ) name = "Default Device"; @@ -6820,6 +6896,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device ) // Count cards and devices card = -1; + subdevice = -1; snd_card_next( &card ); while ( card >= 0 ) { sprintf( name, "hw:%d", card ); @@ -7033,8 +7110,12 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device ) // Test our discrete set of sample rate values. info.sampleRates.clear(); for ( unsigned int i=0; i info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[i]; + } } if ( info.sampleRates.size() == 0 ) { snd_pcm_close( phandle ); @@ -7959,6 +8040,8 @@ void RtApiAlsa :: callbackEvent() errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after underrun, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } + else + errorText_ = "RtApiAlsa::callbackEvent: audio write error, underrun."; } else { errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << "."; @@ -8067,6 +8150,7 @@ RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ ) for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr ) info.sampleRates.push_back( *sr ); + info.preferredSampleRate = 48000; info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32; return info; @@ -8429,7 +8513,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, pah = static_cast( stream_.apiHandle ); int error; - if ( !options->streamName.empty() ) streamName = options->streamName; + if ( options && !options->streamName.empty() ) streamName = options->streamName; switch ( mode ) { case INPUT: pa_buffer_attr buffer_attr; @@ -8635,6 +8719,10 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device ) for ( unsigned int k=0; k info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[k]; + break; } } @@ -8643,8 +8731,12 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device ) else { // Check min and max rate values; for ( unsigned int k=0; k= (int) SAMPLE_RATES[k] ) + if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] ) { info.sampleRates.push_back( SAMPLE_RATES[k] ); + + if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[k]; + } } } diff --git a/drivers/rtaudio/RtAudio.h b/drivers/rtaudio/RtAudio.h index 1f1b63072c8..7d45d365297 100644 --- a/drivers/rtaudio/RtAudio.h +++ b/drivers/rtaudio/RtAudio.h @@ -310,12 +310,13 @@ class RtAudio bool isDefaultOutput; /*!< true if this is the default output device. */ bool isDefaultInput; /*!< true if this is the default input device. */ std::vector sampleRates; /*!< Supported sample rates (queried from list of standard rates). */ + unsigned int preferredSampleRate; /*!< Preferred sample rate, eg. for WASAPI the system sample rate. */ RtAudioFormat nativeFormats; /*!< Bit mask of supported data formats. */ // Default constructor. DeviceInfo() :probed(false), outputChannels(0), inputChannels(0), duplexChannels(0), - isDefaultOutput(false), isDefaultInput(false), nativeFormats(0) {} + isDefaultOutput(false), isDefaultInput(false), preferredSampleRate(0), nativeFormats(0) {} }; //! The structure for specifying input or ouput stream parameters. From 93095014fd87f1a33bdeaeb1f05eaab9342320bc Mon Sep 17 00:00:00 2001 From: "Daniel T. Borelli" Date: Wed, 6 May 2015 20:37:25 -0300 Subject: [PATCH 11/15] Fix segment violation MINIZIP_ENABLED --- core/io/file_access_pack.cpp | 4 +++- main/main.cpp | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index bf1211f2b31..339a6d0528a 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -92,7 +92,9 @@ void PackedData::add_path(const String& pkg_path, const String& path, uint64_t o void PackedData::add_pack_source(PackSource *p_source) { - sources.push_back(p_source); + if (p_source != NULL) { + sources.push_back(p_source); + } }; PackedData *PackedData::singleton=NULL; diff --git a/main/main.cpp b/main/main.cpp index aa4a4b89190..1469ce4618e 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -251,7 +251,14 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas packed_data = memnew(PackedData); #ifdef MINIZIP_ENABLED + + //XXX: always get_singleton() == 0x0 zip_packed_data = ZipArchive::get_singleton(); + //TODO: remove this temporary fix + if (!zip_packed_data) { + zip_packed_data = memnew(ZipArchive); + } + packed_data->add_pack_source(zip_packed_data); #endif @@ -748,10 +755,12 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas if (file_access_network_client) memdelete(file_access_network_client); -#ifdef MINIZIP_ENABLED - if (zip_packed_data) - memdelete( zip_packed_data ); -#endif +// Note 1: *zip_packed_data live into *packed_data +// Note 2: PackedData::~PackedData destroy this. +//#ifdef MINIZIP_ENABLED +// if (zip_packed_data) +// memdelete( zip_packed_data ); +//#endif unregister_core_types(); From ead2dd3db59d22b013da608c002e31603be16169 Mon Sep 17 00:00:00 2001 From: Nicolas Laurito Date: Wed, 6 May 2015 23:53:20 -0300 Subject: [PATCH 12/15] Delete line without functionality --- demos/2d/kinematic_char/player.gd | 2 -- 1 file changed, 2 deletions(-) diff --git a/demos/2d/kinematic_char/player.gd b/demos/2d/kinematic_char/player.gd index ddc0271de08..329382408bf 100644 --- a/demos/2d/kinematic_char/player.gd +++ b/demos/2d/kinematic_char/player.gd @@ -34,8 +34,6 @@ func _fixed_process(delta): #create forces var force = Vector2(0,GRAVITY) - - var stop = velocity.x!=0.0 var walk_left = Input.is_action_pressed("move_left") var walk_right = Input.is_action_pressed("move_right") From 48afa1d2847bdf7d23c21a76494c4789d3bdc9e1 Mon Sep 17 00:00:00 2001 From: hurikhan Date: Wed, 6 May 2015 23:07:11 -0400 Subject: [PATCH 13/15] window_management input fix --- demos/misc/window_management/control.gd | 10 +++++++++- .../window_management/window_management.scn | Bin 5129 -> 5132 bytes 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/demos/misc/window_management/control.gd b/demos/misc/window_management/control.gd index 5eb58176196..1609dda6996 100644 --- a/demos/misc/window_management/control.gd +++ b/demos/misc/window_management/control.gd @@ -1,6 +1,8 @@ extends Control +var mousepos + func _fixed_process(delta): var modetext = "Mode:\n" @@ -31,7 +33,7 @@ func _fixed_process(delta): get_node("Label_Size").set_text(str("Size:\n", OS.get_window_size() ) ) - get_node("Label_MousePosition").set_text(str("Mouse Position:\n", Input.get_mouse_pos() ) ) + get_node("Label_MousePosition").set_text(str("Mouse Position:\n", mousepos ) ) get_node("Label_Screen_Count").set_text( str("Screen_Count:\n", OS.get_screen_count() ) ) @@ -126,6 +128,12 @@ func check_wm_api(): func _ready(): if( check_wm_api() ): set_fixed_process(true) + set_process_input(true) + + +func _input(ev): + if (ev.type==InputEvent.MOUSE_MOTION): + mousepos = ev.pos func _on_Button_MoveTo_pressed(): diff --git a/demos/misc/window_management/window_management.scn b/demos/misc/window_management/window_management.scn index c7d6260df620d50d0960fb0dcf6e8df43db9eadc..8db43b6638bc3aac053622591dacb4f0d6893eb4 100644 GIT binary patch delta 2243 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 b^2#fE)=^O=|8mv|5rcOM{egau`8Vm`iIS^+ From 786b5e3545ea45557c699d74732d62cbcb2337a0 Mon Sep 17 00:00:00 2001 From: yg2f Date: Thu, 7 May 2015 18:10:30 +0200 Subject: [PATCH 14/15] fixes_demo3d_shaders_materials_missing_light add the missing animated light to the demo 3d "shaders materials" --- .../3d/shader_materials/shader_materials.scn | Bin 5494 -> 6382 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/demos/3d/shader_materials/shader_materials.scn b/demos/3d/shader_materials/shader_materials.scn index d6a3efe73f74c8beb0118f2ebb420da894fbc4da..243c6c8f06b728ecc2e990f872d2aeecb70799ee 100644 GIT binary patch literal 6382 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 I(|fCOen(%4oaX;h8m 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 RJ3Bl3b`0+b?4TRh{{|-VYX<-T From 32c0a962491fd6d4125688b03b33efda20f5600d Mon Sep 17 00:00:00 2001 From: yg2f Date: Thu, 7 May 2015 18:29:38 +0200 Subject: [PATCH 15/15] add_missing_textures_to_particles --- demos/3d/platformer/coin.scn | Bin 6013 -> 6791 bytes demos/3d/platformer/enemy.scn | Bin 36976 -> 37784 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/demos/3d/platformer/coin.scn b/demos/3d/platformer/coin.scn index 449bb0f89589a0b122bc635c9d84b97d268f98ce..a4148b406079a3cdd922232a5980d4feb280365e 100644 GIT binary patch literal 6791 zcmYjW3wRsVl|J*3WP5DOZ`pAYUs<;EFtHLlw#ftQjAYpf2@ql^g^+4S(pVlMOF|<% zaVRhlT38+*3xTqMB~_A^0O2dkqdXQ!l%%{vSPJD4_+UiZZh;i~TG*DB>=`BOSAE~P zbI-Zw-np+i=lnDJK^a7NX0sMgIAs4_x9)JTdIpCNR1q7&MV%0h|wn>YR z#k7&efO1woSsTREvu|eXz58Um!0uX>xLesVMNxz8{=D)K{1n5XZ$E~ zP|X@Evzn2f%EmN*N}be{8An!)>r;j@+iAqIdM4*Lol31Zo>UWt1>eDY&00R5o?;0{ z#L(kf+~S+c_0+VM%|*u57`qSLEM+bdr&7j*iVL91f;v|^70IPD&}2bPSyE3-=Z1p^nXRX4I@YY53W7&Qv@ynT~6g&{!VVGP#LJ zJgaWDxul-bBAfMiZo-@v^(|UFlFyeLT0~7|CRCWsHdw9}X7cH5MA^nct5wk^X3}~p z=aq!58qBhsbDeSBh^g6l{!*A@Ip^TCuw^Ea@_xptN%pncn}1J;>*M3Bje{E2m#-6z zj24^nN|sPB(qF9*ztjC2xw*^f_=zvCVjaAlYmGu-MV2M42M(hdhw#rB4OQ6N7R9OoSgpw8vsNT>6 zmRO5j@`n~QTyvx4_^nCfSmG}Ard>Bevn5_HKVdfGQjl0HZ_rJ+jq@*77D}-xBbT0x zsA@Fow|FUD={pw^?M`s8elD5z{TRyxBd2A|qmbsMYa_D&nZ&bE&A5c9nmeU6Jn zSv4d(eiMEO%Df)9;M#)#`1|&kxaEFtw&P;1C)0Uz_+=Q=hSj;|Ts)iaNyN?BN?d)# zoNaNFLeFM(T2aC$#AG@~XL||182WIG0bL`035;14jeIXW5=z;UZoUtqp|(?vOJNHC ze5%?H?+4?jssnIwP(4*0gpcx#qjSr~G80->8=Fwun@5h}f|2Wla%X-hR1PEIBzKP5 zUI%)+1q<04><6B?aM4IpLBd5SA&kfcNlq1{&}!mV;0GlCrF zhR_rK0zH-k1T!!fEVz}E+bocXqh)Z9fj3VRfp#Y54{!k=lkgp4JD6yCNTn05@c=Lh zz!Je~baP!`eogK3m{`~V^O+>q6Ssgk53Nw5vb$8CQ7RXe%AQi`FO`e!a`kzn*K6?} z=qm}AQt5|&yFR>2I7c%kl$zj4tO?C|;CvWh-SS~v$-O?hb_1gCJ*h# z%j7SELpVFQTbxX1GZQzsI0Hx>a5j$dnXJCxc3z*>lpEwbsml!$XPS#KDi`2Pwv1g| zd0==?X#cMs+jv0twm*)N>zk8TANcFZlS3%MJIo`#_1MM$G9Nnu2ha^eOcMWb^5lN- zz6HyeBz)!H`#9~(0hIVxp8w42=gq(X^YHHucD0L~Nn-ejnm=Hpu!MQaPPA?hyi0GQ z1;Zbh#Gc{;v^o5{|8tP}IeQRzpT=z8`Dq7A!XH}S4B)N8-`8y%!a>|ijVIY&w3Xgw z=iy!f&fhr1zEt+oZIa-d{9bUEHv@Qo%g5hI{Df?Cu}ZsqQ61<|*tY z%TF_)J`J?p)JDUxn>Tin(jVAfOL)u@?DO7ESI zNqn`qunsNxLYfWW*~J6TrT*aEBq?)m$XULR- zcLdvt&R1}jRr@f`L4XiBpp|%=xeta}ZDAj-54$1E>I?f|gh|$#efWcL!bR~Tg=n#~ zZw1!jzkST$@GIs$ zw&WG`;5(sxr57ACeH;YB9~V5~W2T2%!yn7Gh5LVxHsZvu(FhJXFR&x9tfr=`DKK8{ z_Zt%wWcFlIiSeGo75EHUVxUEM!k-pABRo+BQ613`(Fn;uC;HNMY%Ft1@@-4-yvi|( zYm(YpJ(^XsGs-70%EIz{*cp5pU0gi6Ypq!qJR)ZFTx=rW2ep9H?&Jb)k5i6@G;R8LX=Vts$1=|^FtJYJQshr;q$TNCulZs8DIOm#gH`d7ux8~(-Z9@eakDdkvaan}TIBy=F^iG-FlhxiP^ z1I0;5AxpSH-6NLBLi)1=RA*UFHT7FuKMeoSF6^V;$qa83a{-8*{JDtVK;hV{^ zr}P}FZogmt%ReELMXpGMP>vdjsFw>iT=LcpZ>_Lnht(+~r>0`per3T6f}f(kj)&!4 z4gx+})==Kz2_3OjkS%f-L92HkMaJ`$_-`!k`0!O0%oSs*k&Ad+2T))!HYpJ;9xX$;BimV!mO(h8es9CG5zun_VM$-f^ zEQdycI~SR;9L>&CD8}$gpiOMG;HuphixE8)QQ0Ojn@&&CE8ga&4EE&w)y{aNgqU;+ z-iIu{*%={(5YglMeLjJkAPlFzgk?^@u}Mp6xdl&!>Oo!b0>DVkC-6F~Q+GyRh77BK zsPD20eSF_pbdTk0{gZIbRDCqvv9rGyIo%f*Z|h zy&h*QSi`HaocHI^V;0og7)XmpU$QurY}d7dI+aUf7rD<+I+^tSgioi&Vyi(VV&N4+JDD|Q=vy7dyRu9NTF^5&1~TP8C6c={g)jFL#-~%7RR%iw$*zh zpN{M7rqzEvg>QX=xr6mZpNO8|)XCWAXII(SE0+t6$)ftXazm_)(XrqGh_t5!EtNA8 z>*zeWsOtS2H?8@C>?w7r1+!wG&^yFE$HYjA?mfFQbSqop8*;?b>1^CkYS>_V+rmS9 zdMX#KE1OochCiu~YuKPpD7EAu=p%|Ny^1@(LAgSyfn?XqoSMZulmkk=54ovizClhZ z4f*-BQ8BjAf<~Tj^!)w##;~MxcMRt1@L8n};$2?3&w^#3cifH3c|+fNZ9wVb$MqCD zSE&!ZrPLP|upeZ6b6)moZ%pq`L%O`*}AQ=uN}3p69Ano3aqpt8{9n$T?g4$b7G$|I$V5Fz}`x-n>j zcmmo4ybaCp$H*n*l%P`MiY)eL(gswsV8N~QSiBdOSWder^HT6nH3ENL=(B5mc`t}; zvq(t_XkadWj4nqtjCs4tliIq{mkYJb<361jm`*3BCbdXBs=S$RIBhjQ1!i&G4mFq4 zQd8{Qs&vXfNgo!0eA^aSwLVVWVm12;A%_jv3G#EBPT_bqQB4jkrTODpg07$e9hRF} z{M{7nTI@{PjD*))mYm5c8;8`1Qb-D2N$vnF%;xU(qsvWfJ{S*Yc%IOB`D&1w6 z%PL_ZMIud1C;%R$IMNJ!i^6y?uRwD3g`0ve7wWCHi==^T>Q-L0sXlRMF>eHO>>zw%qz3FY??g~e4vz7Q0s-;D}FeH z?G#CEC6lN$oC=z1xC+P*Dm_?5Jd;ttIk>~TkkgXvLi*S((ZEH@9P%xC+!9;3M##5V zaEl{7K5l5a{8sa(5GX@}F_GSEm51aHmAU!lI7$0@kNhE@9yjuy;Em=R1c!H(TjCD+ zLg>5ZLR4@SUN4ZXOoqpCDVcC(1ONT^nCiuLe(Sh;-3v68zlE>{zt4}Srxh1lr_^KK zIjw7($>Z(`lY?&#&cpuD_%BptHh*H>&y*NA*)VLuE0jjT|JvG>*n^EgcD9lK)e%&; z<1nQODZgV2u- z&*37IT|bQ7c<33NF}(EQ&k9^vjCEkpMBKjB0F z@@vNhh1J0ilorai>78#|q82>NZ%t`?J{ghmNv?`=3_Aonx2N>dduNB%vnP~CLicl# zEwK@P`N-w5w?}4v3#+*7ROfbH%jFi%d0{kkFOJ}y72hVJvI&DW_ON47l64p{-|v*# z&>#*MVI>VX^xMjZAvS*(q`DqP_LIMiCY`qwTF;uPS?yg|1+deo?=>&~^?y*7WC-h7 zYt3_iTHN%gnR$H01QTvTl zH@dyb&2;x>L+L9lcT3g36wZ2oaYLZywf9%bDbLaJJNH+X-M_y$bJzZ(<&A;LviX7H zj3+g0shjEM|9WMu;wd~tU&yoa^%%2{sbF#Rm{)BI*v8+zV@G?MYHm6o@Z~Gb z|D^yHUGk;4K|VA1B7m|DuQvs&yuL8cRxy<|RK66%F?uWw(RW@b6b=WU!xz!D`Zr)~ zS_q@wJ#aD)tU>{-Ub_=-qb1#ot$04xW0+_)x<;PE)>Us~Yw&uaUD&qjPD1%r=ngHx z?$DdqEuW9w;ScHg046Bf>|6Dp*hg<)g>nn-qy3|B9V56ecrBH8VJmppY(oB3p*q|g z{u={3FU(Jyo-Y3wl#mm&j?|9@O8qME_~fy z<9xD(^O!(U_*b|YO9?03vt|Ptlx`w`2m~!L+{LxQ+Y;wDO*Ztt2!YuiKzc^QdM z(y}T^g{Nk~FMwlZK*2HyoYLKI_ z;}`OSaaB|Q(bnG=8&sE#FID^d7xxZoOBOF)7VRBaGO)Ne*4L-?YaF;(04OO_t$v$W zh?M>=QT{~V*3A}IOUtZ-dbX&R0-@ZuIPBEFE6R(q4*+*_S0^(UF8^+ET593~O2PZ}6h+>X5>GPui9mT```~^h8+wcUyWd-zX;a zJ$6=F1SwySpd}`J+Tp?-@>vM0<=SDjRI<9_3GeMwV$c@fQGOwfjE46p_eRb*GJH>F z#5ZBX2l$HZt`ozVsQQsDG^%IRL$<3H=i^=*8m3?#)O!uPq~0#+oPwb3=q%J@r~HXs zx=s#5vt6#SX6(%dbQ^j#Z{VM7M>V!9U)fMMF=jhI%+W%&z-v*2AlF4~eYZgk_ACBpoCRtiC-Ijo^w({0LLbUZek-rtf5mo^S z|J$L*l{4bH;2^J!z2tjIT-nuy3x&@4+9nuOL+Z9%i!E$n-r&d1fut7aH}3nhwk_Y` z{~>VZ!ykmcq8<8w#deC_;0t}ifX-iB42oS=FD`-XGkC1nv_R~EHG%4Dy-VSE;LdBs zW$>bM^R;3x7TRJXETR`Q(na*pLS574?rFVvS}&Q_ zJ=1zA^JHo0vgt~1Q3qd^HgjuO`@4V#s{-?WvKW@L1@gaO14_z|<0mD{Ff-~>1Z>9D zkUV=5?^Hzj9-O6|bR-QkJ$&$-V1fKT4VZ<4V%pT_of7p?t{#;irYZNu|2Nl-5&1l< zVAr!-%U=y1pDZ{BgjLU#xvmP!ZV~wC88ErR*6#$V4h3#D5^)ywaX#gvkgJP=W zxN!dbnpNZ$-HPcN)e<8dRb zUT4PCQkI^@$H7vc#Z7crhfu;+Mw-bM{QrPkoSDPgGa;w2{!W-m!xu+nVxC4tkM z&vIOQ$;;)R;BA)}$6fgPrB05$62S9knL`EJSt&gK8s0YLtoZ3~Y10_|sQzmd8yu&Q zliaLjxS7?p1drn;?8M`tg9T4$KhhNoO_FX6Jvd!HOs$WR{J*ENfqDkheK~RSCXHkC>V{uC9RWdKOe3K~Sq7Vn$!t3Qi?UPSEM1s zOll7i)H?KdoSV6|p0pO_VS`}T)MFEUC2><5)idMabn8u!QLRF?ILf1u%lS&xBgA-U zE{sRFJLuLJCYA>tr7M-vGps^L#kKvDsTmDfvB(pAhqPao7jNl6%F1Y|CX z5=PW_OkUz7j=)Vzy(kisVC&uA5Q!kPcvlm~wC{{uw1vw`+J-rfsAgrt-ew{TWAWeF z(Bv|Cl+%^Xw}53km$lb9<2)SUasNu?V%8RxsZAmQx$SHy`Gzdm&VB+tAv|t7n+Ru% z;BT>yfe+nmLpXn_Jglb()DvOTFp^g6x4sp^FmaejFK8Wu+RERE$T`%g>>1llL% z&vO-ghw`~C1nK^LCTSxX1NBH&3K)rm_eIf24MxrcGTsM#Z-zFW{hMGv+|1g%UA{ZS zP)cLl!OVRmYLSR`8hEbG)s@yph>_sL@F026C)vU*$B@bSUhiqqi0SNbf5XqE+)>sO zSrE|#Eg6mW&o8o%Oh$PV|4rMc-WR!>ksa|>2>T}_p2}FU({unrL}L#Kquh6z{eyPI zhMCb_v{}dTt&VVtT!`Hre1|ReJ?D%Xh8eTeDz+Rl+IK`_=}0EJtz=X)t*(SV#I?ue zVYS+65gXHD>Jqgwzf=8|S_O%=MnNM+r@pGz`d*m4TG^zwx8>`DIdwtnGx-{PMXiBY zTbtZt!}Xy1D{-Z0>3jEIRNKWNJ;k=DwSfV(wlI(VKuB3UUbSXQ>Q$?LTCVv*6>9yItM}SE-d?#$ZI}|9 zY_W36(Ik(%uQ9vyu-Cb$J()uRbs{Pq@Ulb|taIY|!ZhcqO5`(@w zXg5#3v)+`_nyL8@xJHe{NRo#;&f%}~b@A7qkT&hjHwap$^;sBUTO=dZm2A5~i0OZw zu`62zZI9j5S_t?nAf2qq?*{&}_JtgHTNvX0LtrI;Z8g4CbA2Eut3Tp>sYEuR#s}8Jd}=F&ySGJ!53ea5^y(r<+SLCc~|8 z*mhh;cza!b8}{K{*as!7!4(}bP4a4W5TVfMyq1PcwBf_p2o;RXdA|^ksrC4Pu!K19 zEx1tHOCdo0l+2Lp!z%oP(-^X#3=rgvxkg&Ehnl}fBwCWPdxtbr?V*uh1ZZTRIAn~f zZV}*3wH7zJMs+@xHq2wc!Zy4NF4l_6#b1zAWjKB^5(jCY+$FwQp--wsNJ!8aBqlae|77o-H&7Ewx!ROx-`jcC;w# z#l0zh{HEXp9t>Xj00M$J;zuW+&LDrLC~sf~-dYwNu`))I5~jFCW;$51D8c+zF)dZA z14#_p@JsrPwI7r}<%m)kOZlHd_M|hk$NfN|WzBfiz*=18dEBa9lDq4J$rJT$3N)}P zxsIl|1N#8{=|U@}3Lb3fFQ+!*IYcD9Yw&(zDNEsN_pEqZTJwH)U0>CO_g4q@O?n!d zv-aGrGz7%Y@2*zeg(vYLd|p0?(W2D~wjc>07bKi3J$m%$S}IhM&7d`3j(;L=?nAeH zJMNTMKpo}5pkBsKYzt$cxxg+jE47B-i3c2?dE zvuXIj;-2TSa^?HDpXPQTfR_>D0Uvc9moMNc@Y5P6i2l1tw@>SiqNa)KKShala}bxy zgT(y(a+G+#8ykyjE@0)<*&`do1wVs@tdaC0>im+j0JoiWucADlmPV|C)y#vdSepouKmrd*5X}z4el^w8x#&p5;)Uq2^l0FPX zqUA^MH8R2)`T%$E1bNI!qGAX+cOd(H`a~sPNwn3i9EKoSBSb6Ag?`cokv_M44%Sn- z5eBGl1Ib2`O(dI1wvcQk*+y~$$##-Kk{d~GBDtAl2dx|zZh>4DZl$6Dx6yKsz)mWU zLH2g4RKgup$-=Jba=56Amec637nL4g%9kNRws{|-)YStqT9ng-*Iaj)0gm2LhEP(i6!L^@qSyVhO4Yb`DngN%7pdg zhEx4lH(tUw0%HL9gkbXAEE`S-n_biYOqkpjRZ3Q`5@!+&lO0gMg;{*0Fw=F{h?XGc T$=lsMJw1Kf2e$``|8M;t=;*2z diff --git a/demos/3d/platformer/enemy.scn b/demos/3d/platformer/enemy.scn index b3f69af600ac51b66dd7a9350676262d36e693fd..06d725061d6cd52942cecdccf11f3a5339425123 100644 GIT binary patch delta 11323 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 UMMZ^WS<^B*qWCdolbx~u7qC;)ng9R*