summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ISSUE_TEMPLATE.md18
-rw-r--r--core/bind/core_bind.cpp31
-rw-r--r--core/bind/core_bind.h8
-rw-r--r--core/class_db.cpp5
-rw-r--r--core/dvector.h2
-rw-r--r--core/image.cpp2
-rw-r--r--core/input_map.cpp12
-rw-r--r--core/input_map.h2
-rw-r--r--core/io/config_file.cpp5
-rw-r--r--core/io/config_file.h2
-rw-r--r--core/io/resource_format_binary.cpp100
-rw-r--r--core/io/resource_format_binary.h1
-rw-r--r--core/io/resource_import.cpp238
-rw-r--r--core/io/resource_import.h76
-rw-r--r--core/io/resource_loader.cpp145
-rw-r--r--core/io/resource_loader.h9
-rw-r--r--core/math/a_star.cpp18
-rw-r--r--core/math/a_star.h8
-rw-r--r--core/math/audio_frame.h33
-rw-r--r--core/math/bsp_tree.cpp30
-rw-r--r--core/math/bsp_tree.h8
-rw-r--r--core/math/camera_matrix.cpp64
-rw-r--r--core/math/camera_matrix.h24
-rw-r--r--core/math/face3.cpp56
-rw-r--r--core/math/face3.h22
-rw-r--r--core/math/geometry.cpp22
-rw-r--r--core/math/geometry.h120
-rw-r--r--core/math/math_2d.cpp6
-rw-r--r--core/math/math_funcs.cpp60
-rw-r--r--core/math/math_funcs.h224
-rw-r--r--core/math/matrix3.cpp20
-rw-r--r--core/math/octree.h2
-rw-r--r--core/math/plane.h2
-rw-r--r--core/math/quat.cpp18
-rw-r--r--core/math/quat.h4
-rw-r--r--core/math/quick_hull.cpp6
-rw-r--r--core/math/rect3.cpp10
-rw-r--r--core/math/rect3.h24
-rw-r--r--core/math/triangle_mesh.cpp4
-rw-r--r--core/math/triangulate.cpp24
-rw-r--r--core/math/triangulate.h10
-rw-r--r--core/math/vector3.cpp74
-rw-r--r--core/math/vector3.h16
-rw-r--r--core/object.h1
-rw-r--r--core/os/input.cpp3
-rw-r--r--core/os/input.h3
-rw-r--r--core/os/os.h3
-rw-r--r--core/pair.h9
-rw-r--r--core/path_remap.cpp182
-rw-r--r--core/path_remap.h35
-rw-r--r--core/register_core_types.cpp11
-rw-r--r--core/resource.cpp132
-rw-r--r--core/resource.h54
-rw-r--r--core/safe_refcount.cpp8
-rw-r--r--core/translation.cpp14
-rw-r--r--core/translation.h1
-rw-r--r--core/ustring.cpp11
-rw-r--r--core/ustring.h1
-rw-r--r--core/variant_parser.cpp10
-rw-r--r--core/vector.h2
-rw-r--r--doc/base/classes.xml24
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp3
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp11
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp4
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp25
-rw-r--r--main/input_default.cpp17
-rw-r--r--main/main.cpp43
-rw-r--r--modules/gdscript/gd_functions.cpp64
-rw-r--r--modules/gdscript/gd_parser.cpp13
-rw-r--r--modules/gdscript/gd_tokenizer.cpp2
-rw-r--r--modules/gdscript/gd_tokenizer.h1
-rw-r--r--modules/gdscript/register_types.cpp7
-rw-r--r--modules/stb_vorbis/SCsub10
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.cpp236
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.h84
-rw-r--r--modules/stb_vorbis/config.py7
-rw-r--r--modules/stb_vorbis/register_types.cpp (renamed from scene/resources/audio_stream.cpp)37
-rw-r--r--modules/stb_vorbis/register_types.h30
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp62
-rw-r--r--platform/android/build.gradle.template3
-rw-r--r--platform/android/export/export.cpp3
-rw-r--r--platform/bb10/export/export.cpp3
-rw-r--r--platform/javascript/audio_driver_javascript.h2
-rw-r--r--platform/javascript/detect.py13
-rw-r--r--platform/javascript/export/export.cpp8
-rw-r--r--platform/javascript/godot_shell.html16
-rw-r--r--platform/javascript/javascript_eval.cpp2
-rw-r--r--platform/javascript/os_javascript.cpp37
-rw-r--r--platform/javascript/os_javascript.h5
-rw-r--r--platform/osx/export/export.cpp3
-rw-r--r--platform/uwp/export/export.cpp3
-rw-r--r--platform/windows/export/export.cpp3
-rw-r--r--platform/windows/os_windows.cpp41
-rw-r--r--platform/windows/os_windows.h1
-rw-r--r--platform/x11/detect.py25
-rw-r--r--platform/x11/export/export.cpp3
-rw-r--r--platform/x11/os_x11.cpp96
-rw-r--r--platform/x11/os_x11.h2
-rw-r--r--scene/2d/collision_polygon_2d.cpp1
-rw-r--r--scene/2d/collision_shape_2d.cpp1
-rw-r--r--scene/2d/particles_2d.cpp6
-rw-r--r--scene/2d/physics_body_2d.cpp4
-rw-r--r--scene/3d/baked_light_instance.cpp8
-rw-r--r--scene/3d/gi_probe.cpp8
-rw-r--r--scene/3d/spatial.cpp2
-rw-r--r--scene/animation/animation_player.cpp23
-rw-r--r--scene/animation/animation_player.h2
-rw-r--r--scene/audio/audio_player.cpp301
-rw-r--r--scene/audio/audio_player.h75
-rw-r--r--scene/gui/button.cpp15
-rw-r--r--scene/gui/range.cpp10
-rw-r--r--scene/gui/spin_box.cpp2
-rw-r--r--scene/gui/text_edit.cpp17
-rw-r--r--scene/gui/text_edit.h1
-rw-r--r--scene/gui/texture_progress.cpp5
-rw-r--r--scene/gui/texture_rect.cpp2
-rw-r--r--scene/gui/tree.cpp30
-rw-r--r--scene/gui/tree.h5
-rw-r--r--scene/gui/video_player.cpp1
-rw-r--r--scene/io/resource_format_image.cpp3
-rw-r--r--scene/io/resource_format_image.h3
-rw-r--r--scene/main/viewport.cpp101
-rw-r--r--scene/main/viewport.h2
-rw-r--r--scene/register_scene_types.cpp21
-rw-r--r--scene/resources/audio_stream_resampled.h2
-rw-r--r--scene/resources/capsule_shape.cpp4
-rw-r--r--scene/resources/curve.cpp6
-rw-r--r--scene/resources/default_theme/theme_data.h6
-rw-r--r--scene/resources/default_theme/vslider_grabber.pngbin554 -> 394 bytes
-rw-r--r--scene/resources/default_theme/vslider_grabber_hl.pngbin701 -> 439 bytes
-rw-r--r--scene/resources/scene_format_text.cpp13
-rw-r--r--scene/resources/sphere_shape.cpp4
-rw-r--r--scene/resources/texture.cpp329
-rw-r--r--scene/resources/texture.h71
-rw-r--r--servers/audio/SCsub2
-rw-r--r--servers/audio/audio_effect.h2
-rw-r--r--servers/audio/audio_filter_sw.cpp4
-rw-r--r--servers/audio/audio_filter_sw.h2
-rw-r--r--servers/audio/audio_stream.cpp86
-rw-r--r--servers/audio/audio_stream.h (renamed from scene/resources/audio_stream.h)60
-rw-r--r--servers/audio/effects/SCsub7
-rw-r--r--servers/audio/effects/audio_effect_amplify.cpp50
-rw-r--r--servers/audio/effects/audio_effect_amplify.h40
-rw-r--r--servers/audio/effects/audio_effect_chorus.cpp365
-rw-r--r--servers/audio/effects/audio_effect_chorus.h115
-rw-r--r--servers/audio/effects/audio_effect_compressor.cpp227
-rw-r--r--servers/audio/effects/audio_effect_compressor.h70
-rw-r--r--servers/audio/effects/audio_effect_delay.cpp326
-rw-r--r--servers/audio/effects/audio_effect_delay.h112
-rw-r--r--servers/audio/effects/audio_effect_distortion.cpp171
-rw-r--r--servers/audio/effects/audio_effect_distortion.h69
-rw-r--r--servers/audio/effects/audio_effect_eq.cpp122
-rw-r--r--servers/audio/effects/audio_effect_eq.h72
-rw-r--r--servers/audio/effects/audio_effect_filter.cpp151
-rw-r--r--servers/audio/effects/audio_effect_filter.h125
-rw-r--r--servers/audio/effects/audio_effect_limiter.cpp124
-rw-r--r--servers/audio/effects/audio_effect_limiter.h58
-rw-r--r--servers/audio/effects/audio_effect_panner.cpp47
-rw-r--r--servers/audio/effects/audio_effect_panner.h40
-rw-r--r--servers/audio/effects/audio_effect_phaser.cpp148
-rw-r--r--servers/audio/effects/audio_effect_phaser.h81
-rw-r--r--servers/audio/effects/audio_effect_pitch_shift.cpp298
-rw-r--r--servers/audio/effects/audio_effect_pitch_shift.h89
-rw-r--r--servers/audio/effects/audio_effect_reverb.cpp182
-rw-r--r--servers/audio/effects/audio_effect_reverb.h76
-rw-r--r--servers/audio/effects/audio_effect_stereo_enhance.cpp135
-rw-r--r--servers/audio/effects/audio_effect_stereo_enhance.h62
-rw-r--r--servers/audio/effects/eq.cpp219
-rw-r--r--servers/audio/effects/eq.h106
-rw-r--r--servers/audio/effects/reverb.cpp364
-rw-r--r--servers/audio/effects/reverb.h111
-rw-r--r--servers/audio_server.cpp980
-rw-r--r--servers/audio_server.h185
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.cpp8
-rw-r--r--servers/register_server_types.cpp51
-rw-r--r--thirdparty/stb_vorbis/stb_vorbis.c5399
-rw-r--r--tools/editor/SCsub3
-rw-r--r--tools/editor/animation_editor.cpp16
-rw-r--r--tools/editor/editor_audio_buses.cpp1192
-rw-r--r--tools/editor/editor_audio_buses.h186
-rw-r--r--tools/editor/editor_data.cpp20
-rw-r--r--tools/editor/editor_data.h3
-rw-r--r--tools/editor/editor_file_system.cpp603
-rw-r--r--tools/editor/editor_file_system.h57
-rw-r--r--tools/editor/editor_import_export.cpp2
-rw-r--r--tools/editor/editor_import_export.h3
-rw-r--r--tools/editor/editor_node.cpp711
-rw-r--r--tools/editor/editor_node.h27
-rw-r--r--tools/editor/editor_plugin.cpp37
-rw-r--r--tools/editor/editor_plugin.h6
-rw-r--r--tools/editor/editor_reimport_dialog.cpp2
-rw-r--r--tools/editor/editor_reimport_dialog.h2
-rw-r--r--tools/editor/editor_run_native.cpp7
-rw-r--r--tools/editor/editor_settings.cpp4
-rw-r--r--tools/editor/filesystem_dock.cpp149
-rw-r--r--tools/editor/filesystem_dock.h11
-rw-r--r--tools/editor/icons/2x/icon_transparent.pngbin0 -> 177 bytes
-rw-r--r--tools/editor/icons/icon_audio_effect_amplify.pngbin0 -> 379 bytes
-rw-r--r--tools/editor/icons/icon_bus_vu_db.pngbin0 -> 1136 bytes
-rw-r--r--tools/editor/icons/icon_bus_vu_empty.pngbin0 -> 1631 bytes
-rw-r--r--tools/editor/icons/icon_bus_vu_frozen.pngbin0 -> 267 bytes
-rw-r--r--tools/editor/icons/icon_bus_vu_full.pngbin0 -> 2463 bytes
-rw-r--r--tools/editor/icons/icon_transparent.pngbin0 -> 158 bytes
-rw-r--r--tools/editor/icons/icon_vu_db.pngbin0 -> 1015 bytes
-rw-r--r--tools/editor/import/SCsub5
-rw-r--r--tools/editor/import/resource_import_texture.cpp274
-rw-r--r--tools/editor/import/resource_import_texture.h43
-rw-r--r--tools/editor/import/resource_importer_csv_translation.cpp126
-rw-r--r--tools/editor/import/resource_importer_csv_translation.h27
-rw-r--r--tools/editor/import_dock.cpp331
-rw-r--r--tools/editor/import_dock.h42
-rw-r--r--tools/editor/io_plugins/editor_bitmask_import_plugin.cpp3
-rw-r--r--tools/editor/io_plugins/editor_bitmask_import_plugin.h3
-rw-r--r--tools/editor/io_plugins/editor_export_scene.cpp3
-rw-r--r--tools/editor/io_plugins/editor_export_scene.h4
-rw-r--r--tools/editor/io_plugins/editor_font_import_plugin.cpp5
-rw-r--r--tools/editor/io_plugins/editor_font_import_plugin.h3
-rw-r--r--tools/editor/io_plugins/editor_import_collada.cpp2
-rw-r--r--tools/editor/io_plugins/editor_import_collada.h4
-rw-r--r--tools/editor/io_plugins/editor_mesh_import_plugin.cpp3
-rw-r--r--tools/editor/io_plugins/editor_mesh_import_plugin.h3
-rw-r--r--tools/editor/io_plugins/editor_sample_import_plugin.cpp2
-rw-r--r--tools/editor/io_plugins/editor_scene_import_plugin.cpp3
-rw-r--r--tools/editor/io_plugins/editor_scene_import_plugin.h4
-rw-r--r--tools/editor/io_plugins/editor_texture_import_plugin.cpp3
-rw-r--r--tools/editor/io_plugins/editor_texture_import_plugin.h7
-rw-r--r--tools/editor/io_plugins/editor_translation_import_plugin.cpp3
-rw-r--r--tools/editor/io_plugins/editor_translation_import_plugin.h3
-rw-r--r--tools/editor/plugins/animation_player_editor_plugin.cpp27
-rw-r--r--tools/editor/plugins/animation_player_editor_plugin.h2
-rw-r--r--tools/editor/plugins/canvas_item_editor_plugin.cpp2
-rw-r--r--tools/editor/plugins/canvas_item_editor_plugin.h4
-rw-r--r--tools/editor/plugins/multimesh_editor_plugin.cpp2
-rw-r--r--tools/editor/plugins/script_text_editor.cpp1
-rw-r--r--tools/editor/plugins/spatial_editor_plugin.cpp2
-rw-r--r--tools/editor/project_export.cpp3
-rw-r--r--tools/editor/project_export.h2
-rw-r--r--tools/editor/project_settings.cpp4
-rw-r--r--tools/editor/property_editor.cpp76
-rw-r--r--tools/editor/property_editor.h5
-rw-r--r--tools/editor/scene_tree_dock.cpp5
-rw-r--r--tools/editor/scene_tree_editor.cpp36
-rw-r--r--tools/editor/script_editor_debugger.cpp2
-rw-r--r--tools/editor/spatial_editor_gizmos.cpp28
244 files changed, 16469 insertions, 2698 deletions
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
index cbc96c4ecd..93ded6c954 100644
--- a/ISSUE_TEMPLATE.md
+++ b/ISSUE_TEMPLATE.md
@@ -1,17 +1,17 @@
+<!--
+README: Incompatibilities and broken features in the current master branch / 3.0-alpha
+are known and expected due to important refactoring work, so no need to report them for now. Thanks!
+-->
+
**Operating system or device - Godot version:**
-**Issue description** (what happened, and what was expected):
+**Issue description:**
+<!-- What happened, and what was expected. -->
**Steps to reproduce:**
-**Link to minimal example project** (optional but very welcome):
-
-
-
---------------
-
-*NOTE: Incompatibilities are broken features in the current master branch / 3.0-alpha
-are expected, so no need to report them for now. Thanks!*
+**Link to minimal example project:**
+<!-- Optional but very welcome. You can drag and drop a zip archive to upload it. -->:
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index d4f61b7ffc..636a3f07c1 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -106,17 +106,12 @@ bool _ResourceLoader::has(const String &p_path) {
return ResourceCache::has(local_path);
};
-Ref<ResourceImportMetadata> _ResourceLoader::load_import_metadata(const String& p_path) {
-
- return ResourceLoader::load_import_metadata(p_path);
-}
void _ResourceLoader::_bind_methods() {
ClassDB::bind_method(_MD("load_interactive:ResourceInteractiveLoader","path","type_hint"),&_ResourceLoader::load_interactive,DEFVAL(""));
ClassDB::bind_method(_MD("load:Resource","path","type_hint", "p_no_cache"),&_ResourceLoader::load,DEFVAL(""), DEFVAL(false));
- ClassDB::bind_method(_MD("load_import_metadata:ResourceImportMetadata","path"),&_ResourceLoader::load_import_metadata);
ClassDB::bind_method(_MD("get_recognized_extensions_for_type","type"),&_ResourceLoader::get_recognized_extensions_for_type);
ClassDB::bind_method(_MD("set_abort_on_missing_resources","abort"),&_ResourceLoader::set_abort_on_missing_resources);
ClassDB::bind_method(_MD("get_dependencies","path"),&_ResourceLoader::get_dependencies);
@@ -1732,6 +1727,11 @@ Variant _File::get_var() const {
return v;
}
+uint64_t _File::get_modified_time(const String &p_file) const {
+
+ return FileAccess::get_modified_time(p_file);
+}
+
void _File::_bind_methods() {
@@ -1780,6 +1780,7 @@ void _File::_bind_methods() {
ClassDB::bind_method(_MD("get_pascal_string"),&_File::get_pascal_string);
ClassDB::bind_method(_MD("file_exists","path"),&_File::file_exists);
+ ClassDB::bind_method(_MD("get_modified_time", "file"),&_File::get_modified_time);
BIND_CONSTANT( READ );
BIND_CONSTANT( WRITE );
@@ -1819,16 +1820,28 @@ Error _Directory::open(const String& p_path) {
return OK;
}
-Error _Directory::list_dir_begin() {
+Error _Directory::list_dir_begin(bool p_skip_navigational, bool p_skip_hidden) {
ERR_FAIL_COND_V(!d,ERR_UNCONFIGURED);
+
+ _list_skip_navigational = p_skip_navigational;
+ _list_skip_hidden = p_skip_hidden;
+
return d->list_dir_begin();
}
String _Directory::get_next(){
ERR_FAIL_COND_V(!d,"");
- return d->get_next();
+
+ String next = d->get_next();
+ while (next != ""
+ && ((_list_skip_navigational && (next == "." || next == ".."))
+ || (_list_skip_hidden && d->current_is_hidden()))) {
+
+ next = d->get_next();
+ }
+ return next;
}
bool _Directory::current_is_dir() const{
@@ -1958,7 +1971,7 @@ void _Directory::_bind_methods() {
ClassDB::bind_method(_MD("open:Error","path"),&_Directory::open);
- ClassDB::bind_method(_MD("list_dir_begin"),&_Directory::list_dir_begin);
+ ClassDB::bind_method(_MD("list_dir_begin", "skip_navigational", "skip_hidden"), &_Directory::list_dir_begin, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(_MD("get_next"),&_Directory::get_next);
ClassDB::bind_method(_MD("current_is_dir"),&_Directory::current_is_dir);
ClassDB::bind_method(_MD("list_dir_end"),&_Directory::list_dir_end);
@@ -2499,7 +2512,7 @@ void _ClassDB::_bind_methods() {
ClassDB::bind_method(_MD("class_exists","class"),&_ClassDB::class_exists);
ClassDB::bind_method(_MD("is_parent_class","class","inherits"),&_ClassDB::is_parent_class);
ClassDB::bind_method(_MD("can_instance","class"),&_ClassDB::can_instance);
- ClassDB::bind_method(_MD("instance","class"),&_ClassDB::instance);
+ ClassDB::bind_method(_MD("instance:Variant","class"),&_ClassDB::instance);
ClassDB::bind_method(_MD("class_has_signal","class","signal"),&_ClassDB::has_signal);
ClassDB::bind_method(_MD("class_get_signal","class","signal"),&_ClassDB::get_signal);
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index f10714720f..00cbb254d6 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -54,7 +54,6 @@ public:
void set_abort_on_missing_resources(bool p_abort);
PoolStringArray get_dependencies(const String& p_path);
bool has(const String& p_path);
- Ref<ResourceImportMetadata> load_import_metadata(const String& p_path);
_ResourceLoader();
};
@@ -440,6 +439,8 @@ public:
bool file_exists(const String& p_name) const; ///< return true if a file exists
+ uint64_t get_modified_time(const String& p_file) const;
+
_File();
virtual ~_File();
@@ -456,7 +457,7 @@ public:
Error open(const String& p_path);
- Error list_dir_begin(); ///< This starts dir listing
+ Error list_dir_begin(bool p_skip_internal = false, bool p_skip_hidden = false); ///< This starts dir listing
String get_next();
bool current_is_dir() const;
@@ -485,6 +486,9 @@ public:
_Directory();
virtual ~_Directory();
+private:
+ bool _list_skip_navigational;
+ bool _list_skip_hidden;
};
class _Marshalls : public Reference {
diff --git a/core/class_db.cpp b/core/class_db.cpp
index bb3368c128..2a3a12b127 100644
--- a/core/class_db.cpp
+++ b/core/class_db.cpp
@@ -33,6 +33,7 @@
#ifdef NO_THREADS
#define OBJTYPE_RLOCK
+#define OBJTYPE_WLOCK
#else
@@ -776,11 +777,15 @@ void ClassDB::add_property(StringName p_class,const PropertyInfo& p_pinfo, const
+#ifndef NO_THREADS
lock->read_lock();
+#endif
ClassInfo *type=classes.getptr(p_class);
+#ifndef NO_THREADS
lock->read_unlock();
+#endif
ERR_FAIL_COND(!type);
diff --git a/core/dvector.h b/core/dvector.h
index cac9e8ef85..53a29738f7 100644
--- a/core/dvector.h
+++ b/core/dvector.h
@@ -89,7 +89,7 @@ class PoolVector {
if (!alloc)
return;
- ERR_FAIL_COND(alloc->lock>0);
+// ERR_FAIL_COND(alloc->lock>0); should not be illegal to lock this for copy on write, as it's a copy on write after all
if (alloc->refcount.get()==1)
return; //nothing to do
diff --git a/core/image.cpp b/core/image.cpp
index ed505b0f77..2d038691f2 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -2155,7 +2155,7 @@ void Image::fix_alpha_edges() {
return; //not needed
PoolVector<uint8_t> dcopy = data;
- PoolVector<uint8_t>::Read rp = data.read();
+ PoolVector<uint8_t>::Read rp = dcopy.read();
const uint8_t *srcptr=rp.ptr();
PoolVector<uint8_t>::Write wp = data.write();
diff --git a/core/input_map.cpp b/core/input_map.cpp
index 8473bce806..dcce13ba1b 100644
--- a/core/input_map.cpp
+++ b/core/input_map.cpp
@@ -107,7 +107,7 @@ List<StringName> InputMap::get_actions() const {
return actions;
}
-List<InputEvent>::Element *InputMap::_find_event(List<InputEvent> &p_list,const InputEvent& p_event, bool p_mod_ignore=false) const {
+List<InputEvent>::Element *InputMap::_find_event(List<InputEvent> &p_list,const InputEvent& p_event, bool p_action_test) const {
for (List<InputEvent>::Element *E=p_list.front();E;E=E->next()) {
@@ -123,7 +123,13 @@ List<InputEvent>::Element *InputMap::_find_event(List<InputEvent> &p_list,const
case InputEvent::KEY: {
- same=(e.key.scancode==p_event.key.scancode && (p_mod_ignore || e.key.mod == p_event.key.mod));
+ if(p_action_test) {
+ uint32_t code = e.key.get_scancode_with_modifiers();
+ uint32_t event_code = p_event.key.get_scancode_with_modifiers();
+ same=(e.key.scancode==p_event.key.scancode && (!p_event.key.pressed || ((code & event_code) == code)));
+ } else {
+ same=(e.key.scancode==p_event.key.scancode && e.key.mod == p_event.key.mod);
+ }
} break;
case InputEvent::JOYPAD_BUTTON: {
@@ -230,7 +236,7 @@ bool InputMap::event_is_action(const InputEvent& p_event, const StringName& p_ac
return p_event.action.action==E->get().id;
}
- return _find_event(E->get().inputs,p_event,!p_event.is_pressed())!=NULL;
+ return _find_event(E->get().inputs,p_event,true)!=NULL;
}
const Map<StringName, InputMap::Action>& InputMap::get_action_map() const {
diff --git a/core/input_map.h b/core/input_map.h
index 306845fc89..6ccd24f29c 100644
--- a/core/input_map.h
+++ b/core/input_map.h
@@ -46,7 +46,7 @@ private:
mutable Map<StringName, Action> input_map;
mutable Map<int,StringName> input_id_map;
- List<InputEvent>::Element *_find_event(List<InputEvent> &p_list,const InputEvent& p_event, bool p_mod_ignore) const;
+ List<InputEvent>::Element *_find_event(List<InputEvent> &p_list,const InputEvent& p_event, bool p_action_test=false) const;
Array _get_action_list(const StringName& p_action);
Array _get_actions();
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index a9de740806..b944906e78 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -119,7 +119,10 @@ void ConfigFile::get_section_keys(const String& p_section,List<String> *r_keys)
}
+void ConfigFile::erase_section(const String& p_section) {
+ values.erase(p_section);
+}
Error ConfigFile::save(const String& p_path){
@@ -215,6 +218,8 @@ void ConfigFile::_bind_methods(){
ClassDB::bind_method(_MD("get_sections"),&ConfigFile::_get_sections);
ClassDB::bind_method(_MD("get_section_keys","section"),&ConfigFile::_get_section_keys);
+ ClassDB::bind_method(_MD("erase_section","section"),&ConfigFile::erase_section);
+
ClassDB::bind_method(_MD("load:Error","path"),&ConfigFile::load);
ClassDB::bind_method(_MD("save:Error","path"),&ConfigFile::save);
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 397342f90f..c9c4a9fbc0 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -54,6 +54,8 @@ public:
void get_sections(List<String> *r_sections) const;
void get_section_keys(const String& p_section,List<String> *r_keys) const;
+ void erase_section(const String& p_section);
+
Error save(const String& p_path);
Error load(const String& p_path);
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 4af3503434..c75e476764 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -80,7 +80,8 @@ enum {
OBJECT_EXTERNAL_RESOURCE=1,
OBJECT_INTERNAL_RESOURCE=2,
OBJECT_EXTERNAL_RESOURCE_INDEX=3,
- FORMAT_VERSION=1,
+ //version 2: added 64 bits support for float and int
+ FORMAT_VERSION=2,
FORMAT_VERSION_CAN_RENAME_DEPS=1
@@ -758,30 +759,7 @@ Error ResourceInteractiveLoaderBinary::poll(){
resource_cache.push_back(res);
if (main) {
- if (importmd_ofs) {
- f->seek(importmd_ofs);
- Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
- imd->set_editor(get_unicode_string());
- int sc = f->get_32();
- for(int i=0;i<sc;i++) {
-
- String src = get_unicode_string();
- String md5 = get_unicode_string();
- imd->add_source(src,md5);
- }
- int pc = f->get_32();
-
- for(int i=0;i<pc;i++) {
-
- String name = get_unicode_string();
- Variant val;
- parse_variant(val);
- imd->set_option(name,val);
- }
- res->set_import_metadata(imd);
-
- }
f->close();
resource=res;
error=ERR_FILE_EOF;
@@ -848,9 +826,6 @@ void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f,List<Stri
for(int i=0;i<external_resources.size();i++) {
String dep=external_resources[i].path;
- if (dep.ends_with("*")) {
- dep=ResourceLoader::guess_full_filename(dep,external_resources[i].type);
- }
if (p_add_types && external_resources[i].type!=String()) {
dep+="::"+external_resources[i].type;
@@ -1103,53 +1078,6 @@ bool ResourceFormatLoaderBinary::handles_type(const String& p_type) const{
return true; //handles all
}
-Error ResourceFormatLoaderBinary::load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const {
-
-
- FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
- if (!f) {
- return ERR_FILE_CANT_OPEN;
- }
-
- Ref<ResourceInteractiveLoaderBinary> ria = memnew( ResourceInteractiveLoaderBinary );
- ria->local_path=GlobalConfig::get_singleton()->localize_path(p_path);
- ria->res_path=ria->local_path;
- //ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
- ria->recognize(f);
- if(ria->error!=OK)
- return ERR_FILE_UNRECOGNIZED;
- f=ria->f;
- uint64_t imp_ofs = f->get_64();
-
- if (imp_ofs==0)
- return ERR_UNAVAILABLE;
-
- f->seek(imp_ofs);
- Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
- imd->set_editor(ria->get_unicode_string());
- int sc = f->get_32();
- for(int i=0;i<sc;i++) {
-
- String src = ria->get_unicode_string();
- String md5 = ria->get_unicode_string();
- imd->add_source(src,md5);
- }
- int pc = f->get_32();
-
- for(int i=0;i<pc;i++) {
-
- String name = ria->get_unicode_string();
- Variant val;
- ria->parse_variant(val);
- imd->set_option(name,val);
- }
-
- r_var=imd;
-
- return OK;
-
-}
-
void ResourceFormatLoaderBinary::get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types) {
@@ -2178,30 +2106,6 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
}
f->seek_end();
- print_line("SAVING: "+p_path);
- if (p_resource->get_import_metadata().is_valid()) {
- uint64_t md_pos = f->get_pos();
- Ref<ResourceImportMetadata> imd=p_resource->get_import_metadata();
- save_unicode_string(imd->get_editor());
- f->store_32(imd->get_source_count());
- for(int i=0;i<imd->get_source_count();i++) {
- save_unicode_string(imd->get_source_path(i));
- save_unicode_string(imd->get_source_md5(i));
- print_line("SAVE PATH: "+imd->get_source_path(i));
- print_line("SAVE MD5: "+imd->get_source_md5(i));
- }
- List<String> options;
- imd->get_options(&options);
- f->store_32(options.size());
- for(List<String>::Element *E=options.front();E;E=E->next()) {
- save_unicode_string(E->get());
- write_variant(imd->get_option(E->get()));
- }
-
- f->seek(md_at);
- f->store_64(md_pos);
- f->seek_end();
- }
f->store_buffer((const uint8_t*)"RSRC",4); //magic at end
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 611029e792..1dac51cc5c 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -109,7 +109,6 @@ public:
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
virtual void get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types=false);
- virtual Error load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const;
virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map);
diff --git a/core/io/resource_import.cpp b/core/io/resource_import.cpp
new file mode 100644
index 0000000000..d0799cdbe6
--- /dev/null
+++ b/core/io/resource_import.cpp
@@ -0,0 +1,238 @@
+#include "resource_import.h"
+#include "variant_parser.h"
+
+Error ResourceFormatImporter::_get_path_and_type(const String& p_path, PathAndType &r_path_and_type) const {
+
+ Error err;
+ FileAccess *f= FileAccess::open(p_path+".import",FileAccess::READ,&err);
+
+ if (!f)
+ return err;
+
+ VariantParser::StreamFile stream;
+ stream.f=f;
+
+ String assign;
+ Variant value;
+ VariantParser::Tag next_tag;
+
+ int lines=0;
+ String error_text;
+ while(true) {
+
+ assign=Variant();
+ next_tag.fields.clear();
+ next_tag.name=String();
+
+ err = VariantParser::parse_tag_assign_eof(&stream,lines,error_text,next_tag,assign,value,NULL,true);
+ if (err==ERR_FILE_EOF) {
+ memdelete(f);
+ return OK;
+ }
+ else if (err!=OK) {
+ ERR_PRINTS("ResourceFormatImporter::load - "+p_path+".import:"+itos(lines)+" error: "+error_text);
+ memdelete(f);
+ return err;
+ }
+
+ if (assign!=String()) {
+ if (assign=="path") {
+ r_path_and_type.path=value;
+ } else if (assign=="type") {
+ r_path_and_type.type=value;
+ }
+
+ } else if (next_tag.name!="remap") {
+ break;
+ }
+ }
+
+ memdelete(f);
+
+ if (r_path_and_type.path==String() || r_path_and_type.type==String()) {
+ return ERR_FILE_CORRUPT;
+ }
+ return OK;
+
+}
+
+
+RES ResourceFormatImporter::load(const String &p_path,const String& p_original_path,Error *r_error) {
+
+ PathAndType pat;
+ Error err = _get_path_and_type(p_path,pat);
+
+ if (err!=OK) {
+
+ if (r_error)
+ *r_error=err;
+
+ return RES();
+ }
+
+
+ RES res = ResourceLoader::load(pat.path,pat.type,false,r_error);
+
+#ifdef TOOLS_ENABLED
+ res->set_import_last_modified_time( res->get_last_modified_time() ); //pass this, if used
+ res->set_import_path(pat.path);
+#endif
+
+ return res;
+
+}
+
+void ResourceFormatImporter::get_recognized_extensions(List<String> *p_extensions) const{
+
+ print_line("getting exts from: "+itos(importers.size()));
+ Set<String> found;
+
+ for (Set< Ref<ResourceImporter> >::Element *E=importers.front();E;E=E->next()) {
+ List<String> local_exts;
+ E->get()->get_recognized_extensions(&local_exts);
+ for (List<String>::Element *F=local_exts.front();F;F=F->next()) {
+ if (!found.has(F->get())) {
+ print_line("adding ext "+String(F->get()));
+ p_extensions->push_back(F->get());
+ found.insert(F->get());
+ }
+ }
+ }
+}
+
+void ResourceFormatImporter::get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const{
+
+ if (p_type=="") {
+ return get_recognized_extensions(p_extensions);
+ }
+
+ Set<String> found;
+
+ for (Set< Ref<ResourceImporter> >::Element *E=importers.front();E;E=E->next()) {
+ String res_type = E->get()->get_resource_type();
+ if (res_type==String())
+ continue;
+
+ if (!ClassDB::is_parent_class(res_type,p_type))
+ continue;
+
+ List<String> local_exts;
+ E->get()->get_recognized_extensions(&local_exts);
+ for (List<String>::Element *F=local_exts.front();F;F=F->next()) {
+ if (!found.has(F->get())) {
+ p_extensions->push_back(F->get());
+ found.insert(F->get());
+ }
+ }
+ }
+}
+
+bool ResourceFormatImporter::recognize_path(const String& p_path,const String& p_for_type) const{
+
+ return FileAccess::exists(p_path+".import");
+
+}
+
+bool ResourceFormatImporter::can_be_imported(const String& p_path) const {
+
+ return ResourceFormatLoader::recognize_path(p_path);
+}
+
+
+bool ResourceFormatImporter::handles_type(const String& p_type) const {
+
+ for (Set< Ref<ResourceImporter> >::Element *E=importers.front();E;E=E->next()) {
+
+ String res_type = E->get()->get_resource_type();
+ if (res_type==String())
+ continue;
+ if (ClassDB::is_parent_class(res_type,p_type))
+ return true;
+
+ }
+
+ return true;
+}
+
+String ResourceFormatImporter::get_resource_type(const String &p_path) const {
+
+ PathAndType pat;
+ Error err = _get_path_and_type(p_path,pat);
+
+ if (err!=OK) {
+
+ return "";
+ }
+
+ return pat.type;
+}
+
+void ResourceFormatImporter::get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types){
+
+ PathAndType pat;
+ Error err = _get_path_and_type(p_path,pat);
+
+ if (err!=OK) {
+
+ return;
+ }
+
+ return ResourceLoader::get_dependencies(pat.path,p_dependencies,p_add_types);
+}
+
+Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_name(const String& p_name) {
+
+ for (Set< Ref<ResourceImporter> >::Element *E=importers.front();E;E=E->next()) {
+ if (E->get()->get_importer_name()==p_name) {
+ return E->get();
+ }
+ }
+
+ return Ref<ResourceImporter>();
+}
+
+
+void ResourceFormatImporter::get_importers_for_extension(const String& p_extension,List<Ref<ResourceImporter> > *r_importers) {
+
+ for (Set< Ref<ResourceImporter> >::Element *E=importers.front();E;E=E->next()) {
+ List<String> local_exts;
+ E->get()->get_recognized_extensions(&local_exts);
+ for (List<String>::Element *F=local_exts.front();F;F=F->next()) {
+ if (p_extension.to_lower()==F->get()) {
+ r_importers->push_back(E->get());
+ }
+ }
+ }
+}
+
+Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_extension(const String& p_extension) {
+
+
+ Ref<ResourceImporter> importer;
+ float priority=0;
+
+ for (Set< Ref<ResourceImporter> >::Element *E=importers.front();E;E=E->next()) {
+
+ List<String> local_exts;
+ E->get()->get_recognized_extensions(&local_exts);
+ for (List<String>::Element *F=local_exts.front();F;F=F->next()) {
+ if (p_extension.to_lower()==F->get() && E->get()->get_priority() > priority) {
+ importer=E->get();
+ priority=E->get()->get_priority();
+ }
+ }
+ }
+
+ return importer;
+}
+
+String ResourceFormatImporter::get_import_base_path(const String& p_for_file) const {
+
+ return "res://.import/"+p_for_file.get_file()+"-"+p_for_file.md5_text();
+}
+
+ResourceFormatImporter *ResourceFormatImporter::singleton=NULL;
+
+ResourceFormatImporter::ResourceFormatImporter() {
+ singleton=this;
+}
diff --git a/core/io/resource_import.h b/core/io/resource_import.h
new file mode 100644
index 0000000000..939cecfbd9
--- /dev/null
+++ b/core/io/resource_import.h
@@ -0,0 +1,76 @@
+#ifndef RESOURCE_IMPORT_H
+#define RESOURCE_IMPORT_H
+
+
+#include "io/resource_loader.h"
+class ResourceImporter;
+
+class ResourceFormatImporter : public ResourceFormatLoader {
+
+ struct PathAndType {
+ String path;
+ String type;
+ };
+
+
+ Error _get_path_and_type(const String& p_path,PathAndType & r_path_and_type) const;
+
+ static ResourceFormatImporter *singleton;
+
+ Set< Ref<ResourceImporter> > importers;
+public:
+
+ static ResourceFormatImporter *get_singleton() { return singleton; }
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const;
+ virtual bool recognize_path(const String& p_path,const String& p_for_type=String()) const;
+ virtual bool handles_type(const String& p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+ virtual void get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types=false);
+
+ virtual bool can_be_imported(const String& p_path) const;
+
+
+ void add_importer(const Ref<ResourceImporter>& p_importer) { importers.insert(p_importer); }
+ Ref<ResourceImporter> get_importer_by_name(const String& p_name);
+ Ref<ResourceImporter> get_importer_by_extension(const String& p_extension);
+ void get_importers_for_extension(const String& p_extension,List<Ref<ResourceImporter> > *r_importers);
+
+ String get_import_base_path(const String& p_for_file) const;
+ ResourceFormatImporter();
+};
+
+
+class ResourceImporter : public Reference {
+
+ GDCLASS(ResourceImporter,Reference)
+public:
+ virtual String get_importer_name() const=0;
+ virtual String get_visible_name() const=0;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
+ virtual String get_save_extension() const=0;
+ virtual String get_resource_type() const=0;
+ virtual float get_priority() const { return 1.0; }
+
+ struct ImportOption {
+ PropertyInfo option;
+ Variant default_value;
+
+ ImportOption(const PropertyInfo& p_info,const Variant& p_default) { option=p_info; default_value=p_default; }
+ ImportOption() {}
+ };
+
+
+ virtual int get_preset_count() const { return 0; }
+ virtual String get_preset_name(int p_idx) const { return String(); }
+
+ virtual void get_import_options(List<ImportOption> *r_options,int p_preset=0) const=0;
+ virtual bool get_option_visibility(const String& p_option,const Map<StringName,Variant>& p_options) const=0;
+
+
+ virtual Error import(const String& p_source_file,const String& p_save_path,const Map<StringName,Variant>& p_options,List<String>* r_platform_variants,List<String>* r_gen_files=NULL)=0;
+
+};
+
+#endif // RESOURCE_IMPORT_H
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 354efaa83f..fbf6a2cea2 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -47,21 +47,29 @@ Error ResourceInteractiveLoader::wait() {
return err;
}
+bool ResourceFormatLoader::recognize_path(const String& p_path,const String& p_for_type) const {
-bool ResourceFormatLoader::recognize(const String& p_extension) const {
+ String extension = p_path.get_extension();
List<String> extensions;
- get_recognized_extensions(&extensions);
+ if (p_for_type==String()) {
+ get_recognized_extensions(&extensions);
+ } else {
+ get_recognized_extensions_for_type(p_for_type,&extensions);
+ }
+
for (List<String>::Element *E=extensions.front();E;E=E->next()) {
- if (E->get().nocasecmp_to(p_extension.get_extension())==0)
+ if (E->get().nocasecmp_to(extension)==0)
return true;
}
return false;
+
}
+
void ResourceFormatLoader::get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const {
if (p_type=="" || handles_type(p_type))
@@ -166,7 +174,7 @@ RES ResourceLoader::load(const String &p_path, const String& p_type_hint, bool p
else
local_path = GlobalConfig::get_singleton()->localize_path(p_path);
- local_path=find_complete_path(local_path,p_type_hint);
+
ERR_FAIL_COND_V(local_path=="",RES());
if (!p_no_cache && ResourceCache::has(local_path)) {
@@ -177,22 +185,16 @@ RES ResourceLoader::load(const String &p_path, const String& p_type_hint, bool p
return RES( ResourceCache::get(local_path ) );
}
- String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
-
if (OS::get_singleton()->is_stdout_verbose())
- print_line("load resource: "+remapped_path);
-
- String extension=remapped_path.get_extension();
+ print_line("load resource: "+local_path);
bool found=false;
for (int i=0;i<loader_count;i++) {
- if (!loader[i]->recognize(extension))
- continue;
- if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
+ if (!loader[i]->recognize_path(local_path,p_type_hint))
continue;
found=true;
- RES res = loader[i]->load(remapped_path,local_path,r_error);
+ RES res = loader[i]->load(local_path,local_path,r_error);
if (res.is_null())
continue;
if (!p_no_cache)
@@ -201,7 +203,7 @@ RES ResourceLoader::load(const String &p_path, const String& p_type_hint, bool p
res->set_edited(false);
if (timestamp_on_load) {
- uint64_t mt = FileAccess::get_modified_time(remapped_path);
+ uint64_t mt = FileAccess::get_modified_time(local_path);
//printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt);
res->set_last_modified_time(mt);
}
@@ -220,82 +222,6 @@ RES ResourceLoader::load(const String &p_path, const String& p_type_hint, bool p
}
-Ref<ResourceImportMetadata> ResourceLoader::load_import_metadata(const String &p_path) {
-
-
-
- String local_path;
- if (p_path.is_rel_path())
- local_path="res://"+p_path;
- else
- local_path = GlobalConfig::get_singleton()->localize_path(p_path);
-
- String extension=p_path.get_extension();
- Ref<ResourceImportMetadata> ret;
-
- for (int i=0;i<loader_count;i++) {
-
- if (!loader[i]->recognize(extension))
- continue;
-
- Error err = loader[i]->load_import_metadata(local_path,ret);
- if (err==OK)
- break;
- }
-
-
- return ret;
-
-}
-
-
-
-String ResourceLoader::find_complete_path(const String& p_path,const String& p_type) {
- //this is an old vestige when the engine saved files without extension.
- //remains here for compatibility with old projects and only because it
- //can be sometimes nice to open files using .* from a script and have it guess
- //the right extension.
-
- String local_path = p_path;
- if (local_path.ends_with("*")) {
-
- //find the extension for resource that ends with *
- local_path = local_path.substr(0,local_path.length()-1);
- List<String> extensions;
- get_recognized_extensions_for_type(p_type,&extensions);
- List<String> candidates;
-
- for(List<String>::Element *E=extensions.front();E;E=E->next()) {
-
- String path = local_path+E->get();
-
- if (PathRemap::get_singleton()->has_remap(path) || FileAccess::exists(path)) {
- candidates.push_back(path);
- }
-
- }
-
-
- if (candidates.size()==0) {
- return "";
- } else if (candidates.size()==1 || p_type=="") {
- return candidates.front()->get();
- } else {
-
- for(List<String>::Element *E=candidates.front();E;E=E->next()) {
-
- String rt = get_resource_type(E->get());
- if (ClassDB::is_parent_class(rt,p_type)) {
- return E->get();
- }
- }
-
- return "";
- }
- }
-
- return local_path;
-}
Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_path,const String& p_type_hint,bool p_no_cache,Error *r_error) {
@@ -309,7 +235,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
else
local_path = GlobalConfig::get_singleton()->localize_path(p_path);
- local_path=find_complete_path(local_path,p_type_hint);
+
ERR_FAIL_COND_V(local_path=="",Ref<ResourceInteractiveLoader>());
@@ -329,19 +255,14 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
if (OS::get_singleton()->is_stdout_verbose())
print_line("load resource: ");
- String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
-
- String extension=remapped_path.get_extension();
bool found=false;
for (int i=0;i<loader_count;i++) {
- if (!loader[i]->recognize(extension))
- continue;
- if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
+ if (!loader[i]->recognize_path(local_path,p_type_hint))
continue;
found=true;
- Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(remapped_path,r_error);
+ Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(local_path,r_error);
if (ril.is_null())
continue;
if (!p_no_cache)
@@ -383,20 +304,16 @@ void ResourceLoader::get_dependencies(const String& p_path, List<String> *p_depe
else
local_path = GlobalConfig::get_singleton()->localize_path(p_path);
- String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
-
- String extension=remapped_path.get_extension();
-
for (int i=0;i<loader_count;i++) {
- if (!loader[i]->recognize(extension))
+ if (!loader[i]->recognize_path(local_path))
continue;
/*
if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
continue;
*/
- loader[i]->get_dependencies(remapped_path,p_dependencies,p_add_types);
+ loader[i]->get_dependencies(local_path,p_dependencies,p_add_types);
}
}
@@ -410,20 +327,17 @@ Error ResourceLoader::rename_dependencies(const String &p_path,const Map<String,
else
local_path = GlobalConfig::get_singleton()->localize_path(p_path);
- String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
-
- String extension=remapped_path.get_extension();
for (int i=0;i<loader_count;i++) {
- if (!loader[i]->recognize(extension))
+ if (!loader[i]->recognize_path(local_path))
continue;
/*
if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
continue;
*/
- return loader[i]->rename_dependencies(p_path,p_map);
+ return loader[i]->rename_dependencies(local_path,p_map);
}
@@ -432,17 +346,6 @@ Error ResourceLoader::rename_dependencies(const String &p_path,const Map<String,
}
-String ResourceLoader::guess_full_filename(const String &p_path,const String& p_type) {
-
- String local_path;
- if (p_path.is_rel_path())
- local_path="res://"+p_path;
- else
- local_path = GlobalConfig::get_singleton()->localize_path(p_path);
-
- return find_complete_path(local_path,p_type);
-
-}
String ResourceLoader::get_resource_type(const String &p_path) {
@@ -452,8 +355,6 @@ String ResourceLoader::get_resource_type(const String &p_path) {
else
local_path = GlobalConfig::get_singleton()->localize_path(p_path);
- String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
- String extension=remapped_path.get_extension();
for (int i=0;i<loader_count;i++) {
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 7979bd02a7..f464415e12 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -61,11 +61,10 @@ public:
virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const;
- bool recognize(const String& p_extension) const;
+ virtual bool recognize_path(const String& p_path,const String& p_for_type=String()) const;
virtual bool handles_type(const String& p_type) const=0;
virtual String get_resource_type(const String &p_path) const=0;
virtual void get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types=false);
- virtual Error load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const { return ERR_UNAVAILABLE; }
virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map) { return OK; }
virtual ~ResourceFormatLoader() {}
@@ -92,14 +91,12 @@ class ResourceLoader {
static DependencyErrorNotify dep_err_notify;
static bool abort_on_missing_resource;
- static String find_complete_path(const String& p_path,const String& p_type);
public:
static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,const String& p_type_hint="",bool p_no_cache=false,Error *r_error=NULL);
static RES load(const String &p_path,const String& p_type_hint="",bool p_no_cache=false,Error *r_error=NULL);
- static Ref<ResourceImportMetadata> load_import_metadata(const String &p_path);
static void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions);
static void add_resource_format_loader(ResourceFormatLoader *p_format_loader,bool p_at_front=false);
@@ -107,8 +104,6 @@ public:
static void get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types=false);
static Error rename_dependencies(const String &p_path,const Map<String,String>& p_map);
- static String guess_full_filename(const String &p_path,const String& p_type);
-
static void set_timestamp_on_load(bool p_timestamp) { timestamp_on_load=p_timestamp; }
static void notify_load_error(const String& p_err) { if (err_notify) err_notify(err_notify_ud,p_err); }
@@ -122,4 +117,6 @@ public:
static bool get_abort_on_missing_resources() { return abort_on_missing_resource; }
};
+
+
#endif
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 2c45009a60..a1f471ebe3 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -39,7 +39,7 @@ int AStar::get_available_point_id() const {
return points.back()->key()+1;
}
-void AStar::add_point(int p_id, const Vector3 &p_pos, float p_weight_scale) {
+void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) {
ERR_FAIL_COND(p_id<0);
if (!points.has(p_id)) {
Point *pt = memnew( Point );
@@ -62,7 +62,7 @@ Vector3 AStar::get_point_pos(int p_id) const{
return points[p_id]->pos;
}
-float AStar::get_point_weight_scale(int p_id) const{
+real_t AStar::get_point_weight_scale(int p_id) const{
ERR_FAIL_COND_V(!points.has(p_id),0);
@@ -145,11 +145,11 @@ void AStar::clear(){
int AStar::get_closest_point(const Vector3& p_point) const{
int closest_id=-1;
- float closest_dist=1e20;
+ real_t closest_dist=1e20;
for (const Map<int,Point*>::Element *E=points.front();E;E=E->next()) {
- float d = p_point.distance_squared_to(E->get()->pos);
+ real_t d = p_point.distance_squared_to(E->get()->pos);
if (closest_id<0 || d<closest_dist) {
closest_dist=d;
closest_id=E->key();
@@ -162,7 +162,7 @@ int AStar::get_closest_point(const Vector3& p_point) const{
}
Vector3 AStar::get_closest_pos_in_segment(const Vector3& p_point) const {
- float closest_dist = 1e20;
+ real_t closest_dist = 1e20;
bool found=false;
Vector3 closest_point;
@@ -175,7 +175,7 @@ Vector3 AStar::get_closest_pos_in_segment(const Vector3& p_point) const {
};
Vector3 p = Geometry::get_closest_point_to_segment(p_point,segment);
- float d = p_point.distance_squared_to(p);
+ real_t d = p_point.distance_squared_to(p);
if (!found || d<closest_dist) {
closest_point=p;
@@ -220,14 +220,14 @@ bool AStar::_solve(Point* begin_point, Point* end_point) {
//check open list
SelfList<Point> *least_cost_point=NULL;
- float least_cost=1e30;
+ real_t least_cost=1e30;
//this could be faster (cache previous results)
for (SelfList<Point> *E=open_list.first();E;E=E->next()) {
Point *p=E->self();
- float cost=p->distance;
+ real_t cost=p->distance;
cost+=p->pos.distance_to(end_point->pos);
cost*=p->weight_scale;
@@ -249,7 +249,7 @@ bool AStar::_solve(Point* begin_point, Point* end_point) {
Point* e=p->neighbours[i];
- float distance = p->pos.distance_to(e->pos) + p->distance;
+ real_t distance = p->pos.distance_to(e->pos) + p->distance;
distance*=e->weight_scale;
diff --git a/core/math/a_star.h b/core/math/a_star.h
index 35e6ead226..c4c955ed2d 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -48,14 +48,14 @@ class AStar: public Reference {
int id;
Vector3 pos;
- float weight_scale;
+ real_t weight_scale;
uint64_t last_pass;
Vector<Point*> neighbours;
//used for pathfinding
Point *prev_point;
- float distance;
+ real_t distance;
Point() : list(this) {}
};
@@ -98,9 +98,9 @@ public:
int get_available_point_id() const;
- void add_point(int p_id,const Vector3& p_pos,float p_weight_scale=1);
+ void add_point(int p_id,const Vector3& p_pos,real_t p_weight_scale=1);
Vector3 get_point_pos(int p_id) const;
- float get_point_weight_scale(int p_id) const;
+ real_t get_point_weight_scale(int p_id) const;
void remove_point(int p_id);
void connect_points(int p_id,int p_with_id);
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index dbababf762..acd74903bb 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -3,8 +3,25 @@
#include "typedefs.h"
+
+static inline float undenormalise(volatile float f)
+{
+ union {
+ uint32_t i;
+ float f;
+ } v;
+
+ v.f = f;
+
+ // original: return (v.i & 0x7f800000) == 0 ? 0.0f : f;
+ // version from Tim Blechmann:
+ return (v.i & 0x7f800000) < 0x08000000 ? 0.0f : f;
+}
+
+
struct AudioFrame {
+ //left and right samples
float l,r;
_ALWAYS_INLINE_ const float& operator[](int idx) const { return idx==0?l:r; }
@@ -15,14 +32,30 @@ struct AudioFrame {
_ALWAYS_INLINE_ AudioFrame operator*(const AudioFrame& p_frame) const { return AudioFrame(l*p_frame.l,r*p_frame.r); }
_ALWAYS_INLINE_ AudioFrame operator/(const AudioFrame& p_frame) const { return AudioFrame(l/p_frame.l,r/p_frame.r); }
+ _ALWAYS_INLINE_ AudioFrame operator+(float p_sample) const { return AudioFrame(l+p_sample,r+p_sample); }
+ _ALWAYS_INLINE_ AudioFrame operator-(float p_sample) const { return AudioFrame(l-p_sample,r-p_sample); }
+ _ALWAYS_INLINE_ AudioFrame operator*(float p_sample) const { return AudioFrame(l*p_sample,r*p_sample); }
+ _ALWAYS_INLINE_ AudioFrame operator/(float p_sample) const { return AudioFrame(l/p_sample,r/p_sample); }
+
_ALWAYS_INLINE_ void operator+=(const AudioFrame& p_frame) { l+=p_frame.l; r+=p_frame.r; }
_ALWAYS_INLINE_ void operator-=(const AudioFrame& p_frame) { l-=p_frame.l; r-=p_frame.r; }
_ALWAYS_INLINE_ void operator*=(const AudioFrame& p_frame) { l*=p_frame.l; r*=p_frame.r; }
_ALWAYS_INLINE_ void operator/=(const AudioFrame& p_frame) { l/=p_frame.l; r/=p_frame.r; }
+ _ALWAYS_INLINE_ void operator+=(float p_sample) { l+=p_sample; r+=p_sample; }
+ _ALWAYS_INLINE_ void operator-=(float p_sample) { l-=p_sample; r-=p_sample; }
+ _ALWAYS_INLINE_ void operator*=(float p_sample) { l*=p_sample; r*=p_sample; }
+ _ALWAYS_INLINE_ void operator/=(float p_sample) { l/=p_sample; r/=p_sample; }
+
+ _ALWAYS_INLINE_ void undenormalise() {
+ l = ::undenormalise(l);
+ r = ::undenormalise(r);
+ }
+
_ALWAYS_INLINE_ AudioFrame(float p_l, float p_r) {l=p_l; r=p_r;}
_ALWAYS_INLINE_ AudioFrame(const AudioFrame& p_frame) {l=p_frame.l; r=p_frame.r;}
+ _ALWAYS_INLINE_ AudioFrame() {}
};
#endif
diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp
index e2526f5134..1ca6385032 100644
--- a/core/math/bsp_tree.cpp
+++ b/core/math/bsp_tree.cpp
@@ -87,8 +87,8 @@ int BSP_Tree::_get_points_inside(int p_node,const Vector3* p_points,int *p_indic
max+=p_center;
min+=p_center;
- float dist_min = p.distance_to(min);
- float dist_max = p.distance_to(max);
+ real_t dist_min = p.distance_to(min);
+ real_t dist_max = p.distance_to(max);
if ((dist_min * dist_max) < CMP_EPSILON ) { //intersection, test point by point
@@ -290,13 +290,13 @@ bool BSP_Tree::point_is_inside(const Vector3& p_point) const {
}
-static int _bsp_find_best_half_plane(const Face3* p_faces,const Vector<int>& p_indices,float p_tolerance) {
+static int _bsp_find_best_half_plane(const Face3* p_faces,const Vector<int>& p_indices,real_t p_tolerance) {
int ic = p_indices.size();
const int*indices=p_indices.ptr();
int best_plane = -1;
- float best_plane_cost = 1e20;
+ real_t best_plane_cost = 1e20;
// Loop to find the polygon that best divides the set.
@@ -317,7 +317,7 @@ static int _bsp_find_best_half_plane(const Face3* p_faces,const Vector<int>& p_i
for(int k=0;k<3;k++) {
- float d = p.distance_to(g.vertex[j]);
+ real_t d = p.distance_to(g.vertex[j]);
if (Math::abs(d)>p_tolerance) {
@@ -340,13 +340,13 @@ static int _bsp_find_best_half_plane(const Face3* p_faces,const Vector<int>& p_i
- //double split_cost = num_spanning / (double) face_count;
- double relation = Math::abs(num_over-num_under) / (double) ic;
+ //real_t split_cost = num_spanning / (real_t) face_count;
+ real_t relation = Math::abs(num_over-num_under) / (real_t) ic;
// being honest, i never found a way to add split cost to the mix in a meaninguful way
// in this engine, also, will likely be ignored anyway
- double plane_cost = /*split_cost +*/ relation;
+ real_t plane_cost = /*split_cost +*/ relation;
//printf("plane %i, %i over, %i under, %i spanning, cost is %g\n",i,num_over,num_under,num_spanning,plane_cost);
if (plane_cost<best_plane_cost) {
@@ -362,7 +362,7 @@ static int _bsp_find_best_half_plane(const Face3* p_faces,const Vector<int>& p_i
}
-static int _bsp_create_node(const Face3 *p_faces,const Vector<int>& p_indices,Vector<Plane> &p_planes, Vector<BSP_Tree::Node> &p_nodes,float p_tolerance) {
+static int _bsp_create_node(const Face3 *p_faces,const Vector<int>& p_indices,Vector<Plane> &p_planes, Vector<BSP_Tree::Node> &p_nodes,real_t p_tolerance) {
ERR_FAIL_COND_V( p_nodes.size() == BSP_Tree::MAX_NODES, -1 );
@@ -400,7 +400,7 @@ static int _bsp_create_node(const Face3 *p_faces,const Vector<int>& p_indices,Ve
for(int j=0;j<3;j++) {
- float d = divisor_plane.distance_to(f.vertex[j]);
+ real_t d = divisor_plane.distance_to(f.vertex[j]);
if (Math::abs(d)>p_tolerance) {
if (d > 0)
@@ -473,7 +473,7 @@ BSP_Tree::operator Variant() const {
Dictionary d;
d["error_radius"]=error_radius;
- Vector<float> plane_values;
+ Vector<real_t> plane_values;
plane_values.resize(planes.size()*4);
for(int i=0;i<planes.size();i++) {
@@ -522,13 +522,13 @@ BSP_Tree::BSP_Tree(const Variant& p_variant) {
if (d["planes"].get_type()==Variant::POOL_REAL_ARRAY) {
- PoolVector<float> src_planes=d["planes"];
+ PoolVector<real_t> src_planes=d["planes"];
int plane_count=src_planes.size();
ERR_FAIL_COND(plane_count%4);
planes.resize(plane_count/4);
if (plane_count) {
- PoolVector<float>::Read r = src_planes.read();
+ PoolVector<real_t>::Read r = src_planes.read();
for(int i=0;i<plane_count/4;i++) {
planes[i].normal.x=r[i*4+0];
@@ -562,7 +562,7 @@ BSP_Tree::BSP_Tree(const Variant& p_variant) {
}
-BSP_Tree::BSP_Tree(const PoolVector<Face3>& p_faces,float p_error_radius) {
+BSP_Tree::BSP_Tree(const PoolVector<Face3>& p_faces,real_t p_error_radius) {
// compute aabb
@@ -615,7 +615,7 @@ BSP_Tree::BSP_Tree(const PoolVector<Face3>& p_faces,float p_error_radius) {
error_radius=p_error_radius;
}
-BSP_Tree::BSP_Tree(const Vector<Node> &p_nodes, const Vector<Plane> &p_planes, const Rect3& p_aabb,float p_error_radius) {
+BSP_Tree::BSP_Tree(const Vector<Node> &p_nodes, const Vector<Plane> &p_planes, const Rect3& p_aabb,real_t p_error_radius) {
nodes=p_nodes;
planes=p_planes;
diff --git a/core/math/bsp_tree.h b/core/math/bsp_tree.h
index a64fffcb78..c0071438db 100644
--- a/core/math/bsp_tree.h
+++ b/core/math/bsp_tree.h
@@ -66,7 +66,7 @@ private:
Vector<Node> nodes;
Vector<Plane> planes;
Rect3 aabb;
- float error_radius;
+ real_t error_radius;
int _get_points_inside(int p_node,const Vector3* p_points,int *p_indices, const Vector3& p_center,const Vector3& p_half_extents,int p_indices_count) const;
@@ -91,8 +91,8 @@ public:
BSP_Tree();
BSP_Tree(const Variant& p_variant);
- BSP_Tree(const PoolVector<Face3>& p_faces,float p_error_radius=0);
- BSP_Tree(const Vector<Node> &p_nodes, const Vector<Plane> &p_planes, const Rect3& p_aabb,float p_error_radius=0);
+ BSP_Tree(const PoolVector<Face3>& p_faces,real_t p_error_radius=0);
+ BSP_Tree(const Vector<Node> &p_nodes, const Vector<Plane> &p_planes, const Rect3& p_aabb,real_t p_error_radius=0);
~BSP_Tree();
};
@@ -110,7 +110,7 @@ bool BSP_Tree::_test_convex(const Node* p_nodes, const Plane* p_planes,int p_cur
const Plane& p=p_planes[n.plane];
- float min,max;
+ real_t min,max;
p_convex.project_range(p.normal,min,max);
bool go_under = min < p.d;
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index 7669356f5e..3b47a75c65 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -65,15 +65,15 @@ Plane CameraMatrix::xform4(const Plane& p_vec4) const {
return ret;
}
-void CameraMatrix::set_perspective(float p_fovy_degrees, float p_aspect, float p_z_near, float p_z_far,bool p_flip_fov) {
+void CameraMatrix::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far,bool p_flip_fov) {
if (p_flip_fov) {
p_fovy_degrees=get_fovy(p_fovy_degrees,1.0/p_aspect);
}
- float sine, cotangent, deltaZ;
- float radians = p_fovy_degrees / 2.0 * Math_PI / 180.0;
+ real_t sine, cotangent, deltaZ;
+ real_t radians = p_fovy_degrees / 2.0 * Math_PI / 180.0;
deltaZ = p_z_far - p_z_near;
sine = Math::sin(radians);
@@ -94,7 +94,7 @@ void CameraMatrix::set_perspective(float p_fovy_degrees, float p_aspect, float p
}
-void CameraMatrix::set_orthogonal(float p_left, float p_right, float p_bottom, float p_top, float p_znear, float p_zfar) {
+void CameraMatrix::set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) {
set_identity();
@@ -109,7 +109,7 @@ void CameraMatrix::set_orthogonal(float p_left, float p_right, float p_bottom, f
}
-void CameraMatrix::set_orthogonal(float p_size, float p_aspect, float p_znear, float p_zfar,bool p_flip_fov) {
+void CameraMatrix::set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar,bool p_flip_fov) {
if (!p_flip_fov) {
p_size*=p_aspect;
@@ -120,7 +120,7 @@ void CameraMatrix::set_orthogonal(float p_size, float p_aspect, float p_znear, f
-void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, float p_top, float p_near, float p_far) {
+void CameraMatrix::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) {
#if 0
///@TODO, give a check to this. I'm not sure if it's working.
set_identity();
@@ -134,14 +134,14 @@ void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, floa
matrix[3][2]=-1;
matrix[3][3]=0;
#else
- float *te = &matrix[0][0];
- float x = 2 * p_near / ( p_right - p_left );
- float y = 2 * p_near / ( p_top - p_bottom );
+ real_t *te = &matrix[0][0];
+ real_t x = 2 * p_near / ( p_right - p_left );
+ real_t y = 2 * p_near / ( p_top - p_bottom );
- float a = ( p_right + p_left ) / ( p_right - p_left );
- float b = ( p_top + p_bottom ) / ( p_top - p_bottom );
- float c = - ( p_far + p_near ) / ( p_far - p_near );
- float d = - 2 * p_far * p_near / ( p_far - p_near );
+ real_t a = ( p_right + p_left ) / ( p_right - p_left );
+ real_t b = ( p_top + p_bottom ) / ( p_top - p_bottom );
+ real_t c = - ( p_far + p_near ) / ( p_far - p_near );
+ real_t d = - 2 * p_far * p_near / ( p_far - p_near );
te[0] = x;
te[1] = 0;
@@ -166,9 +166,9 @@ void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, floa
-float CameraMatrix::get_z_far() const {
+real_t CameraMatrix::get_z_far() const {
- const float * matrix = (const float*)this->matrix;
+ const real_t * matrix = (const real_t*)this->matrix;
Plane new_plane=Plane(matrix[ 3] - matrix[ 2],
matrix[ 7] - matrix[ 6],
matrix[11] - matrix[10],
@@ -179,9 +179,9 @@ float CameraMatrix::get_z_far() const {
return new_plane.d;
}
-float CameraMatrix::get_z_near() const {
+real_t CameraMatrix::get_z_near() const {
- const float * matrix = (const float*)this->matrix;
+ const real_t * matrix = (const real_t*)this->matrix;
Plane new_plane=Plane(matrix[ 3] + matrix[ 2],
matrix[ 7] + matrix[ 6],
matrix[11] + matrix[10],
@@ -191,9 +191,9 @@ float CameraMatrix::get_z_near() const {
return new_plane.d;
}
-void CameraMatrix::get_viewport_size(float& r_width, float& r_height) const {
+void CameraMatrix::get_viewport_size(real_t& r_width, real_t& r_height) const {
- const float * matrix = (const float*)this->matrix;
+ const real_t * matrix = (const real_t*)this->matrix;
///////--- Near Plane ---///////
Plane near_plane=Plane(matrix[ 3] + matrix[ 2],
matrix[ 7] + matrix[ 6],
@@ -223,7 +223,7 @@ void CameraMatrix::get_viewport_size(float& r_width, float& r_height) const {
bool CameraMatrix::get_endpoints(const Transform& p_transform, Vector3 *p_8points) const {
- const float * matrix = (const float*)this->matrix;
+ const real_t * matrix = (const real_t*)this->matrix;
///////--- Near Plane ---///////
Plane near_plane=Plane(matrix[ 3] + matrix[ 2],
@@ -284,7 +284,7 @@ Vector<Plane> CameraMatrix::get_projection_planes(const Transform& p_transform)
Vector<Plane> planes;
- const float * matrix = (const float*)this->matrix;
+ const real_t * matrix = (const real_t*)this->matrix;
Plane new_plane;
@@ -377,9 +377,9 @@ void CameraMatrix::invert() {
int i,j,k;
int pvt_i[4], pvt_j[4]; /* Locations of pivot matrix */
- float pvt_val; /* Value of current pivot element */
- float hold; /* Temporary storage */
- float determinat; /* Determinant */
+ real_t pvt_val; /* Value of current pivot element */
+ real_t hold; /* Temporary storage */
+ real_t determinat; /* Determinant */
determinat = 1.0;
for (k=0; k<4; k++) {
@@ -492,7 +492,7 @@ CameraMatrix CameraMatrix::operator*(const CameraMatrix& p_matrix) const {
void CameraMatrix::set_light_bias() {
- float *m=&matrix[0][0];
+ real_t *m=&matrix[0][0];
m[0]=0.5,
m[1]=0.0,
@@ -515,7 +515,7 @@ void CameraMatrix::set_light_bias() {
void CameraMatrix::set_light_atlas_rect(const Rect2& p_rect) {
- float *m=&matrix[0][0];
+ real_t *m=&matrix[0][0];
m[0]=p_rect.size.width,
m[1]=0.0,
@@ -545,9 +545,9 @@ CameraMatrix::operator String() const {
return str;
}
-float CameraMatrix::get_aspect() const {
+real_t CameraMatrix::get_aspect() const {
- float w,h;
+ real_t w,h;
get_viewport_size(w,h);
return w/h;
}
@@ -561,8 +561,8 @@ int CameraMatrix::get_pixels_per_meter(int p_for_pixel_width) const {
}
-float CameraMatrix::get_fov() const {
- const float * matrix = (const float*)this->matrix;
+real_t CameraMatrix::get_fov() const {
+ const real_t * matrix = (const real_t*)this->matrix;
Plane right_plane=Plane(matrix[ 3] - matrix[ 0],
matrix[ 7] - matrix[ 4],
@@ -613,7 +613,7 @@ void CameraMatrix::scale_translate_to_fit(const Rect3& p_aabb) {
CameraMatrix::operator Transform() const {
Transform tr;
- const float *m=&matrix[0][0];
+ const real_t *m=&matrix[0][0];
tr.basis.elements[0][0]=m[0];
tr.basis.elements[1][0]=m[1];
@@ -637,7 +637,7 @@ CameraMatrix::operator Transform() const {
CameraMatrix::CameraMatrix(const Transform& p_transform) {
const Transform &tr = p_transform;
- float *m=&matrix[0][0];
+ real_t *m=&matrix[0][0];
m[0]=tr.basis.elements[0][0];
m[1]=tr.basis.elements[1][0];
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index 952f1e8fb2..c96f8259b5 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -48,32 +48,32 @@ struct CameraMatrix {
PLANE_BOTTOM
};
- float matrix[4][4];
+ real_t matrix[4][4];
void set_identity();
void set_zero();
void set_light_bias();
void set_light_atlas_rect(const Rect2& p_rect);
- void set_perspective(float p_fovy_degrees, float p_aspect, float p_z_near, float p_z_far,bool p_flip_fov=false);
- void set_orthogonal(float p_left, float p_right, float p_bottom, float p_top, float p_znear, float p_zfar);
- void set_orthogonal(float p_size, float p_aspect, float p_znear, float p_zfar,bool p_flip_fov=false);
- void set_frustum(float p_left, float p_right, float p_bottom, float p_top, float p_near, float p_far);
+ void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far,bool p_flip_fov=false);
+ void set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar);
+ void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar,bool p_flip_fov=false);
+ void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
- static float get_fovy(float p_fovx,float p_aspect) {
+ static real_t get_fovy(real_t p_fovx,real_t p_aspect) {
return Math::rad2deg(Math::atan(p_aspect * Math::tan(Math::deg2rad(p_fovx) * 0.5))*2.0);
}
- float get_z_far() const;
- float get_z_near() const;
- float get_aspect() const;
- float get_fov() const;
+ real_t get_z_far() const;
+ real_t get_z_near() const;
+ real_t get_aspect() const;
+ real_t get_fov() const;
Vector<Plane> get_projection_planes(const Transform& p_transform) const;
bool get_endpoints(const Transform& p_transform,Vector3 *p_8points) const;
- void get_viewport_size(float& r_width, float& r_height) const;
+ void get_viewport_size(real_t& r_width, real_t& r_height) const;
void invert();
CameraMatrix inverse() const;
@@ -102,7 +102,7 @@ Vector3 CameraMatrix::xform(const Vector3& p_vec3) const {
ret.x = matrix[0][0] * p_vec3.x + matrix[1][0] * p_vec3.y + matrix[2][0] * p_vec3.z + matrix[3][0];
ret.y = matrix[0][1] * p_vec3.x + matrix[1][1] * p_vec3.y + matrix[2][1] * p_vec3.z + matrix[3][1];
ret.z = matrix[0][2] * p_vec3.x + matrix[1][2] * p_vec3.y + matrix[2][2] * p_vec3.z + matrix[3][2];
- float w = matrix[0][3] * p_vec3.x + matrix[1][3] * p_vec3.y + matrix[2][3] * p_vec3.z + matrix[3][3];
+ real_t w = matrix[0][3] * p_vec3.x + matrix[1][3] * p_vec3.y + matrix[2][3] * p_vec3.z + matrix[3][3];
return ret/w;
}
diff --git a/core/math/face3.cpp b/core/math/face3.cpp
index faf124593e..60fab6748a 100644
--- a/core/math/face3.cpp
+++ b/core/math/face3.cpp
@@ -168,8 +168,8 @@ Face3::Side Face3::get_side_of(const Face3& p_face,ClockDirection p_clock_dir) c
Vector3 Face3::get_random_point_inside() const {
- float a=Math::random(0,1);
- float b=Math::random(0,1);
+ real_t a=Math::random(0,1);
+ real_t b=Math::random(0,1);
if (a>b) {
SWAP(a,b);
}
@@ -215,9 +215,9 @@ bool Face3::intersects_aabb(const Rect3& p_aabb) const {
#define TEST_AXIS(m_ax)\
{\
- float aabb_min=p_aabb.pos.m_ax;\
- float aabb_max=p_aabb.pos.m_ax+p_aabb.size.m_ax;\
- float tri_min,tri_max;\
+ real_t aabb_min=p_aabb.pos.m_ax;\
+ real_t aabb_max=p_aabb.pos.m_ax+p_aabb.size.m_ax;\
+ real_t tri_min,tri_max;\
for (int i=0;i<3;i++) {\
if (i==0 || vertex[i].m_ax > tri_max)\
tri_max=vertex[i].m_ax;\
@@ -255,7 +255,7 @@ bool Face3::intersects_aabb(const Rect3& p_aabb) const {
continue; // coplanar
axis.normalize();
- float minA,maxA,minB,maxB;
+ real_t minA,maxA,minB,maxB;
p_aabb.project_range_in_plane(Plane(axis,0),minA,maxA);
project_range(axis,Transform(),minB,maxB);
@@ -272,12 +272,12 @@ Face3::operator String() const {
return String()+vertex[0]+", "+vertex[1]+", "+vertex[2];
}
-void Face3::project_range(const Vector3& p_normal,const Transform& p_transform,float& r_min, float& r_max) const {
+void Face3::project_range(const Vector3& p_normal,const Transform& p_transform,real_t& r_min, real_t& r_max) const {
for (int i=0;i<3;i++) {
Vector3 v=p_transform.xform(vertex[i]);
- float d=p_normal.dot(v);
+ real_t d=p_normal.dot(v);
if (i==0 || d > r_max)
r_max=d;
@@ -316,11 +316,11 @@ void Face3::get_support(const Vector3& p_normal,const Transform& p_transform,Vec
/** FIND SUPPORT VERTEX **/
int vert_support_idx=-1;
- float support_max;
+ real_t support_max;
for (int i=0;i<3;i++) {
- float d=n.dot(vertex[i]);
+ real_t d=n.dot(vertex[i]);
if (i==0 || d > support_max) {
support_max=d;
@@ -336,7 +336,7 @@ void Face3::get_support(const Vector3& p_normal,const Transform& p_transform,Vec
continue;
// check if edge is valid as a support
- float dot=(vertex[i]-vertex[(i+1)%3]).normalized().dot(n);
+ real_t dot=(vertex[i]-vertex[(i+1)%3]).normalized().dot(n);
dot=ABS(dot);
if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD) {
@@ -362,15 +362,15 @@ Vector3 Face3::get_closest_point_to(const Vector3& p_point) const {
Vector3 edge1 = vertex[2] - vertex[0];
Vector3 v0 = vertex[0] - p_point;
- float a = edge0.dot( edge0 );
- float b = edge0.dot( edge1 );
- float c = edge1.dot( edge1 );
- float d = edge0.dot( v0 );
- float e = edge1.dot( v0 );
+ real_t a = edge0.dot( edge0 );
+ real_t b = edge0.dot( edge1 );
+ real_t c = edge1.dot( edge1 );
+ real_t d = edge0.dot( v0 );
+ real_t e = edge1.dot( v0 );
- float det = a*c - b*b;
- float s = b*e - c*d;
- float t = b*d - a*e;
+ real_t det = a*c - b*b;
+ real_t s = b*e - c*d;
+ real_t t = b*d - a*e;
if ( s + t < det )
{
@@ -402,7 +402,7 @@ Vector3 Face3::get_closest_point_to(const Vector3& p_point) const {
}
else
{
- float invDet = 1.f / det;
+ real_t invDet = 1.f / det;
s *= invDet;
t *= invDet;
}
@@ -411,12 +411,12 @@ Vector3 Face3::get_closest_point_to(const Vector3& p_point) const {
{
if ( s < 0.f )
{
- float tmp0 = b+d;
- float tmp1 = c+e;
+ real_t tmp0 = b+d;
+ real_t tmp1 = c+e;
if ( tmp1 > tmp0 )
{
- float numer = tmp1 - tmp0;
- float denom = a-2*b+c;
+ real_t numer = tmp1 - tmp0;
+ real_t denom = a-2*b+c;
s = CLAMP( numer/denom, 0.f, 1.f );
t = 1-s;
}
@@ -430,8 +430,8 @@ Vector3 Face3::get_closest_point_to(const Vector3& p_point) const {
{
if ( a+d > b+e )
{
- float numer = c+e-b-d;
- float denom = a-2*b+c;
+ real_t numer = c+e-b-d;
+ real_t denom = a-2*b+c;
s = CLAMP( numer/denom, 0.f, 1.f );
t = 1-s;
}
@@ -443,8 +443,8 @@ Vector3 Face3::get_closest_point_to(const Vector3& p_point) const {
}
else
{
- float numer = c+e-b-d;
- float denom = a-2*b+c;
+ real_t numer = c+e-b-d;
+ real_t denom = a-2*b+c;
s = CLAMP( numer/denom, 0.f, 1.f );
t = 1.f - s;
}
diff --git a/core/math/face3.h b/core/math/face3.h
index e957f64320..a0da588ea5 100644
--- a/core/math/face3.h
+++ b/core/math/face3.h
@@ -76,7 +76,7 @@ public:
ClockDirection get_clock_dir() const; ///< todo, test if this is returning the proper clockwisity
void get_support(const Vector3& p_normal,const Transform& p_transform,Vector3 *p_vertices,int* p_count,int p_max) const;
- void project_range(const Vector3& p_normal,const Transform& p_transform,float& r_min, float& r_max) const;
+ void project_range(const Vector3& p_normal,const Transform& p_transform,real_t& r_min, real_t& r_max) const;
Rect3 get_aabb() const {
@@ -109,9 +109,9 @@ bool Face3::intersects_aabb2(const Rect3& p_aabb) const {
(perp.z>0) ? -half_extents.z : half_extents.z
);
- float d = perp.dot(vertex[0]);
- float dist_a = perp.dot(ofs+sup)-d;
- float dist_b = perp.dot(ofs-sup)-d;
+ real_t d = perp.dot(vertex[0]);
+ real_t dist_a = perp.dot(ofs+sup)-d;
+ real_t dist_b = perp.dot(ofs-sup)-d;
if (dist_a*dist_b > 0)
return false; //does not intersect the plane
@@ -119,9 +119,9 @@ bool Face3::intersects_aabb2(const Rect3& p_aabb) const {
#define TEST_AXIS(m_ax)\
{\
- float aabb_min=p_aabb.pos.m_ax;\
- float aabb_max=p_aabb.pos.m_ax+p_aabb.size.m_ax;\
- float tri_min,tri_max;\
+ real_t aabb_min=p_aabb.pos.m_ax;\
+ real_t aabb_max=p_aabb.pos.m_ax+p_aabb.size.m_ax;\
+ real_t tri_min,tri_max;\
for (int i=0;i<3;i++) {\
if (i==0 || vertex[i].m_ax > tri_max)\
tri_max=vertex[i].m_ax;\
@@ -236,16 +236,16 @@ bool Face3::intersects_aabb2(const Rect3& p_aabb) const {
(axis.z>0) ? -half_extents.z : half_extents.z
);
- float maxB = axis.dot(ofs+sup2);
- float minB = axis.dot(ofs-sup2);
+ real_t maxB = axis.dot(ofs+sup2);
+ real_t minB = axis.dot(ofs-sup2);
if (minB>maxB) {
SWAP(maxB,minB);
}
- float minT=1e20,maxT=-1e20;
+ real_t minT=1e20,maxT=-1e20;
for (int k=0;k<3;k++) {
- float d=axis.dot(vertex[k]);
+ real_t d=axis.dot(vertex[k]);
if (d > maxT)
maxT=d;
diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp
index bf3364a052..6570dfe672 100644
--- a/core/math/geometry.cpp
+++ b/core/math/geometry.cpp
@@ -580,7 +580,7 @@ static inline void _build_faces(uint8_t*** p_cell_status,int x,int y,int z,int l
}
-PoolVector< Face3 > Geometry::wrap_geometry( PoolVector< Face3 > p_array,float *p_error ) {
+PoolVector< Face3 > Geometry::wrap_geometry( PoolVector< Face3 > p_array,real_t *p_error ) {
#define _MIN_SIZE 1.0
#define _MAX_LENGTH 20
@@ -755,7 +755,7 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes
#define SUBPLANE_SIZE 1024.0
- float subplane_size = 1024.0; // should compute this from the actual plane
+ real_t subplane_size = 1024.0; // should compute this from the actual plane
for (int i=0;i<p_planes.size();i++) {
Plane p =p_planes[i];
@@ -910,7 +910,7 @@ PoolVector<Plane> Geometry::build_box_planes(const Vector3& p_extents) {
return planes;
}
-PoolVector<Plane> Geometry::build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis) {
+PoolVector<Plane> Geometry::build_cylinder_planes(real_t p_radius, real_t p_height, int p_sides, Vector3::Axis p_axis) {
PoolVector<Plane> planes;
@@ -933,7 +933,7 @@ PoolVector<Plane> Geometry::build_cylinder_planes(float p_radius, float p_height
}
-PoolVector<Plane> Geometry::build_sphere_planes(float p_radius, int p_lats,int p_lons, Vector3::Axis p_axis) {
+PoolVector<Plane> Geometry::build_sphere_planes(real_t p_radius, int p_lats,int p_lons, Vector3::Axis p_axis) {
PoolVector<Plane> planes;
@@ -957,7 +957,7 @@ PoolVector<Plane> Geometry::build_sphere_planes(float p_radius, int p_lats,int p
for (int j=1;j<=p_lats;j++) {
//todo this is stupid, fix
- Vector3 angle = normal.linear_interpolate(axis,j/(float)p_lats).normalized();
+ Vector3 angle = normal.linear_interpolate(axis,j/(real_t)p_lats).normalized();
Vector3 pos = angle*p_radius;
planes.push_back( Plane( pos, angle ) );
planes.push_back( Plane( pos * axis_neg, angle * axis_neg) );
@@ -969,7 +969,7 @@ PoolVector<Plane> Geometry::build_sphere_planes(float p_radius, int p_lats,int p
}
-PoolVector<Plane> Geometry::build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis) {
+PoolVector<Plane> Geometry::build_capsule_planes(real_t p_radius, real_t p_height, int p_sides, int p_lats, Vector3::Axis p_axis) {
PoolVector<Plane> planes;
@@ -991,7 +991,7 @@ PoolVector<Plane> Geometry::build_capsule_planes(float p_radius, float p_height,
for (int j=1;j<=p_lats;j++) {
- Vector3 angle = normal.linear_interpolate(axis,j/(float)p_lats).normalized();
+ Vector3 angle = normal.linear_interpolate(axis,j/(real_t)p_lats).normalized();
Vector3 pos = axis*p_height*0.5 + angle*p_radius;
planes.push_back( Plane( pos, angle ) );
planes.push_back( Plane( pos * axis_neg, angle * axis_neg) );
@@ -1108,13 +1108,13 @@ void Geometry::make_atlas(const Vector<Size2i>& p_rects,Vector<Point2i>& r_resul
//find the result with the best aspect ratio
int best=-1;
- float best_aspect=1e20;
+ real_t best_aspect=1e20;
for(int i=0;i<results.size();i++) {
- float h = nearest_power_of_2(results[i].max_h);
- float w = nearest_power_of_2(results[i].max_w);
- float aspect = h>w ? h/w : w/h;
+ real_t h = nearest_power_of_2(results[i].max_h);
+ real_t w = nearest_power_of_2(results[i].max_w);
+ real_t aspect = h>w ? h/w : w/h;
if (aspect < best_aspect) {
best=i;
best_aspect=aspect;
diff --git a/core/math/geometry.h b/core/math/geometry.h
index 25f5e11fcf..13cbbdce6f 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -48,15 +48,15 @@ public:
- static float get_closest_points_between_segments( const Vector2& p1,const Vector2& q1, const Vector2& p2,const Vector2& q2, Vector2& c1, Vector2& c2) {
+ static real_t get_closest_points_between_segments( const Vector2& p1,const Vector2& q1, const Vector2& p2,const Vector2& q2, Vector2& c1, Vector2& c2) {
Vector2 d1 = q1 - p1; // Direction vector of segment S1
Vector2 d2 = q2 - p2; // Direction vector of segment S2
Vector2 r = p1 - p2;
- float a = d1.dot(d1); // Squared length of segment S1, always nonnegative
- float e = d2.dot(d2); // Squared length of segment S2, always nonnegative
- float f = d2.dot(r);
- float s,t;
+ real_t a = d1.dot(d1); // Squared length of segment S1, always nonnegative
+ real_t e = d2.dot(d2); // Squared length of segment S2, always nonnegative
+ real_t f = d2.dot(r);
+ real_t s,t;
// Check if either or both segments degenerate into points
if (a <= CMP_EPSILON && e <= CMP_EPSILON) {
// Both segments degenerate into points
@@ -66,25 +66,25 @@ public:
}
if (a <= CMP_EPSILON) {
// First segment degenerates into a point
- s = 0.0f;
+ s = 0.0;
t = f / e; // s = 0 => t = (b*s + f) / e = f / e
- t = CLAMP(t, 0.0f, 1.0f);
+ t = CLAMP(t, 0.0, 1.0);
} else {
- float c = d1.dot(r);
+ real_t c = d1.dot(r);
if (e <= CMP_EPSILON) {
// Second segment degenerates into a point
- t = 0.0f;
- s = CLAMP(-c / a, 0.0f, 1.0f); // t = 0 => s = (b*t - c) / a = -c / a
+ t = 0.0;
+ s = CLAMP(-c / a, 0.0, 1.0); // t = 0 => s = (b*t - c) / a = -c / a
} else {
// The general nondegenerate case starts here
- float b = d1.dot(d2);
- float denom = a*e-b*b; // Always nonnegative
+ real_t b = d1.dot(d2);
+ real_t denom = a*e-b*b; // Always nonnegative
// If segments not parallel, compute closest point on L1 to L2 and
// clamp to segment S1. Else pick arbitrary s (here 0)
- if (denom != 0.0f) {
- s = CLAMP((b*f - c*e) / denom, 0.0f, 1.0f);
+ if (denom != 0.0) {
+ s = CLAMP((b*f - c*e) / denom, 0.0, 1.0);
} else
- s = 0.0f;
+ s = 0.0;
// Compute point on L2 closest to S1(s) using
// t = Dot((P1 + D1*s) - P2,D2) / Dot(D2,D2) = (b*s + f) / e
t = (b*s + f) / e;
@@ -92,12 +92,12 @@ public:
//If t in [0,1] done. Else clamp t, recompute s for the new value
// of t using s = Dot((P2 + D2*t) - P1,D1) / Dot(D1,D1)= (t*b - c) / a
// and clamp s to [0, 1]
- if (t < 0.0f) {
- t = 0.0f;
- s = CLAMP(-c / a, 0.0f, 1.0f);
- } else if (t > 1.0f) {
- t = 1.0f;
- s = CLAMP((b - c) / a, 0.0f, 1.0f);
+ if (t < 0.0) {
+ t = 0.0;
+ s = CLAMP(-c / a, 0.0, 1.0);
+ } else if (t > 1.0) {
+ t = 1.0;
+ s = CLAMP((b - c) / a, 0.0, 1.0);
}
}
}
@@ -113,8 +113,8 @@ public:
#define d_of(m,n,o,p) ( (m.x - n.x) * (o.x - p.x) + (m.y - n.y) * (o.y - p.y) + (m.z - n.z) * (o.z - p.z) )
//caluclate the parpametric position on the 2 curves, mua and mub
- float mua = ( d_of(p1,q1,q2,q1) * d_of(q2,q1,p2,p1) - d_of(p1,q1,p2,p1) * d_of(q2,q1,q2,q1) ) / ( d_of(p2,p1,p2,p1) * d_of(q2,q1,q2,q1) - d_of(q2,q1,p2,p1) * d_of(q2,q1,p2,p1) );
- float mub = ( d_of(p1,q1,q2,q1) + mua * d_of(q2,q1,p2,p1) ) / d_of(q2,q1,q2,q1);
+ real_t mua = ( d_of(p1,q1,q2,q1) * d_of(q2,q1,p2,p1) - d_of(p1,q1,p2,p1) * d_of(q2,q1,q2,q1) ) / ( d_of(p2,p1,p2,p1) * d_of(q2,q1,q2,q1) - d_of(q2,q1,p2,p1) * d_of(q2,q1,p2,p1) );
+ real_t mub = ( d_of(p1,q1,q2,q1) + mua * d_of(q2,q1,p2,p1) ) / d_of(q2,q1,q2,q1);
//clip the value between [0..1] constraining the solution to lie on the original curves
if (mua < 0) mua = 0;
@@ -125,7 +125,7 @@ public:
c2 = q1.linear_interpolate(q2,mub);
}
- static float get_closest_distance_between_segments( const Vector3& p_from_a,const Vector3& p_to_a, const Vector3& p_from_b,const Vector3& p_to_b) {
+ static real_t get_closest_distance_between_segments( const Vector3& p_from_a,const Vector3& p_to_a, const Vector3& p_from_b,const Vector3& p_to_b) {
Vector3 u = p_to_a - p_from_a;
Vector3 v = p_to_b - p_from_b;
Vector3 w = p_from_a - p_to_a;
@@ -273,22 +273,22 @@ public:
Vector3 sphere_pos=p_sphere_pos-p_from;
Vector3 rel=(p_to-p_from);
- float rel_l=rel.length();
+ real_t rel_l=rel.length();
if (rel_l<CMP_EPSILON)
return false; // both points are the same
Vector3 normal=rel/rel_l;
- float sphere_d=normal.dot(sphere_pos);
+ real_t sphere_d=normal.dot(sphere_pos);
//Vector3 ray_closest=normal*sphere_d;
- float ray_distance=sphere_pos.distance_to(normal*sphere_d);
+ real_t ray_distance=sphere_pos.distance_to(normal*sphere_d);
if (ray_distance>=p_sphere_radius)
return false;
- float inters_d2=p_sphere_radius*p_sphere_radius - ray_distance*ray_distance;
- float inters_d=sphere_d;
+ real_t inters_d2=p_sphere_radius*p_sphere_radius - ray_distance*ray_distance;
+ real_t inters_d=sphere_d;
if (inters_d2>=CMP_EPSILON)
inters_d-=Math::sqrt(inters_d2);
@@ -307,17 +307,17 @@ public:
return true;
}
- static inline bool segment_intersects_cylinder( const Vector3& p_from, const Vector3& p_to, float p_height,float p_radius,Vector3* r_res=0,Vector3 *r_norm=0) {
+ static inline bool segment_intersects_cylinder( const Vector3& p_from, const Vector3& p_to, real_t p_height,real_t p_radius,Vector3* r_res=0,Vector3 *r_norm=0) {
Vector3 rel=(p_to-p_from);
- float rel_l=rel.length();
+ real_t rel_l=rel.length();
if (rel_l<CMP_EPSILON)
return false; // both points are the same
// first check if they are parallel
Vector3 normal=(rel/rel_l);
Vector3 crs = normal.cross(Vector3(0,0,1));
- float crs_l=crs.length();
+ real_t crs_l=crs.length();
Vector3 z_dir;
@@ -328,13 +328,13 @@ public:
z_dir=crs/crs_l;
}
- float dist=z_dir.dot(p_from);
+ real_t dist=z_dir.dot(p_from);
if (dist>=p_radius)
return false; // too far away
// convert to 2D
- float w2=p_radius*p_radius-dist*dist;
+ real_t w2=p_radius*p_radius-dist*dist;
if (w2<CMP_EPSILON)
return false; //avoid numerical error
Size2 size(Math::sqrt(w2),p_height*0.5);
@@ -344,7 +344,7 @@ public:
Vector2 from2D(x_dir.dot(p_from),p_from.z);
Vector2 to2D(x_dir.dot(p_to),p_to.z);
- float min=0,max=1;
+ real_t min=0,max=1;
int axis=-1;
@@ -464,12 +464,12 @@ public:
Vector3 p=p_point-p_segment[0];
Vector3 n=p_segment[1]-p_segment[0];
- float l =n.length();
+ real_t l =n.length();
if (l<1e-10)
return p_segment[0]; // both points are the same, just give any
n/=l;
- float d=n.dot(p);
+ real_t d=n.dot(p);
if (d<=0.0)
return p_segment[0]; // before first point
@@ -483,12 +483,12 @@ public:
Vector3 p=p_point-p_segment[0];
Vector3 n=p_segment[1]-p_segment[0];
- float l =n.length();
+ real_t l =n.length();
if (l<1e-10)
return p_segment[0]; // both points are the same, just give any
n/=l;
- float d=n.dot(p);
+ real_t d=n.dot(p);
return p_segment[0]+n*d; // inside
}
@@ -497,12 +497,12 @@ public:
Vector2 p=p_point-p_segment[0];
Vector2 n=p_segment[1]-p_segment[0];
- float l =n.length();
+ real_t l =n.length();
if (l<1e-10)
return p_segment[0]; // both points are the same, just give any
n/=l;
- float d=n.dot(p);
+ real_t d=n.dot(p);
if (d<=0.0)
return p_segment[0]; // before first point
@@ -529,12 +529,12 @@ public:
Vector2 p=p_point-p_segment[0];
Vector2 n=p_segment[1]-p_segment[0];
- float l =n.length();
+ real_t l =n.length();
if (l<1e-10)
return p_segment[0]; // both points are the same, just give any
n/=l;
- float d=n.dot(p);
+ real_t d=n.dot(p);
return p_segment[0]+n*d; // inside
}
@@ -555,7 +555,7 @@ public:
if ((C.y<0 && D.y<0) || (C.y>=0 && D.y>=0))
return false;
- float ABpos=D.x+(C.x-D.x)*D.y/(D.y-C.y);
+ real_t ABpos=D.x+(C.x-D.x)*D.y/(D.y-C.y);
// Fail if segment C-D crosses line A-B outside of segment A-B.
if (ABpos<0 || ABpos>1.0)
@@ -595,7 +595,7 @@ public:
static inline bool triangle_sphere_intersection_test(const Vector3 *p_triangle,const Vector3& p_normal,const Vector3& p_sphere_pos, real_t p_sphere_radius,Vector3& r_triangle_contact,Vector3& r_sphere_contact) {
- float d=p_normal.dot(p_sphere_pos)-p_normal.dot(p_triangle[0]);
+ real_t d=p_normal.dot(p_sphere_pos)-p_normal.dot(p_triangle[0]);
if (d > p_sphere_radius || d < -p_sphere_radius) // not touching the plane of the face, return
return false;
@@ -629,7 +629,7 @@ public:
Vector3 axis =n1.cross(n2).cross(n1);
axis.normalize(); // ugh
- float ad=axis.dot(n2);
+ real_t ad=axis.dot(n2);
if (ABS(ad)>p_sphere_radius) {
// no chance with this edge, too far away
@@ -639,7 +639,7 @@ public:
// check point within edge capsule cylinder
/** 4th TEST INSIDE EDGE POINTS **/
- float sphere_at = n1.dot(n2);
+ real_t sphere_at = n1.dot(n2);
if (sphere_at>=0 && sphere_at<n1.dot(n1)) {
@@ -650,7 +650,7 @@ public:
return true;
}
- float r2=p_sphere_radius*p_sphere_radius;
+ real_t r2=p_sphere_radius*p_sphere_radius;
if (n2.length_squared()<r2) {
@@ -726,8 +726,8 @@ public:
int outside_count = 0;
for (int a = 0; a < polygon.size(); a++) {
- //float p_plane.d = (*this) * polygon[a];
- float dist = p_plane.distance_to(polygon[a]);
+ //real_t p_plane.d = (*this) * polygon[a];
+ real_t dist = p_plane.distance_to(polygon[a]);
if (dist <-CMP_POINT_IN_PLANE_EPSILON) {
location_cache[a] = LOC_INSIDE;
inside_count++;
@@ -761,8 +761,8 @@ public:
const Vector3& v2 = polygon[index];
Vector3 segment= v1 - v2;
- double den=p_plane.normal.dot( segment );
- double dist=p_plane.distance_to( v1 ) / den;
+ real_t den=p_plane.normal.dot( segment );
+ real_t dist=p_plane.distance_to( v1 ) / den;
dist=-dist;
clipped.push_back( v1 + segment * dist );
}
@@ -771,8 +771,8 @@ public:
if ((loc == LOC_INSIDE) && (location_cache[previous] == LOC_OUTSIDE)) {
const Vector3& v2 = polygon[previous];
Vector3 segment= v1 - v2;
- double den=p_plane.normal.dot( segment );
- double dist=p_plane.distance_to( v1 ) / den;
+ real_t den=p_plane.normal.dot( segment );
+ real_t dist=p_plane.distance_to( v1 ) / den;
dist=-dist;
clipped.push_back( v1 + segment * dist );
}
@@ -808,7 +808,7 @@ public:
static PoolVector< PoolVector< Face3 > > separate_objects( PoolVector< Face3 > p_array );
- static PoolVector< Face3 > wrap_geometry( PoolVector< Face3 > p_array, float *p_error=NULL ); ///< create a "wrap" that encloses the given geometry
+ static PoolVector< Face3 > wrap_geometry( PoolVector< Face3 > p_array, real_t *p_error=NULL ); ///< create a "wrap" that encloses the given geometry
struct MeshData {
@@ -884,9 +884,9 @@ public:
}
- static double vec2_cross(const Point2 &O, const Point2 &A, const Point2 &B)
+ static real_t vec2_cross(const Point2 &O, const Point2 &A, const Point2 &B)
{
- return (double)(A.x - O.x) * (B.y - O.y) - (double)(A.y - O.y) * (B.x - O.x);
+ return (real_t)(A.x - O.x) * (B.y - O.y) - (real_t)(A.y - O.y) * (B.x - O.x);
}
// Returns a list of points on the convex hull in counter-clockwise order.
@@ -918,10 +918,10 @@ public:
}
static MeshData build_convex_mesh(const PoolVector<Plane> &p_planes);
- static PoolVector<Plane> build_sphere_planes(float p_radius, int p_lats, int p_lons, Vector3::Axis p_axis=Vector3::AXIS_Z);
+ static PoolVector<Plane> build_sphere_planes(real_t p_radius, int p_lats, int p_lons, Vector3::Axis p_axis=Vector3::AXIS_Z);
static PoolVector<Plane> build_box_planes(const Vector3& p_extents);
- static PoolVector<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis=Vector3::AXIS_Z);
- static PoolVector<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis=Vector3::AXIS_Z);
+ static PoolVector<Plane> build_cylinder_planes(real_t p_radius, real_t p_height, int p_sides, Vector3::Axis p_axis=Vector3::AXIS_Z);
+ static PoolVector<Plane> build_capsule_planes(real_t p_radius, real_t p_height, int p_sides, int p_lats, Vector3::Axis p_axis=Vector3::AXIS_Z);
static void make_atlas(const Vector<Size2i>& p_rects,Vector<Point2i>& r_result, Size2i& r_size);
diff --git a/core/math/math_2d.cpp b/core/math/math_2d.cpp
index c6860ba2e8..76eeece688 100644
--- a/core/math/math_2d.cpp
+++ b/core/math/math_2d.cpp
@@ -239,10 +239,10 @@ Vector2 Vector2::cubic_interpolate(const Vector2& p_b,const Vector2& p_pre_a, co
real_t t3 = t2 * t;
Vector2 out;
- out = 0.5f * ( ( p1 * 2.0f) +
+ out = 0.5 * ( ( p1 * 2.0) +
( -p0 + p2 ) * t +
- ( 2.0f * p0 - 5.0f * p1 + 4 * p2 - p3 ) * t2 +
- ( -p0 + 3.0f * p1 - 3.0f * p2 + p3 ) * t3 );
+ ( 2.0 * p0 - 5.0 * p1 + 4 * p2 - p3 ) * t2 +
+ ( -p0 + 3.0 * p1 - 3.0 * p2 + p3 ) * t3 );
return out;
/*
diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp
index 70b1f303a5..c730b4fa30 100644
--- a/core/math/math_funcs.cpp
+++ b/core/math/math_funcs.cpp
@@ -59,35 +59,8 @@ uint32_t Math::rand() {
return pcg32_random_r(&default_pcg);
}
-double Math::randf() {
-
- return (double)rand() / (double)Math::RANDOM_MAX;
-}
-
-
-double Math::round(double p_val) {
-
- if (p_val>=0) {
- return ::floor(p_val+0.5);
- } else {
- p_val=-p_val;
- return -::floor(p_val+0.5);
- }
-}
-
-double Math::dectime(double p_value,double p_amount, double p_step) {
-
- float sgn = p_value < 0 ? -1.0 : 1.0;
- float val = absf(p_value);
- val-=p_amount*p_step;
- if (val<0.0)
- val=0.0;
- return val*sgn;
-}
-
int Math::step_decimals(double p_step) {
-
static const int maxn=9;
static const double sd[maxn]={
0.9999, // somehow compensate for floating point error
@@ -101,7 +74,7 @@ int Math::step_decimals(double p_step) {
0.000000009999
};
- double as=absf(p_step);
+ double as=Math::abs(p_step);
for(int i=0;i<maxn;i++) {
if (as>=sd[i]) {
return i;
@@ -111,8 +84,16 @@ int Math::step_decimals(double p_step) {
return maxn;
}
-double Math::ease(double p_x, double p_c) {
+double Math::dectime(double p_value,double p_amount, double p_step) {
+ double sgn = p_value < 0 ? -1.0 : 1.0;
+ double val = Math::abs(p_value);
+ val-=p_amount*p_step;
+ if (val<0.0)
+ val=0.0;
+ return val*sgn;
+}
+double Math::ease(double p_x, double p_c) {
if (p_x<0)
p_x=0;
else if (p_x>1.0)
@@ -133,20 +114,16 @@ double Math::ease(double p_x, double p_c) {
}
} else
return 0; // no ease (raw)
-
}
double Math::stepify(double p_value,double p_step) {
-
if (p_step!=0) {
-
- p_value=floor( p_value / p_step + 0.5 ) * p_step;
+ p_value=Math::floor( p_value / p_step + 0.5 ) * p_step;
}
return p_value;
}
-
uint32_t Math::larger_prime(uint32_t p_val) {
static const uint32_t primes[] = {
@@ -195,22 +172,15 @@ uint32_t Math::larger_prime(uint32_t p_val) {
}
double Math::random(double from, double to) {
-
unsigned int r = Math::rand();
double ret = (double)r/(double)RANDOM_MAX;
return (ret)*(to-from) + from;
}
-double Math::pow(double x, double y) {
-
- return ::pow(x,y);
+float Math::random(float from, float to) {
+ unsigned int r = Math::rand();
+ float ret = (float)r/(float)RANDOM_MAX;
+ return (ret)*(to-from) + from;
}
-double Math::log(double x) {
-
- return ::log(x);
-}
-double Math::exp(double x) {
- return ::exp(x);
-}
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 665182afcf..511af91835 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -38,6 +38,7 @@
#define Math_PI 3.14159265358979323846
#define Math_SQRT12 0.7071067811865475244008443621048490
+#define Math_LN2 0.693147180559945309417
class Math {
@@ -51,149 +52,122 @@ public:
};
- static _ALWAYS_INLINE_ double sin(double p_x) {
+ static _ALWAYS_INLINE_ double sin(double p_x) { return ::sin(p_x); }
+ static _ALWAYS_INLINE_ float sin(float p_x) { return ::sinf(p_x); }
- return ::sin(p_x);
+ static _ALWAYS_INLINE_ double cos(double p_x) { return ::cos(p_x); }
+ static _ALWAYS_INLINE_ float cos(float p_x) { return ::cosf(p_x); }
- }
-
- static _ALWAYS_INLINE_ double cos(double p_x) {
-
- return ::cos(p_x);
-
- }
-
- static _ALWAYS_INLINE_ double tan(double p_x) {
-
- return ::tan(p_x);
-
- }
- static _ALWAYS_INLINE_ double sinh(double p_x) {
-
- return ::sinh(p_x);
- }
+ static _ALWAYS_INLINE_ double tan(double p_x) { return ::tan(p_x); }
+ static _ALWAYS_INLINE_ float tan(float p_x) { return ::tanf(p_x); }
- static _ALWAYS_INLINE_ double cosh(double p_x) {
-
- return ::cosh(p_x);
- }
-
- static _ALWAYS_INLINE_ double tanh(double p_x) {
-
- return ::tanh(p_x);
- }
+ static _ALWAYS_INLINE_ double sinh(double p_x) { return ::sinh(p_x); }
+ static _ALWAYS_INLINE_ float sinh(float p_x) { return ::sinhf(p_x); }
+ static _ALWAYS_INLINE_ double cosh(double p_x) { return ::cosh(p_x); }
+ static _ALWAYS_INLINE_ float cosh(float p_x) { return ::coshf(p_x); }
- static _ALWAYS_INLINE_ double asin(double p_x) {
+ static _ALWAYS_INLINE_ double tanh(double p_x) { return ::tanh(p_x); }
+ static _ALWAYS_INLINE_ float tanh(float p_x) { return ::tanhf(p_x); }
- return ::asin(p_x);
+ static _ALWAYS_INLINE_ double asin(double p_x) { return ::asin(p_x); }
+ static _ALWAYS_INLINE_ float asin(float p_x) { return ::asinf(p_x); }
- }
+ static _ALWAYS_INLINE_ double acos(double p_x) { return ::acos(p_x); }
+ static _ALWAYS_INLINE_ float acos(float p_x) { return ::acosf(p_x); }
- static _ALWAYS_INLINE_ double acos(double p_x) {
-
- return ::acos(p_x);
- }
-
- static _ALWAYS_INLINE_ double atan(double p_x) {
-
- return ::atan(p_x);
- }
+ static _ALWAYS_INLINE_ double atan(double p_x) { return ::atan(p_x); }
+ static _ALWAYS_INLINE_ float atan(float p_x) { return ::atanf(p_x); }
- static _ALWAYS_INLINE_ double atan2(double p_y, double p_x) {
+ static _ALWAYS_INLINE_ double atan2(double p_y, double p_x) { return ::atan2(p_y,p_x); }
+ static _ALWAYS_INLINE_ float atan2(float p_y, float p_x) { return ::atan2f(p_y,p_x); }
- return ::atan2(p_y,p_x);
+ static _ALWAYS_INLINE_ double sqrt(double p_x) { return ::sqrt(p_x); }
+ static _ALWAYS_INLINE_ float sqrt(float p_x) { return ::sqrtf(p_x); }
- }
+ static _ALWAYS_INLINE_ double fmod(double p_x,double p_y) { return ::fmod(p_x,p_y); }
+ static _ALWAYS_INLINE_ float fmod(float p_x,float p_y) { return ::fmodf(p_x,p_y); }
- static _ALWAYS_INLINE_ double deg2rad(double p_y) {
+ static _ALWAYS_INLINE_ double floor(double p_x) { return ::floor(p_x); }
+ static _ALWAYS_INLINE_ float floor(float p_x) { return ::floorf(p_x); }
- return p_y*Math_PI/180.0;
- }
+ static _ALWAYS_INLINE_ double ceil(double p_x) { return ::ceil(p_x); }
+ static _ALWAYS_INLINE_ float ceil(float p_x) { return ::ceilf(p_x); }
- static _ALWAYS_INLINE_ double rad2deg(double p_y) {
+ static _ALWAYS_INLINE_ double pow(double p_x, double p_y) { return ::pow(p_x,p_y); }
+ static _ALWAYS_INLINE_ float pow(float p_x, float p_y) { return ::powf(p_x,p_y); }
- return p_y*180.0/Math_PI;
- }
+ static _ALWAYS_INLINE_ double log(double p_x) { return ::log(p_x); }
+ static _ALWAYS_INLINE_ float log(float p_x) { return ::logf(p_x); }
+ static _ALWAYS_INLINE_ double exp(double p_x) { return ::exp(p_x); }
+ static _ALWAYS_INLINE_ float exp(float p_x) { return ::expf(p_x); }
- static _ALWAYS_INLINE_ double sqrt(double p_x) {
+ static _ALWAYS_INLINE_ bool is_nan(double p_val) { return (p_val!=p_val); }
+ static _ALWAYS_INLINE_ bool is_nan(float p_val) { return (p_val!=p_val); }
- return ::sqrt(p_x);
+ static _ALWAYS_INLINE_ bool is_inf(double p_val) {
+ #ifdef _MSC_VER
+ return !_finite(p_val);
+ #else
+ return isinf(p_val);
+ #endif
}
-
- static _ALWAYS_INLINE_ double fmod(double p_x,double p_y) {
-
- return ::fmod(p_x,p_y);
+
+ static _ALWAYS_INLINE_ bool is_inf(float p_val) {
+ #ifdef _MSC_VER
+ return !_finite(p_val);
+ #else
+ return isinf(p_val);
+ #endif
}
+
+ static _ALWAYS_INLINE_ double abs(double g) { return absd(g); }
+ static _ALWAYS_INLINE_ float abs(float g) { return absf(g); }
+ static _ALWAYS_INLINE_ int abs(int g) { return g > 0 ? g : -g; }
- static _ALWAYS_INLINE_ double fposmod(double p_x,double p_y) {
-
- if (p_x>=0) {
-
- return fmod(p_x,p_y);
-
- } else {
-
- return p_y-fmod(-p_x,p_y);
- }
+ static _ALWAYS_INLINE_ double fposmod(double p_x,double p_y) { return (p_x>=0) ? Math::fmod(p_x,p_y) : p_y-Math::fmod(-p_x,p_y); }
+ static _ALWAYS_INLINE_ float fposmod(float p_x,float p_y) { return (p_x>=0) ? Math::fmod(p_x,p_y) : p_y-Math::fmod(-p_x,p_y); }
- }
- static _ALWAYS_INLINE_ double floor(double p_x) {
+ static _ALWAYS_INLINE_ double deg2rad(double p_y) { return p_y*Math_PI/180.0; }
+ static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y*Math_PI/180.0; }
- return ::floor(p_x);
- }
+ static _ALWAYS_INLINE_ double rad2deg(double p_y) { return p_y*180.0/Math_PI; }
+ static _ALWAYS_INLINE_ float rad2deg(float p_y) { return p_y*180.0/Math_PI; }
- static _ALWAYS_INLINE_ double ceil(double p_x) {
+ static _ALWAYS_INLINE_ double lerp(double a, double b, double c) { return a+(b-a)*c; }
+ static _ALWAYS_INLINE_ float lerp(float a, float b, float c) { return a+(b-a)*c; }
- return ::ceil(p_x);
- }
+ static _ALWAYS_INLINE_ double linear2db(double p_linear) { return Math::log( p_linear ) * 8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log( p_linear ) * 8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ double db2linear(double p_db) { return Math::exp( p_db * 0.11512925464970228420089957273422 ); }
+ static _ALWAYS_INLINE_ float db2linear(float p_db) { return Math::exp( p_db * 0.11512925464970228420089957273422 ); }
- static uint32_t rand_from_seed(uint64_t *seed);
+ static _ALWAYS_INLINE_ double round(double p_val) { return (p_val>=0) ? Math::floor(p_val+0.5) : -Math::floor(-p_val+0.5); }
+ static _ALWAYS_INLINE_ float round(float p_val) { return (p_val>=0) ? Math::floor(p_val+0.5) : -Math::floor(-p_val+0.5); }
+ // double only, as these functions are mainly used by the editor and not performance-critical,
static double ease(double p_x, double p_c);
static int step_decimals(double p_step);
static double stepify(double p_value,double p_step);
- static void seed(uint64_t x=0);
- static void randomize();
- static uint32_t larger_prime(uint32_t p_val);
static double dectime(double p_value,double p_amount, double p_step);
+ static uint32_t larger_prime(uint32_t p_val);
- static inline double linear2db(double p_linear) {
-
- return Math::log( p_linear ) * 8.6858896380650365530225783783321;
- }
-
- static inline double db2linear(double p_db) {
-
- return Math::exp( p_db * 0.11512925464970228420089957273422 );
- }
-
- static _ALWAYS_INLINE_ bool is_nan(double p_val) {
-
- return (p_val!=p_val);
- }
-
- static _ALWAYS_INLINE_ bool is_inf(double p_val) {
-
- #ifdef _MSC_VER
- return !_finite(p_val);
- #else
- return isinf(p_val);
- #endif
-
- }
-
+ static void seed(uint64_t x=0);
+ static void randomize();
+ static uint32_t rand_from_seed(uint64_t *seed);
static uint32_t rand();
- static double randf();
-
- static double round(double p_val);
+ static _ALWAYS_INLINE_ double randf() { return (double)rand() / (double)Math::RANDOM_MAX; }
+ static _ALWAYS_INLINE_ float randd() { return (float)rand() / (float)Math::RANDOM_MAX; }
static double random(double from, double to);
+ static float random(float from, float to);
+ static real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); }
+
- static _FORCE_INLINE_ bool isequal_approx(real_t a, real_t b) {
+ static _ALWAYS_INLINE_ bool isequal_approx(real_t a, real_t b) {
// TODO: Comparing floats for approximate-equality is non-trivial.
// Using epsilon should cover the typical cases in Godot (where a == b is used to compare two reals), such as matrix and vector comparison operators.
// A proper implementation in terms of ULPs should eventually replace the contents of this function.
@@ -203,18 +177,7 @@ public:
}
- static _FORCE_INLINE_ real_t abs(real_t g) {
-
-#ifdef REAL_T_IS_DOUBLE
-
- return absd(g);
-#else
-
- return absf(g);
-#endif
- }
-
- static _FORCE_INLINE_ float absf(float g) {
+ static _ALWAYS_INLINE_ float absf(float g) {
union {
float f;
@@ -226,7 +189,7 @@ public:
return u.f;
}
- static _FORCE_INLINE_ double absd(double g) {
+ static _ALWAYS_INLINE_ double absd(double g) {
union {
double d;
@@ -238,12 +201,12 @@ public:
}
//this function should be as fast as possible and rounding mode should not matter
- static _FORCE_INLINE_ int fast_ftoi(float a) {
+ static _ALWAYS_INLINE_ int fast_ftoi(float a) {
static int b;
#if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0603) || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // windows 8 phone?
- b = (int)((a>0.0f) ? (a + 0.5f):(a -0.5f));
+ b = (int)((a>0.0) ? (a + 0.5):(a -0.5));
#elif defined(_MSC_VER) && _MSC_VER < 1800
__asm fld a
@@ -266,23 +229,16 @@ public:
#if defined(__GNUC__)
- static _FORCE_INLINE_ int64_t dtoll(double p_double) { return (int64_t)p_double; } ///@TODO OPTIMIZE
+ static _ALWAYS_INLINE_ int64_t dtoll(double p_double) { return (int64_t)p_double; } ///@TODO OPTIMIZE
+ static _ALWAYS_INLINE_ int64_t dtoll(float p_float) { return (int64_t)p_float; } ///@TODO OPTIMIZE and rename
#else
- static _FORCE_INLINE_ int64_t dtoll(double p_double) { return (int64_t)p_double; } ///@TODO OPTIMIZE
+ static _ALWAYS_INLINE_ int64_t dtoll(double p_double) { return (int64_t)p_double; } ///@TODO OPTIMIZE
+ static _ALWAYS_INLINE_ int64_t dtoll(float p_float) { return (int64_t)p_float; } ///@TODO OPTIMIZE and rename
#endif
- static _FORCE_INLINE_ float lerp(float a, float b, float c) {
-
- return a+(b-a)*c;
- }
-
- static double pow(double x, double y);
- static double log(double x);
- static double exp(double x);
-
- static _FORCE_INLINE_ uint32_t halfbits_to_floatbits(uint16_t h)
+ static _ALWAYS_INLINE_ uint32_t halfbits_to_floatbits(uint16_t h)
{
uint16_t h_exp, h_sig;
uint32_t f_sgn, f_exp, f_sig;
@@ -314,7 +270,7 @@ public:
}
}
- static _FORCE_INLINE_ float halfptr_to_float(const uint16_t *h) {
+ static _ALWAYS_INLINE_ float halfptr_to_float(const uint16_t *h) {
union {
uint32_t u32;
@@ -325,7 +281,7 @@ public:
return u.f32;
}
- static _FORCE_INLINE_ uint16_t make_half_float(float f) {
+ static _ALWAYS_INLINE_ uint16_t make_half_float(float f) {
union {
float fv;
diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp
index e9c3442582..1fabfbbd4c 100644
--- a/core/math/matrix3.cpp
+++ b/core/math/matrix3.cpp
@@ -504,9 +504,9 @@ void Basis::get_axis_and_angle(Vector3 &r_axis,real_t& r_angle) const {
ERR_FAIL_COND(is_rotation() == false);
- double angle,x,y,z; // variables for result
- double epsilon = 0.01; // margin to allow for rounding errors
- double epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees
+ real_t angle,x,y,z; // variables for result
+ real_t epsilon = 0.01; // margin to allow for rounding errors
+ real_t epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees
if ( (Math::abs(elements[1][0]-elements[0][1])< epsilon)
&& (Math::abs(elements[2][0]-elements[0][2])< epsilon)
@@ -525,12 +525,12 @@ void Basis::get_axis_and_angle(Vector3 &r_axis,real_t& r_angle) const {
}
// otherwise this singularity is angle = 180
angle = Math_PI;
- double xx = (elements[0][0]+1)/2;
- double yy = (elements[1][1]+1)/2;
- double zz = (elements[2][2]+1)/2;
- double xy = (elements[1][0]+elements[0][1])/4;
- double xz = (elements[2][0]+elements[0][2])/4;
- double yz = (elements[2][1]+elements[1][2])/4;
+ real_t xx = (elements[0][0]+1)/2;
+ real_t yy = (elements[1][1]+1)/2;
+ real_t zz = (elements[2][2]+1)/2;
+ real_t xy = (elements[1][0]+elements[0][1])/4;
+ real_t xz = (elements[2][0]+elements[0][2])/4;
+ real_t yz = (elements[2][1]+elements[1][2])/4;
if ((xx > yy) && (xx > zz)) { // elements[0][0] is the largest diagonal term
if (xx< epsilon) {
x = 0;
@@ -567,7 +567,7 @@ void Basis::get_axis_and_angle(Vector3 &r_axis,real_t& r_angle) const {
return;
}
// as we have reached here there are no singularities so we can handle normally
- double s = Math::sqrt((elements[1][2] - elements[2][1])*(elements[1][2] - elements[2][1])
+ real_t s = Math::sqrt((elements[1][2] - elements[2][1])*(elements[1][2] - elements[2][1])
+(elements[2][0] - elements[0][2])*(elements[2][0] - elements[0][2])
+(elements[0][1] - elements[1][0])*(elements[0][1] - elements[1][0])); // s=|axis||sin(angle)|, used to normalise
diff --git a/core/math/octree.h b/core/math/octree.h
index 3630922d10..e566df6a4f 100644
--- a/core/math/octree.h
+++ b/core/math/octree.h
@@ -435,7 +435,7 @@ int Octree<T,use_pairs,AL>::get_subindex(OctreeElementID p_id) const {
template<class T,bool use_pairs,class AL>
void Octree<T,use_pairs,AL>::_insert_element(Element *p_element,Octant *p_octant) {
- float element_size = p_element->aabb.get_longest_axis_size() * 1.01; // avoid precision issues
+ real_t element_size = p_element->aabb.get_longest_axis_size() * 1.01; // avoid precision issues
if (p_octant->aabb.size.x/OCTREE_DIVISOR < element_size) {
//if (p_octant->aabb.size.x*0.5 < element_size) {
diff --git a/core/math/plane.h b/core/math/plane.h
index f746ea2067..8235c59135 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -99,7 +99,7 @@ real_t Plane::distance_to(const Vector3 &p_point) const {
bool Plane::has_point(const Vector3 &p_point,real_t _epsilon) const {
- float dist=normal.dot(p_point) - d;
+ real_t dist=normal.dot(p_point) - d;
dist=ABS(dist);
return ( dist <= _epsilon);
diff --git a/core/math/quat.cpp b/core/math/quat.cpp
index 055e2b7c35..4085f9b84a 100644
--- a/core/math/quat.cpp
+++ b/core/math/quat.cpp
@@ -124,8 +124,8 @@ Quat Quat::slerp(const Quat& q, const real_t& t) const {
// Standard case (slerp)
real_t sine = Math::sqrt(1 - cosine*cosine);
real_t angle = Math::atan2(sine, cosine);
- real_t inv_sine = 1.0f / sine;
- real_t coeff_0 = Math::sin((1.0f - t) * angle) * inv_sine;
+ real_t inv_sine = 1.0 / sine;
+ real_t coeff_0 = Math::sin((1.0 - t) * angle) * inv_sine;
real_t coeff_1 = Math::sin(t * angle) * inv_sine;
Quat ret= src * coeff_0 + dst * coeff_1;
@@ -137,7 +137,7 @@ Quat Quat::slerp(const Quat& q, const real_t& t) const {
// 2. "rkP" and "q" are almost invedste of each other (cosine ~= -1), there
// are an infinite number of possibilities interpolation. but we haven't
// have method to fix this case, so just use linear interpolation here.
- Quat ret = src * (1.0f - t) + dst *t;
+ Quat ret = src * (1.0 - t) + dst *t;
// taking the complement requires renormalisation
ret.normalize();
return ret;
@@ -194,14 +194,14 @@ Quat Quat::slerpni(const Quat& q, const real_t& t) const {
const Quat &from = *this;
- float dot = from.dot(q);
+ real_t dot = from.dot(q);
- if (Math::absf(dot) > 0.9999f) return from;
+ if (Math::absf(dot) > 0.9999) return from;
- float theta = Math::acos(dot),
- sinT = 1.0f / Math::sin(theta),
+ real_t theta = Math::acos(dot),
+ sinT = 1.0 / Math::sin(theta),
newFactor = Math::sin(t * theta) * sinT,
- invFactor = Math::sin((1.0f - t) * theta) * sinT;
+ invFactor = Math::sin((1.0 - t) * theta) * sinT;
return Quat(invFactor * from.x + newFactor * q.x,
invFactor * from.y + newFactor * q.y,
@@ -259,7 +259,7 @@ Quat Quat::slerpni(const Quat& q, const real_t& t) const {
Quat Quat::cubic_slerp(const Quat& q, const Quat& prep, const Quat& postq,const real_t& t) const {
//the only way to do slerp :|
- float t2 = (1.0-t)*t*2;
+ real_t t2 = (1.0-t)*t*2;
Quat sp = this->slerp(q,t);
Quat sq = prep.slerpni(postq,t);
return sp.slerpni(sq,t2);
diff --git a/core/math/quat.h b/core/math/quat.h
index 43c2cab9e6..d3a50343a3 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -119,8 +119,8 @@ public:
w=0;
} else {
- real_t s = Math::sqrt((1.0f + d) * 2.0f);
- real_t rs = 1.0f / s;
+ real_t s = Math::sqrt((1.0 + d) * 2.0);
+ real_t rs = 1.0 / s;
x=c.x*rs;
y=c.y*rs;
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index 756e48d0b4..32fc0e01e8 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -86,7 +86,7 @@ Error QuickHull::build(const Vector<Vector3>& p_points, Geometry::MeshData &r_me
if (!valid_points[i])
continue;
- float d = p_points[i][longest_axis];
+ real_t d = p_points[i][longest_axis];
if (i==0 || d < min) {
simplex[0]=i;
@@ -105,7 +105,7 @@ Error QuickHull::build(const Vector<Vector3>& p_points, Geometry::MeshData &r_me
{
- float maxd;
+ real_t maxd;
Vector3 rel12 = p_points[simplex[0]] - p_points[simplex[1]];
for(int i=0;i<p_points.size();i++) {
@@ -127,7 +127,7 @@ Error QuickHull::build(const Vector<Vector3>& p_points, Geometry::MeshData &r_me
//fourth vertex is the one most further away from the plane
{
- float maxd;
+ real_t maxd;
Plane p(p_points[simplex[0]],p_points[simplex[1]],p_points[simplex[2]]);
for(int i=0;i<p_points.size();i++) {
diff --git a/core/math/rect3.cpp b/core/math/rect3.cpp
index e0b0646505..d3f95b89e8 100644
--- a/core/math/rect3.cpp
+++ b/core/math/rect3.cpp
@@ -30,7 +30,7 @@
#include "print_string.h"
-float Rect3::get_area() const {
+real_t Rect3::get_area() const {
return size.x*size.y*size.z;
@@ -114,8 +114,8 @@ bool Rect3::intersects_ray(const Vector3& p_from, const Vector3& p_dir,Vector3*
Vector3 c1, c2;
Vector3 end = pos+size;
- float near=-1e20;
- float far=1e20;
+ real_t near=-1e20;
+ real_t far=1e20;
int axis=0;
for (int i=0;i<3;i++){
@@ -159,7 +159,7 @@ bool Rect3::intersects_segment(const Vector3& p_from, const Vector3& p_to,Vector
real_t min=0,max=1;
int axis=0;
- float sign=0;
+ real_t sign=0;
for(int i=0;i<3;i++) {
real_t seg_from=p_from[i];
@@ -167,7 +167,7 @@ bool Rect3::intersects_segment(const Vector3& p_from, const Vector3& p_to,Vector
real_t box_begin=pos[i];
real_t box_end=box_begin+size[i];
real_t cmin,cmax;
- float csign;
+ real_t csign;
if (seg_from < seg_to) {
diff --git a/core/math/rect3.h b/core/math/rect3.h
index 80c67200f4..902592b02c 100644
--- a/core/math/rect3.h
+++ b/core/math/rect3.h
@@ -33,6 +33,8 @@
#include "vector3.h"
#include "plane.h"
+#include "math_defs.h"
+
/**
* AABB / AABB (Axis Aligned Bounding Box)
* This is implemented by a point (pos) and the box size
@@ -45,7 +47,7 @@ public:
Vector3 pos;
Vector3 size;
- float get_area() const; /// get area
+ real_t get_area() const; /// get area
_FORCE_INLINE_ bool has_no_area() const {
return (size.x<=CMP_EPSILON || size.y<=CMP_EPSILON || size.z<=CMP_EPSILON);
@@ -74,7 +76,7 @@ public:
Rect3 intersection(const Rect3& p_aabb) const; ///get box where two intersect, empty if no intersection occurs
bool intersects_segment(const Vector3& p_from, const Vector3& p_to,Vector3* r_clip=NULL,Vector3* r_normal=NULL) const;
bool intersects_ray(const Vector3& p_from, const Vector3& p_dir,Vector3* r_clip=NULL,Vector3* r_normal=NULL) const;
- _FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &from,const Vector3& p_dir, float t0, float t1) const;
+ _FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &from,const Vector3& p_dir, real_t t0, real_t t1) const;
_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_plane, int p_plane_count) const;
bool intersects_plane(const Plane &p_plane) const;
@@ -98,7 +100,7 @@ public:
_FORCE_INLINE_ Vector3 get_endpoint(int p_point) const;
Rect3 expand(const Vector3& p_vector) const;
- _FORCE_INLINE_ void project_range_in_plane(const Plane& p_plane,float &r_min,float& r_max) const;
+ _FORCE_INLINE_ void project_range_in_plane(const Plane& p_plane,real_t &r_min,real_t& r_max) const;
_FORCE_INLINE_ void expand_to(const Vector3& p_vector); /** expand to contain a point if necesary */
operator String() const;
@@ -293,13 +295,13 @@ inline void Rect3::expand_to(const Vector3& p_vector) {
size=end-begin;
}
-void Rect3::project_range_in_plane(const Plane& p_plane,float &r_min,float& r_max) const {
+void Rect3::project_range_in_plane(const Plane& p_plane,real_t &r_min,real_t& r_max) const {
Vector3 half_extents( size.x * 0.5, size.y * 0.5, size.z * 0.5 );
Vector3 center( pos.x + half_extents.x, pos.y + half_extents.y, pos.z + half_extents.z );
- float length = p_plane.normal.abs().dot(half_extents);
- float distance = p_plane.distance_to( center );
+ real_t length = p_plane.normal.abs().dot(half_extents);
+ real_t distance = p_plane.distance_to( center );
r_min = distance - length;
r_max = distance + length;
}
@@ -334,14 +336,14 @@ inline real_t Rect3::get_shortest_axis_size() const {
return max_size;
}
-bool Rect3::smits_intersect_ray(const Vector3 &from,const Vector3& dir, float t0, float t1) const {
+bool Rect3::smits_intersect_ray(const Vector3 &from,const Vector3& dir, real_t t0, real_t t1) const {
- float divx=1.0/dir.x;
- float divy=1.0/dir.y;
- float divz=1.0/dir.z;
+ real_t divx=1.0/dir.x;
+ real_t divy=1.0/dir.y;
+ real_t divz=1.0/dir.z;
Vector3 upbound=pos+size;
- float tmin, tmax, tymin, tymax, tzmin, tzmax;
+ real_t tmin, tmax, tymin, tymax, tzmin, tzmax;
if (dir.x >= 0) {
tmin = (pos.x - from.x) * divx;
tmax = (upbound.x - from.x) * divx;
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index 86f8bf29e7..247cb90a48 100644
--- a/core/math/triangle_mesh.cpp
+++ b/core/math/triangle_mesh.cpp
@@ -340,7 +340,7 @@ bool TriangleMesh::intersect_segment(const Vector3& p_begin,const Vector3& p_end
if (f3.intersects_segment(p_begin,p_end,&res)) {
- float nd = n.dot(res);
+ real_t nd = n.dot(res);
if (nd<d) {
d=nd;
@@ -462,7 +462,7 @@ bool TriangleMesh::intersect_ray(const Vector3& p_begin,const Vector3& p_dir,Vec
if (f3.intersects_ray(p_begin,p_dir,&res)) {
- float nd = n.dot(res);
+ real_t nd = n.dot(res);
if (nd<d) {
d=nd;
diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp
index 82b49be7f3..128b6ca331 100644
--- a/core/math/triangulate.cpp
+++ b/core/math/triangulate.cpp
@@ -28,19 +28,19 @@
/*************************************************************************/
#include "triangulate.h"
-float Triangulate::get_area(const Vector<Vector2> &contour)
+real_t Triangulate::get_area(const Vector<Vector2> &contour)
{
int n = contour.size();
const Vector2 *c=&contour[0];
- float A=0.0f;
+ real_t A=0.0;
for(int p=n-1,q=0; q<n; p=q++)
{
A+= c[p].cross(c[q]);
}
- return A*0.5f;
+ return A*0.5;
}
/*
@@ -48,14 +48,14 @@ float Triangulate::get_area(const Vector<Vector2> &contour)
defined by A, B, C.
*/
-bool Triangulate::is_inside_triangle(float Ax, float Ay,
- float Bx, float By,
- float Cx, float Cy,
- float Px, float Py)
+bool Triangulate::is_inside_triangle(real_t Ax, real_t Ay,
+ real_t Bx, real_t By,
+ real_t Cx, real_t Cy,
+ real_t Px, real_t Py)
{
- float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
- float cCROSSap, bCROSScp, aCROSSbp;
+ real_t ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
+ real_t cCROSSap, bCROSScp, aCROSSbp;
ax = Cx - Bx; ay = Cy - By;
bx = Ax - Cx; by = Ay - Cy;
@@ -68,13 +68,13 @@ bool Triangulate::is_inside_triangle(float Ax, float Ay,
cCROSSap = cx*apy - cy*apx;
bCROSScp = bx*cpy - by*cpx;
- return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
+ return ((aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0));
};
bool Triangulate::snip(const Vector<Vector2> &p_contour,int u,int v,int w,int n,const Vector<int>& V)
{
int p;
- float Ax, Ay, Bx, By, Cx, Cy, Px, Py;
+ real_t Ax, Ay, Bx, By, Cx, Cy, Px, Py;
const Vector2 *contour=&p_contour[0];
Ax = contour[V[u]].x;
@@ -112,7 +112,7 @@ bool Triangulate::triangulate(const Vector<Vector2> &contour,Vector<int> &result
/* we want a counter-clockwise polygon in V */
- if ( 0.0f < get_area(contour) )
+ if ( 0.0 < get_area(contour) )
for (int v=0; v<n; v++) V[v] = v;
else
for(int v=0; v<n; v++) V[v] = (n-1)-v;
diff --git a/core/math/triangulate.h b/core/math/triangulate.h
index d22677a8b8..ce77334519 100644
--- a/core/math/triangulate.h
+++ b/core/math/triangulate.h
@@ -45,14 +45,14 @@ public:
static bool triangulate(const Vector< Vector2 > &contour, Vector<int> &result);
// compute area of a contour/polygon
- static float get_area(const Vector< Vector2 > &contour);
+ static real_t get_area(const Vector< Vector2 > &contour);
// decide if point Px/Py is inside triangle defined by
// (Ax,Ay) (Bx,By) (Cx,Cy)
- static bool is_inside_triangle(float Ax, float Ay,
- float Bx, float By,
- float Cx, float Cy,
- float Px, float Py);
+ static bool is_inside_triangle(real_t Ax, real_t Ay,
+ real_t Bx, real_t By,
+ real_t Cx, real_t Cy,
+ real_t Px, real_t Py);
private:
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index 3eb978333d..2ab5fa0465 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -30,12 +30,12 @@
#include "matrix3.h"
-void Vector3::rotate(const Vector3& p_axis,float p_phi) {
+void Vector3::rotate(const Vector3& p_axis,real_t p_phi) {
*this=Basis(p_axis,p_phi).xform(*this);
}
-Vector3 Vector3::rotated(const Vector3& p_axis,float p_phi) const {
+Vector3 Vector3::rotated(const Vector3& p_axis,real_t p_phi) const {
Vector3 r = *this;
r.rotate(p_axis,p_phi);
@@ -63,13 +63,13 @@ int Vector3::max_axis() const {
}
-void Vector3::snap(float p_val) {
+void Vector3::snap(real_t p_val) {
x=Math::stepify(x,p_val);
y=Math::stepify(y,p_val);
z=Math::stepify(z,p_val);
}
-Vector3 Vector3::snapped(float p_val) const {
+Vector3 Vector3::snapped(real_t p_val) const {
Vector3 v=*this;
v.snap(p_val);
@@ -77,7 +77,7 @@ Vector3 Vector3::snapped(float p_val) const {
}
-Vector3 Vector3::cubic_interpolaten(const Vector3& p_b,const Vector3& p_pre_a, const Vector3& p_post_b,float p_t) const {
+Vector3 Vector3::cubic_interpolaten(const Vector3& p_b,const Vector3& p_pre_a, const Vector3& p_post_b,real_t p_t) const {
Vector3 p0=p_pre_a;
Vector3 p1=*this;
@@ -87,9 +87,9 @@ Vector3 Vector3::cubic_interpolaten(const Vector3& p_b,const Vector3& p_pre_a, c
{
//normalize
- float ab = p0.distance_to(p1);
- float bc = p1.distance_to(p2);
- float cd = p2.distance_to(p3);
+ real_t ab = p0.distance_to(p1);
+ real_t bc = p1.distance_to(p2);
+ real_t cd = p2.distance_to(p3);
if (ab>0)
p0 = p1+(p0-p1)*(bc/ab);
@@ -98,41 +98,41 @@ Vector3 Vector3::cubic_interpolaten(const Vector3& p_b,const Vector3& p_pre_a, c
}
- float t = p_t;
- float t2 = t * t;
- float t3 = t2 * t;
+ real_t t = p_t;
+ real_t t2 = t * t;
+ real_t t3 = t2 * t;
Vector3 out;
- out = 0.5f * ( ( p1 * 2.0f) +
+ out = 0.5 * ( ( p1 * 2.0) +
( -p0 + p2 ) * t +
- ( 2.0f * p0 - 5.0f * p1 + 4 * p2 - p3 ) * t2 +
- ( -p0 + 3.0f * p1 - 3.0f * p2 + p3 ) * t3 );
+ ( 2.0 * p0 - 5.0 * p1 + 4 * p2 - p3 ) * t2 +
+ ( -p0 + 3.0 * p1 - 3.0 * p2 + p3 ) * t3 );
return out;
}
-Vector3 Vector3::cubic_interpolate(const Vector3& p_b,const Vector3& p_pre_a, const Vector3& p_post_b,float p_t) const {
+Vector3 Vector3::cubic_interpolate(const Vector3& p_b,const Vector3& p_pre_a, const Vector3& p_post_b,real_t p_t) const {
Vector3 p0=p_pre_a;
Vector3 p1=*this;
Vector3 p2=p_b;
Vector3 p3=p_post_b;
- float t = p_t;
- float t2 = t * t;
- float t3 = t2 * t;
+ real_t t = p_t;
+ real_t t2 = t * t;
+ real_t t3 = t2 * t;
Vector3 out;
- out = 0.5f * ( ( p1 * 2.0f) +
+ out = 0.5 * ( ( p1 * 2.0) +
( -p0 + p2 ) * t +
- ( 2.0f * p0 - 5.0f * p1 + 4 * p2 - p3 ) * t2 +
- ( -p0 + 3.0f * p1 - 3.0f * p2 + p3 ) * t3 );
+ ( 2.0 * p0 - 5.0 * p1 + 4 * p2 - p3 ) * t2 +
+ ( -p0 + 3.0 * p1 - 3.0 * p2 + p3 ) * t3 );
return out;
}
#if 0
-Vector3 Vector3::cubic_interpolate(const Vector3& p_b,const Vector3& p_pre_a, const Vector3& p_post_b,float p_t) const {
+Vector3 Vector3::cubic_interpolate(const Vector3& p_b,const Vector3& p_pre_a, const Vector3& p_post_b,real_t p_t) const {
Vector3 p0=p_pre_a;
Vector3 p1=*this;
@@ -141,9 +141,9 @@ Vector3 Vector3::cubic_interpolate(const Vector3& p_b,const Vector3& p_pre_a, co
if (true) {
- float ab = p0.distance_to(p1);
- float bc = p1.distance_to(p2);
- float cd = p2.distance_to(p3);
+ real_t ab = p0.distance_to(p1);
+ real_t bc = p1.distance_to(p2);
+ real_t cd = p2.distance_to(p3);
//if (ab>bc) {
if (ab>0)
@@ -156,23 +156,23 @@ Vector3 Vector3::cubic_interpolate(const Vector3& p_b,const Vector3& p_pre_a, co
//}
}
- float t = p_t;
- float t2 = t * t;
- float t3 = t2 * t;
+ real_t t = p_t;
+ real_t t2 = t * t;
+ real_t t3 = t2 * t;
Vector3 out;
- out.x = 0.5f * ( ( 2.0f * p1.x ) +
+ out.x = 0.5 * ( ( 2.0 * p1.x ) +
( -p0.x + p2.x ) * t +
- ( 2.0f * p0.x - 5.0f * p1.x + 4 * p2.x - p3.x ) * t2 +
- ( -p0.x + 3.0f * p1.x - 3.0f * p2.x + p3.x ) * t3 );
- out.y = 0.5f * ( ( 2.0f * p1.y ) +
+ ( 2.0 * p0.x - 5.0 * p1.x + 4 * p2.x - p3.x ) * t2 +
+ ( -p0.x + 3.0 * p1.x - 3.0 * p2.x + p3.x ) * t3 );
+ out.y = 0.5 * ( ( 2.0 * p1.y ) +
( -p0.y + p2.y ) * t +
- ( 2.0f * p0.y - 5.0f * p1.y + 4 * p2.y - p3.y ) * t2 +
- ( -p0.y + 3.0f * p1.y - 3.0f * p2.y + p3.y ) * t3 );
- out.z = 0.5f * ( ( 2.0f * p1.z ) +
+ ( 2.0 * p0.y - 5.0 * p1.y + 4 * p2.y - p3.y ) * t2 +
+ ( -p0.y + 3.0 * p1.y - 3.0 * p2.y + p3.y ) * t3 );
+ out.z = 0.5 * ( ( 2.0 * p1.z ) +
( -p0.z + p2.z ) * t +
- ( 2.0f * p0.z - 5.0f * p1.z + 4 * p2.z - p3.z ) * t2 +
- ( -p0.z + 3.0f * p1.z - 3.0f * p2.z + p3.z ) * t3 );
+ ( 2.0 * p0.z - 5.0 * p1.z + 4 * p2.z - p3.z ) * t2 +
+ ( -p0.z + 3.0 * p1.z - 3.0 * p2.z + p3.z ) * t3 );
return out;
}
# endif
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 9ae9b69dfa..a289f9bf4c 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -79,17 +79,17 @@ struct Vector3 {
_FORCE_INLINE_ void zero();
- void snap(float p_val);
- Vector3 snapped(float p_val) const;
+ void snap(real_t p_val);
+ Vector3 snapped(real_t p_val) const;
- void rotate(const Vector3& p_axis,float p_phi);
- Vector3 rotated(const Vector3& p_axis,float p_phi) const;
+ void rotate(const Vector3& p_axis,real_t p_phi);
+ Vector3 rotated(const Vector3& p_axis,real_t p_phi) const;
/* Static Methods between 2 vector3s */
- _FORCE_INLINE_ Vector3 linear_interpolate(const Vector3& p_b,float p_t) const;
- Vector3 cubic_interpolate(const Vector3& p_b,const Vector3& p_pre_a, const Vector3& p_post_b,float p_t) const;
- Vector3 cubic_interpolaten(const Vector3& p_b,const Vector3& p_pre_a, const Vector3& p_post_b,float p_t) const;
+ _FORCE_INLINE_ Vector3 linear_interpolate(const Vector3& p_b,real_t p_t) const;
+ Vector3 cubic_interpolate(const Vector3& p_b,const Vector3& p_pre_a, const Vector3& p_post_b,real_t p_t) const;
+ Vector3 cubic_interpolaten(const Vector3& p_b,const Vector3& p_pre_a, const Vector3& p_post_b,real_t p_t) const;
_FORCE_INLINE_ Vector3 cross(const Vector3& p_b) const;
_FORCE_INLINE_ real_t dot(const Vector3& p_b) const;
@@ -195,7 +195,7 @@ Vector3 Vector3::ceil() const {
return Vector3( Math::ceil(x), Math::ceil(y), Math::ceil(z) );
}
-Vector3 Vector3::linear_interpolate(const Vector3& p_b,float p_t) const {
+Vector3 Vector3::linear_interpolate(const Vector3& p_b,real_t p_t) const {
return Vector3(
x+(p_t * (p_b.x-x)),
diff --git a/core/object.h b/core/object.h
index b9a800afc4..3032452ccf 100644
--- a/core/object.h
+++ b/core/object.h
@@ -103,6 +103,7 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_SCRIPT_VARIABLE=8192,
PROPERTY_USAGE_STORE_IF_NULL=16384,
PROPERTY_USAGE_ANIMATE_AS_TRIGGER=32768,
+ PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED=65536,
PROPERTY_USAGE_DEFAULT=PROPERTY_USAGE_STORAGE|PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_NETWORK,
PROPERTY_USAGE_DEFAULT_INTL=PROPERTY_USAGE_STORAGE|PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_INTERNATIONALIZED,
diff --git a/core/os/input.cpp b/core/os/input.cpp
index e53aa82b13..4e7b037453 100644
--- a/core/os/input.cpp
+++ b/core/os/input.cpp
@@ -38,7 +38,7 @@ Input *Input::get_singleton() {
}
void Input::set_mouse_mode(MouseMode p_mode) {
- ERR_FAIL_INDEX(p_mode,3);
+ ERR_FAIL_INDEX(p_mode,4);
OS::get_singleton()->set_mouse_mode((OS::MouseMode)p_mode);
}
@@ -87,6 +87,7 @@ void Input::_bind_methods() {
BIND_CONSTANT( MOUSE_MODE_VISIBLE );
BIND_CONSTANT( MOUSE_MODE_HIDDEN );
BIND_CONSTANT( MOUSE_MODE_CAPTURED );
+ BIND_CONSTANT( MOUSE_MODE_CONFINED );
ADD_SIGNAL( MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "connected")) );
}
diff --git a/core/os/input.h b/core/os/input.h
index 82c7a80d3f..2cea154a50 100644
--- a/core/os/input.h
+++ b/core/os/input.h
@@ -47,7 +47,8 @@ public:
enum MouseMode {
MOUSE_MODE_VISIBLE,
MOUSE_MODE_HIDDEN,
- MOUSE_MODE_CAPTURED
+ MOUSE_MODE_CAPTURED,
+ MOUSE_MODE_CONFINED
};
void set_mouse_mode(MouseMode p_mode);
diff --git a/core/os/os.h b/core/os/os.h
index ea03481a92..42c7c18b0c 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -131,7 +131,8 @@ public:
enum MouseMode {
MOUSE_MODE_VISIBLE,
MOUSE_MODE_HIDDEN,
- MOUSE_MODE_CAPTURED
+ MOUSE_MODE_CAPTURED,
+ MOUSE_MODE_CONFINED
};
virtual void set_mouse_mode(MouseMode p_mode);
diff --git a/core/pair.h b/core/pair.h
index d75cbed642..174ffb3883 100644
--- a/core/pair.h
+++ b/core/pair.h
@@ -39,4 +39,13 @@ struct Pair {
Pair( F p_first, S p_second) { first=p_first; second=p_second; }
};
+template<class F,class S>
+struct PairSort {
+
+ bool operator()(const Pair<F,S>& A, const Pair<F,S>& B) const {
+ return A.first < B.first;
+ }
+};
+
+
#endif // PAIR_H
diff --git a/core/path_remap.cpp b/core/path_remap.cpp
index ed77fd8840..bbaba71bba 100644
--- a/core/path_remap.cpp
+++ b/core/path_remap.cpp
@@ -28,185 +28,3 @@
/*************************************************************************/
#include "path_remap.h"
-#include "globals.h"
-#include "os/os.h"
-#include "translation.h"
-
-PathRemap* PathRemap::singleton=NULL;
-
-PathRemap* PathRemap::get_singleton() {
-
- return singleton;
-}
-
-void PathRemap::add_remap(const String& p_from, const String& p_to,const String& p_locale) {
-
- if (!remap.has(p_from)) {
- remap[p_from]=RemapData();
- }
-
- if (p_locale==String())
- remap[p_from].always=p_to;
- else
- remap[p_from].locale[p_locale]=p_to;
-}
-
-
-String PathRemap::get_remap(const String& p_from) const {
-
- const RemapData *ptr=remap.getptr(p_from);
- if (!ptr) {
- if (OS::get_singleton()->is_stdout_verbose())
- print_line("remap failed: "+p_from);
- return p_from;
- } else {
-
- const RemapData *ptr2=NULL;
-
- String locale = TranslationServer::get_singleton()->get_locale();
-
- if (ptr->locale.has(locale)) {
- if (OS::get_singleton()->is_stdout_verbose())
- print_line("remap found: "+p_from+" -> "+ptr->locale[locale]);
-
- ptr2=remap.getptr(ptr->locale[locale]);
-
- if (ptr2 && ptr2->always!=String()) //may have atlas or export remap too
- return ptr2->always;
- else
- return ptr->locale[locale];
- }
-
- int p = locale.find("_");
- if (p!=-1) {
- locale=locale.substr(0,p);
- if (ptr->locale.has(locale)) {
- if (OS::get_singleton()->is_stdout_verbose())
- print_line("remap found: "+p_from+" -> "+ptr->locale[locale]);
-
- ptr2=remap.getptr(ptr->locale[locale]);
-
- if (ptr2 && ptr2->always!=String()) //may have atlas or export remap too
- return ptr2->always;
- else
- return ptr->locale[locale];
-
- }
- }
-
- if (ptr->always!=String()) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_line("remap found: "+p_from+" -> "+ptr->always);
- }
- return ptr->always;
- }
-
- if (OS::get_singleton()->is_stdout_verbose())
- print_line("remap failed: "+p_from);
-
- return p_from;
- }
-}
-bool PathRemap::has_remap(const String& p_from) const{
-
- return remap.has(p_from);
-}
-
-void PathRemap::erase_remap(const String& p_from){
-
- ERR_FAIL_COND(!remap.has(p_from));
- remap.erase(p_from);
-}
-
-void PathRemap::clear_remaps() {
-
- remap.clear();
-}
-
-void PathRemap::load_remaps() {
-
- // default remaps first
- PoolVector<String> remaps;
- if (GlobalConfig::get_singleton()->has("remap/all")) {
- remaps = GlobalConfig::get_singleton()->get("remap/all");
- }
-
- {
- int rlen = remaps.size();
-
- ERR_FAIL_COND( rlen%2 );
- PoolVector<String>::Read r = remaps.read();
- for(int i=0;i<rlen/2;i++) {
-
- String from = r[i*2+0];
- String to = r[i*2+1];
- add_remap(from,to);
- }
- }
-
-
- // platform remaps second, so override
- if (GlobalConfig::get_singleton()->has("remap/"+OS::get_singleton()->get_name())) {
- remaps = GlobalConfig::get_singleton()->get("remap/"+OS::get_singleton()->get_name());
- } else {
- remaps.resize(0);
- }
- //remaps = Globals::get_singleton()->get("remap/PSP");
- {
- int rlen = remaps.size();
-
- ERR_FAIL_COND( rlen%2 );
- PoolVector<String>::Read r = remaps.read();
- for(int i=0;i<rlen/2;i++) {
-
- String from = r[i*2+0];
- String to = r[i*2+1];
- //print_line("add remap: "+from+" -> "+to);
- add_remap(from,to);
- }
- }
-
-
- //locale based remaps
-
- if (GlobalConfig::get_singleton()->has("locale/translation_remaps")) {
-
- Dictionary remaps = GlobalConfig::get_singleton()->get("locale/translation_remaps");
- List<Variant> rk;
- remaps.get_key_list(&rk);
- for(List<Variant>::Element *E=rk.front();E;E=E->next()) {
-
- String source = E->get();
- PoolStringArray sa = remaps[E->get()];
- int sas = sa.size();
- PoolStringArray::Read r = sa.read();
-
- for(int i=0;i<sas;i++) {
-
- String s = r[i];
- int qp = s.find_last(":");
- if (qp!=-1) {
- String path = s.substr(0,qp);
- String locale = s.substr(qp+1,s.length());
- add_remap(source,path,locale);
- }
- }
- }
-
- }
-
-}
-
-void PathRemap::_bind_methods() {
-
- ClassDB::bind_method(_MD("add_remap","from","to","locale"),&PathRemap::add_remap,DEFVAL(String()));
- ClassDB::bind_method(_MD("has_remap","path"),&PathRemap::has_remap);
- ClassDB::bind_method(_MD("get_remap","path"),&PathRemap::get_remap);
- ClassDB::bind_method(_MD("erase_remap","path"),&PathRemap::erase_remap);
- ClassDB::bind_method(_MD("clear_remaps"),&PathRemap::clear_remaps);
-}
-
-PathRemap::PathRemap() {
-
- singleton=this;
-}
diff --git a/core/path_remap.h b/core/path_remap.h
index a106030f95..966bb10ea5 100644
--- a/core/path_remap.h
+++ b/core/path_remap.h
@@ -29,39 +29,4 @@
#ifndef PATH_REMAP_H
#define PATH_REMAP_H
-#include "hash_map.h"
-#include "ustring.h"
-#include "object.h"
-
-
-class PathRemap : public Object {
-
- GDCLASS(PathRemap,Object);
-
- static PathRemap* singleton;
- struct RemapData {
- String always;
- Map<String,String> locale;
- };
-
- HashMap<String,RemapData> remap;
-protected:
-
- static void _bind_methods();
-public:
-
- void add_remap(const String& p_from, const String& p_to,const String& p_locale=String());
- bool has_remap(const String& p_from) const;
- //_FORCE_INLINE_ String get_remap(const String& p_from) const { const String *ptr=remap.getptr(p_from); if (!ptr) return p_from; else return *ptr; }
- String get_remap(const String& p_from) const;
- void erase_remap(const String& p_from);
- void clear_remaps();
-
- void load_remaps();
-
- static PathRemap* get_singleton();
-
- PathRemap();
-};
-
#endif // PATH_REMAP_H
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 242d36042d..ab94b56cdc 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -45,6 +45,7 @@
#include "compressed_translation.h"
#include "io/translation_loader_po.h"
#include "io/resource_format_binary.h"
+#include "io/resource_import.h"
#include "io/stream_peer_ssl.h"
#include "os/input.h"
#include "core/io/xml_parser.h"
@@ -57,7 +58,7 @@
static ResourceFormatSaverBinary *resource_saver_binary=NULL;
static ResourceFormatLoaderBinary *resource_loader_binary=NULL;
-
+static ResourceFormatImporter *resource_format_importer=NULL;
static _ResourceLoader *_resource_loader=NULL;
static _ResourceSaver *_resource_saver=NULL;
@@ -105,12 +106,14 @@ void register_core_types() {
resource_loader_binary = memnew( ResourceFormatLoaderBinary );
ResourceLoader::add_resource_format_loader(resource_loader_binary);
+ resource_format_importer = memnew( ResourceFormatImporter );
+ ResourceLoader::add_resource_format_loader(resource_format_importer);
+
ClassDB::register_class<Object>();
ClassDB::register_class<Reference>();
ClassDB::register_class<WeakRef>();
- ClassDB::register_class<ResourceImportMetadata>();
ClassDB::register_class<Resource>();
ClassDB::register_class<FuncRef>();
ClassDB::register_virtual_class<StreamPeer>();
@@ -179,13 +182,11 @@ void register_core_singletons() {
GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("Geometry",_Geometry::get_singleton()) );
GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("ResourceLoader",_ResourceLoader::get_singleton()) );
GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("ResourceSaver",_ResourceSaver::get_singleton()) );
- GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("PathRemap",PathRemap::get_singleton() ) );
GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("OS",_OS::get_singleton() ) );
GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("Engine",_Engine::get_singleton() ) );
GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("ClassDB",_classdb ) );
GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("Marshalls",_Marshalls::get_singleton() ) );
GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("TranslationServer",TranslationServer::get_singleton() ) );
- GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("TS",TranslationServer::get_singleton() ) );
GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("Input",Input::get_singleton() ) );
GlobalConfig::get_singleton()->add_singleton( GlobalConfig::Singleton("InputMap",InputMap::get_singleton() ) );
@@ -209,6 +210,8 @@ void unregister_core_types() {
memdelete(resource_saver_binary);
if (resource_loader_binary)
memdelete(resource_loader_binary);
+ if (resource_format_importer)
+ memdelete(resource_format_importer);
memdelete( resource_format_po );
diff --git a/core/resource.cpp b/core/resource.cpp
index 4b09a506ff..9b5bac5f32 100644
--- a/core/resource.cpp
+++ b/core/resource.cpp
@@ -35,119 +35,6 @@
#include <stdio.h>
-void ResourceImportMetadata::set_editor(const String& p_editor) {
-
- editor=p_editor;
-}
-
-String ResourceImportMetadata::get_editor() const{
-
- return editor;
-}
-
-void ResourceImportMetadata::add_source(const String& p_path,const String& p_md5) {
-
- Source s;
- s.md5=p_md5;
- s.path=p_path;
- sources.push_back(s);
-}
-
-String ResourceImportMetadata::get_source_path(int p_idx) const{
- ERR_FAIL_INDEX_V(p_idx,sources.size(),String());
- return sources[p_idx].path;
-}
-String ResourceImportMetadata::get_source_md5(int p_idx) const{
- ERR_FAIL_INDEX_V(p_idx,sources.size(),String());
- return sources[p_idx].md5;
-}
-
-void ResourceImportMetadata::set_source_md5(int p_idx,const String& p_md5) {
-
- ERR_FAIL_INDEX(p_idx,sources.size());
- sources[p_idx].md5=p_md5;
-
-}
-
-void ResourceImportMetadata::remove_source(int p_idx){
-
- ERR_FAIL_INDEX(p_idx,sources.size());
- sources.remove(p_idx);
-
-}
-
-int ResourceImportMetadata::get_source_count() const {
-
- return sources.size();
-}
-void ResourceImportMetadata::set_option(const String& p_key, const Variant& p_value) {
-
- if (p_value.get_type()==Variant::NIL) {
- options.erase(p_key);
- return;
- }
-
- ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT);
- ERR_FAIL_COND(p_value.get_type() == Variant::_RID);
-
- options[p_key]=p_value;
-
-}
-
-bool ResourceImportMetadata::has_option(const String& p_key) const {
-
- return options.has(p_key);
-}
-
-Variant ResourceImportMetadata::get_option(const String& p_key) const {
-
- ERR_FAIL_COND_V(!options.has(p_key),Variant());
-
- return options[p_key];
-}
-
-void ResourceImportMetadata::get_options(List<String> *r_options) const {
-
- for(Map<String,Variant>::Element *E=options.front();E;E=E->next()) {
-
- r_options->push_back(E->key());
- }
-
-}
-
-PoolStringArray ResourceImportMetadata::_get_options() const {
-
- PoolStringArray option_names;
- option_names.resize(options.size());
- int i=0;
- for(Map<String,Variant>::Element *E=options.front();E;E=E->next()) {
-
- option_names.set(i++,E->key());
- }
-
- return option_names;
-}
-
-void ResourceImportMetadata::_bind_methods() {
-
- ClassDB::bind_method(_MD("set_editor","name"),&ResourceImportMetadata::set_editor);
- ClassDB::bind_method(_MD("get_editor"),&ResourceImportMetadata::get_editor);
- ClassDB::bind_method(_MD("add_source","path","md5"),&ResourceImportMetadata::add_source, "");
- ClassDB::bind_method(_MD("get_source_path","idx"),&ResourceImportMetadata::get_source_path);
- ClassDB::bind_method(_MD("get_source_md5","idx"),&ResourceImportMetadata::get_source_md5);
- ClassDB::bind_method(_MD("set_source_md5","idx", "md5"),&ResourceImportMetadata::set_source_md5);
- ClassDB::bind_method(_MD("remove_source","idx"),&ResourceImportMetadata::remove_source);
- ClassDB::bind_method(_MD("get_source_count"),&ResourceImportMetadata::get_source_count);
- ClassDB::bind_method(_MD("set_option","key","value"),&ResourceImportMetadata::set_option);
- ClassDB::bind_method(_MD("get_option","key"),&ResourceImportMetadata::get_option);
- ClassDB::bind_method(_MD("get_options"),&ResourceImportMetadata::_get_options);
-}
-
-ResourceImportMetadata::ResourceImportMetadata() {
-
-
-}
-
void Resource::emit_changed() {
@@ -381,21 +268,6 @@ void Resource::notify_change_to_owners() {
}
}
-void Resource::set_import_metadata(const Ref<ResourceImportMetadata>& p_metadata) {
-#ifdef TOOLS_ENABLED
- import_metadata=p_metadata;
-#endif
-}
-
-Ref<ResourceImportMetadata> Resource::get_import_metadata() const {
-
-#ifdef TOOLS_ENABLED
- return import_metadata;
-#else
- return Ref<ResourceImportMetadata>();
-#endif
-
-}
#ifdef TOOLS_ENABLED
@@ -461,8 +333,6 @@ void Resource::_bind_methods() {
ClassDB::bind_method(_MD("set_name","name"),&Resource::set_name);
ClassDB::bind_method(_MD("get_name"),&Resource::get_name);
ClassDB::bind_method(_MD("get_rid"),&Resource::get_rid);
- ClassDB::bind_method(_MD("set_import_metadata","metadata"),&Resource::set_import_metadata);
- ClassDB::bind_method(_MD("get_import_metadata"),&Resource::get_import_metadata);
ClassDB::bind_method(_MD("set_local_to_scene","enable"),&Resource::set_local_to_scene);
ClassDB::bind_method(_MD("is_local_to_scene"),&Resource::is_local_to_scene);
ClassDB::bind_method(_MD("get_local_scene:Node"),&Resource::get_local_scene);
@@ -483,9 +353,11 @@ Resource::Resource() {
#ifdef TOOLS_ENABLED
last_modified_time=0;
+ import_last_modified_time=0;
#endif
subindex=0;
+ local_to_scene=false;
local_scene=NULL;
}
diff --git a/core/resource.h b/core/resource.h
index 2b071c8e1c..b29077a3b8 100644
--- a/core/resource.h
+++ b/core/resource.h
@@ -46,47 +46,6 @@ virtual String get_base_extension() const { return m_ext; }\
private:
-class ResourceImportMetadata : public Reference {
-
- GDCLASS( ResourceImportMetadata, Reference );
-
- struct Source {
- String path;
- String md5;
- };
-
- Vector<Source> sources;
- String editor;
-
- Map<String,Variant> options;
-
- PoolStringArray _get_options() const;
-
-protected:
-
- static void _bind_methods();
-public:
-
- void set_editor(const String& p_editor);
- String get_editor() const;
-
- void add_source(const String& p_path,const String& p_md5="");
- String get_source_path(int p_idx) const;
- String get_source_md5(int p_idx) const;
- void set_source_md5(int p_idx,const String& p_md5);
- void remove_source(int p_idx);
- int get_source_count() const;
-
- void set_option(const String& p_key, const Variant& p_value);
- Variant get_option(const String& p_key) const;
- bool has_option(const String& p_key) const;
-
- void get_options(List<String> *r_options) const;
-
-
- ResourceImportMetadata();
-};
-
class Resource : public Reference {
@@ -106,8 +65,9 @@ friend class ResourceCache;
virtual bool _use_builtin_script() const { return true; }
#ifdef TOOLS_ENABLED
- Ref<ResourceImportMetadata> import_metadata;
uint64_t last_modified_time;
+ uint64_t import_last_modified_time;
+ String import_path;
#endif
bool local_to_scene;
@@ -147,10 +107,6 @@ public:
Ref<Resource> duplicate(bool p_subresources=false);
Ref<Resource> duplicate_for_local_scene(Node *p_scene,Map<Ref<Resource>,Ref<Resource> >& remap_cache);
-
- void set_import_metadata(const Ref<ResourceImportMetadata>& p_metadata);
- Ref<ResourceImportMetadata> get_import_metadata() const;
-
void set_local_to_scene(bool p_enable);
bool is_local_to_scene() const;
virtual void setup_local_to_scene();
@@ -164,6 +120,12 @@ public:
virtual void set_last_modified_time(uint64_t p_time) { last_modified_time=p_time; }
uint64_t get_last_modified_time() const { return last_modified_time; }
+ virtual void set_import_last_modified_time(uint64_t p_time) { import_last_modified_time=p_time; }
+ uint64_t get_import_last_modified_time() const { return import_last_modified_time; }
+
+ void set_import_path(const String& p_path) { import_path=p_path; }
+ String get_import_path() const { return import_path; }
+
#endif
virtual RID get_rid() const; // some resources may offer conversion to RID
diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp
index ede37bbe8a..50617f2062 100644
--- a/core/safe_refcount.cpp
+++ b/core/safe_refcount.cpp
@@ -44,6 +44,14 @@ uint32_t atomic_conditional_increment( register uint32_t * pw ) {
return *pw;
}
+uint32_t atomic_increment( register uint32_t * pw ) {
+
+ (*pw)++;
+
+ return *pw;
+
+}
+
uint32_t atomic_decrement( register uint32_t * pw ) {
(*pw)--;
diff --git a/core/translation.cpp b/core/translation.cpp
index d5ec61b8d6..8835cb133c 100644
--- a/core/translation.cpp
+++ b/core/translation.cpp
@@ -751,6 +751,20 @@ static const char* locale_names[]={
0
};
+bool TranslationServer::is_locale_valid(const String& p_locale) {
+
+ const char **ptr=locale_list;
+
+ while (*ptr) {
+
+ if (*ptr==p_locale)
+ return true;
+ ptr++;
+ }
+
+ return false;
+
+}
Vector<String> TranslationServer::get_all_locales() {
diff --git a/core/translation.h b/core/translation.h
index 85ab4a229d..feed352549 100644
--- a/core/translation.h
+++ b/core/translation.h
@@ -102,6 +102,7 @@ public:
static Vector<String> get_all_locales();
static Vector<String> get_all_locale_names();
+ static bool is_locale_valid(const String& p_locale);
void set_tool_translation(const Ref<Translation>& p_translation);
StringName tool_translate(const StringName& p_message) const;
diff --git a/core/ustring.cpp b/core/ustring.cpp
index 478c427fb9..a0d26ea0af 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -3410,8 +3410,17 @@ String String::c_escape() const {
escaped=escaped.replace("\t","\\t");
escaped=escaped.replace("\v","\\v");
escaped=escaped.replace("\'","\\'");
- escaped=escaped.replace("\"","\\\"");
escaped=escaped.replace("\?","\\?");
+ escaped=escaped.replace("\"","\\\"");
+
+ return escaped;
+}
+
+String String::c_escape_multiline() const {
+
+ String escaped=*this;
+ escaped=escaped.replace("\\","\\\\");
+ escaped=escaped.replace("\"","\\\"");
return escaped;
}
diff --git a/core/ustring.h b/core/ustring.h
index 426762a9e1..5665a23112 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -218,6 +218,7 @@ public:
String http_escape() const;
String http_unescape() const;
String c_escape() const;
+ String c_escape_multiline() const;
String c_unescape() const;
String json_escape() const;
String word_wrap(int p_chars_per_line) const;
diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp
index a833a275df..1e938b4899 100644
--- a/core/variant_parser.cpp
+++ b/core/variant_parser.cpp
@@ -1873,7 +1873,7 @@ Error VariantWriter::write(const Variant& p_variant, StoreStringFunc p_store_str
String str=p_variant;
- str="\""+str.c_escape()+"\"";
+ str="\""+str.c_escape_multiline()+"\"";
p_store_string_func(p_store_string_ud, str );
} break;
case Variant::VECTOR2: {
@@ -2091,7 +2091,7 @@ Error VariantWriter::write(const Variant& p_variant, StoreStringFunc p_store_str
dict.get_key_list(&keys);
keys.sort();
- p_store_string_func(p_store_string_ud,"{ ");
+ p_store_string_func(p_store_string_ud,"{\n");
for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
/*
@@ -2099,14 +2099,14 @@ Error VariantWriter::write(const Variant& p_variant, StoreStringFunc p_store_str
continue;
*/
write(E->get(),p_store_string_func,p_store_string_ud,p_encode_res_func,p_encode_res_ud);
- p_store_string_func(p_store_string_ud,":");
+ p_store_string_func(p_store_string_ud,": ");
write(dict[E->get()],p_store_string_func,p_store_string_ud,p_encode_res_func,p_encode_res_ud);
if (E->next())
- p_store_string_func(p_store_string_ud,", ");
+ p_store_string_func(p_store_string_ud,",\n");
}
- p_store_string_func(p_store_string_ud," }");
+ p_store_string_func(p_store_string_ud,"\n}");
} break;
diff --git a/core/vector.h b/core/vector.h
index 3119657cbb..1cb3fee256 100644
--- a/core/vector.h
+++ b/core/vector.h
@@ -81,7 +81,7 @@ class Vector {
size_t p;
if (_mul_overflow(p_elements, sizeof(T), &o)) return false;
*out = nearest_power_of_2(o);
- if (_add_overflow(o, 32, &p)) return false; //no longer allocated here
+ if (_add_overflow(o, static_cast<size_t>(32), &p)) return false; //no longer allocated here
return true;
#else
// Speed is more important than correctness here, do the operations unchecked
diff --git a/doc/base/classes.xml b/doc/base/classes.xml
index 0b8c5cc11c..9223b887a3 100644
--- a/doc/base/classes.xml
+++ b/doc/base/classes.xml
@@ -667,7 +667,7 @@
</methods>
<constants>
<constant name="PI" value="3.141593">
- Constant that represents how many times the diameter of a circumference fits around it's perimeter.
+ Constant that represents how many times the diameter of a circumference fits around its perimeter.
</constant>
</constants>
</class>
@@ -8025,7 +8025,7 @@
Circular Shape for 2D Physics.
</brief_description>
<description>
- Circular Shape for 2D Physics. This shape is useful for modeling balls or small characters and it's collision detection with everything else is very fast.
+ Circular Shape for 2D Physics. This shape is useful for modeling balls or small characters and its collision detection with everything else is very fast.
</description>
<methods>
<method name="get_radius" qualifiers="const">
@@ -11258,7 +11258,7 @@
This function is called for each file exported and depending from the return value one of many things might happen.
1) If returned value is null, the file is exported as is.
2) If the returned value is a RawAray (array of bytes), the content of that array becomes the new file being exported.
- 3) If the file must also change it's name when exported, then a [Dictionary] must be returned with two fields: 'name' with the new filename and 'data' with a [RawArray] containing the raw contents of the file. Even if the name is changed, the run-time will redirect the old file to the new file automatically when accessed.
+ 3) If the file must also change its name when exported, then a [Dictionary] must be returned with two fields: 'name' with the new filename and 'data' with a [RawArray] containing the raw contents of the file. Even if the name is changed, the run-time will redirect the old file to the new file automatically when accessed.
</description>
</method>
</methods>
@@ -11706,7 +11706,7 @@
</class>
<class name="EditorPlugin" inherits="Node" category="Core">
<brief_description>
- Used by the editor to extend it's functionality.
+ Used by the editor to extend its functionality.
</brief_description>
<description>
Plugins are used by the editor to extend functionality. The most common types of plugins are those which edit a given node or resource type, import plugins and export plugins.
@@ -12005,7 +12005,7 @@
</method>
<method name="save_external_data" qualifiers="virtual">
<description>
- This method is called after the editor save the project or when the it's closed. It asks the plugin to save edited external scenes/resources.
+ This method is called after the editor saves the project or when it's closed. It asks the plugin to save edited external scenes/resources.
</description>
</method>
<method name="set_state" qualifiers="virtual">
@@ -15970,7 +15970,7 @@
Request does not have a response(yet).
</constant>
<constant name="RESULT_BODY_SIZE_LIMIT_EXCEEDED" value="7">
- Request exceded it's maximum size limit, see [method set_body_size_limit].
+ Request exceded its maximum size limit, see [method set_body_size_limit].
</constant>
<constant name="RESULT_REQUEST_FAILED" value="8">
Request failed. (unused)
@@ -15982,7 +15982,7 @@
HTTPRequest couldn't write to the download file.
</constant>
<constant name="RESULT_REDIRECT_LIMIT_REACHED" value="11">
- Request reached it's maximum redirect limit, see [method set_max_redirects].
+ Request reached its maximum redirect limit, see [method set_max_redirects].
</constant>
</constants>
</class>
@@ -16088,7 +16088,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the status of hostname queued for resolving, given it's queue ID. Returned status can be any of the RESOLVER_STATUS_* enumeration.
+ Return the status of hostname queued for resolving, given its queue ID. Returned status can be any of the RESOLVER_STATUS_* enumeration.
</description>
</method>
<method name="resolve_hostname">
@@ -22660,7 +22660,7 @@
Nodes can also process input events. When set, the [method _input] function will be called for each input that the program receives. In many cases, this can be overkill (unless used for simple projects), and the [method _unhandled_input] function might be preferred; it is called when the input event was not handled by anyone else (typically, GUI [Control] nodes), ensuring that the node only receives the events that were meant for it.
To keep track of the scene hierarchy (especially when instancing scenes into other scenes), an "owner" can be set for the node with [method set_owner]. This keeps track of who instanced what. This is mostly useful when writing editors and tools, though.
Finally, when a node is freed with [method free] or [method queue_free], it will also free all its children.
- [b]Networking with nodes:[/b] After connecting to a server (or making one, see [NetworkedMultiplayerENet]) it is possible to use the built-in RPC (remote procedure call) system to easily communicate over the network. By calling [method rpc] with a method name, it will be called locally, and in all connected peers (peers = clients and the server that accepts connections), with behaviour varying depending on the network mode ([method set_network_mode]) on the receiving peer. To identify which [Node] receives the RPC call Godot will use it's [NodePath] (make sure node names are the same on all peers).
+ [b]Networking with nodes:[/b] After connecting to a server (or making one, see [NetworkedMultiplayerENet]) it is possible to use the built-in RPC (remote procedure call) system to easily communicate over the network. By calling [method rpc] with a method name, it will be called locally, and in all connected peers (peers = clients and the server that accepts connections), with behaviour varying depending on the network mode ([method set_network_mode]) on the receiving peer. To identify which [Node] receives the RPC call Godot will use its [NodePath] (make sure node names are the same on all peers).
</description>
<methods>
<method name="_enter_tree" qualifiers="virtual">
@@ -33832,7 +33832,7 @@
</signal>
<signal name="sleeping_state_changed">
<description>
- Emitted when the body changes it's sleeping state. Either by sleeping or waking up.
+ Emitted when the body changes its sleeping state. Either by sleeping or waking up.
</description>
</signal>
</signals>
@@ -34227,7 +34227,7 @@
</signal>
<signal name="sleeping_state_changed">
<description>
- Emitted when the body changes it's sleeping state. Either by sleeping or waking up.
+ Emitted when the body changes its sleeping state. Either by sleeping or waking up.
</description>
</signal>
</signals>
@@ -35889,7 +35889,7 @@
<return type="Error">
</return>
<description>
- Tries to wait for the [Semaphore], if it's value is zero, blocks until non-zero.
+ Tries to wait for the [Semaphore], if its value is zero, blocks until non-zero.
</description>
</method>
</methods>
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 458da85e74..2923dfff9f 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -1,8 +1,7 @@
#include "rasterizer_canvas_gles3.h"
#include "os/os.h"
-#ifdef IPHONE_ENABLED
-// for some reason glClearDepth seems to have been removed in iOS ES3.h
+#ifndef GLES_OVER_GL
#define glClearDepth glClearDepthf
#endif
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index f47fcfcd9b..c0af9b3bcf 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -3,8 +3,7 @@
#include "os/os.h"
#include "rasterizer_canvas_gles3.h"
-#ifdef IPHONE_ENABLED
-// for some reason glClearDepth seems to have been removed in iOS ES3.h
+#ifndef GLES_OVER_GL
#define glClearDepth glClearDepthf
#endif
@@ -166,7 +165,7 @@ void RasterizerSceneGLES3::shadow_atlas_set_quadrant_subdivision(RID p_atlas,int
subdiv<<=1;
}
- subdiv=int(Math::sqrt(subdiv));
+ subdiv=int(Math::sqrt((float)subdiv));
//obtain the number that will be x*x
@@ -568,7 +567,7 @@ void RasterizerSceneGLES3::reflection_atlas_set_subdivision(RID p_ref_atlas,int
subdiv<<=1;
}
- subdiv=int(Math::sqrt(subdiv));
+ subdiv=int(Math::sqrt((float)subdiv));
if (reflection_atlas->subdiv==subdiv)
return;
@@ -4567,7 +4566,7 @@ static _FORCE_INLINE_ Vector3 ImportanceSampleGGX(Vector2 Xi, float Roughness, V
// Compute distribution direction
float Phi = 2.0f * Math_PI * Xi.x;
- float CosTheta = Math::sqrt((1.0f - Xi.y) / (1.0f + (a*a - 1.0f) * Xi.y));
+ float CosTheta = Math::sqrt((float)(1.0f - Xi.y) / (1.0f + (a*a - 1.0f) * Xi.y));
float SinTheta = Math::sqrt((float)Math::abs(1.0f - CosTheta * CosTheta));
// Convert to spherical direction
@@ -4615,7 +4614,7 @@ void RasterizerSceneGLES3::_generate_brdf() {
float NoV = float(i+1)/(brdf_size); //avoid storing nov0
Vector3 V;
- V.x = Math::sqrt( 1.0 - NoV * NoV );
+ V.x = Math::sqrt( 1.0f - NoV * NoV );
V.y = 0.0;
V.z = NoV;
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 9f1ff396f1..a96fd8dd41 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -135,7 +135,7 @@ Image RasterizerStorageGLES3::_get_gl_image_and_format(const Image& p_image, Ima
} break;
case Image::FORMAT_RGB565: {
-#ifdef IPHONE_ENABLED
+#ifndef GLES_OVER_GL
r_gl_internal_format=GL_RGB565;
#else
//#warning TODO: Convert tod 555 if 565 is not supported (GLES3.3-)
@@ -5256,7 +5256,7 @@ void RasterizerStorageGLES3::update_particles() {
shaders.particles.set_uniform(ParticlesShaderGLES3::ORIGIN,particles->origin);
- float new_phase = Math::fmod(particles->phase+(frame.delta/particles->lifetime),1.0);
+ float new_phase = Math::fmod((float)particles->phase+(frame.delta/particles->lifetime),(float)1.0);
shaders.particles.set_uniform(ParticlesShaderGLES3::SYSTEM_PHASE,new_phase);
shaders.particles.set_uniform(ParticlesShaderGLES3::PREV_SYSTEM_PHASE,particles->phase);
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 14b1b229b2..5f0e647545 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -65,15 +65,15 @@ Error AudioDriverPulseAudio::init() {
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
- &attr, // use buffering attributes from above
- &error_code
- );
+ "Godot", // application name
+ PA_STREAM_PLAYBACK,
+ NULL, // default device
+ "Sound", // stream description
+ &spec,
+ NULL, // use default channel map
+ &attr, // use buffering attributes from above
+ &error_code
+ );
if (pulse == NULL) {
fprintf(stderr, "PulseAudio ERR: %s\n", pa_strerror(error_code));\
@@ -103,6 +103,7 @@ float AudioDriverPulseAudio::get_latency() {
void AudioDriverPulseAudio::thread_func(void* p_udata) {
+ print_line("thread");
AudioDriverPulseAudio* ad = (AudioDriverPulseAudio*)p_udata;
while (!ad->exit_thread) {
@@ -121,9 +122,9 @@ void AudioDriverPulseAudio::thread_func(void* p_udata) {
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
+ // pa_simple_write always consumes the entire buffer
int error_code;
int byte_size = ad->buffer_size * sizeof(int16_t) * ad->channels;
@@ -134,7 +135,7 @@ void AudioDriverPulseAudio::thread_func(void* p_udata) {
ad->exit_thread = true;
break;
}
- }
+ }
ad->thread_exited = true;
}
diff --git a/main/input_default.cpp b/main/input_default.cpp
index ea4e3f9505..0561f2bb34 100644
--- a/main/input_default.cpp
+++ b/main/input_default.cpp
@@ -381,15 +381,12 @@ void InputDefault::parse_input_event(const InputEvent& p_event) {
if (!p_event.is_echo()) {
for (const Map<StringName,InputMap::Action>::Element *E=InputMap::get_singleton()->get_action_map().front();E;E=E->next()) {
- if (InputMap::get_singleton()->event_is_action(p_event,E->key())) {
-
- if(is_action_pressed(E->key()) != p_event.is_pressed()) {
- Action action;
- action.fixed_frame=Engine::get_singleton()->get_fixed_frames();
- action.idle_frame=Engine::get_singleton()->get_idle_frames();
- action.pressed=p_event.is_pressed();
- action_state[E->key()]=action;
- }
+ if (InputMap::get_singleton()->event_is_action(p_event,E->key()) && is_action_pressed(E->key()) != p_event.is_pressed()) {
+ Action action;
+ action.fixed_frame=Engine::get_singleton()->get_fixed_frames();
+ action.idle_frame=Engine::get_singleton()->get_idle_frames();
+ action.pressed=p_event.is_pressed();
+ action_state[E->key()]=action;
}
}
}
@@ -486,7 +483,7 @@ Point2 InputDefault::get_last_mouse_speed() const {
int InputDefault::get_mouse_button_mask() const {
- return OS::get_singleton()->get_mouse_button_state();
+ return mouse_button_mask;// do not trust OS implementaiton, should remove it - OS::get_singleton()->get_mouse_button_state();
}
void InputDefault::warp_mouse_pos(const Vector2& p_to) {
diff --git a/main/main.cpp b/main/main.cpp
index 559f5e359b..094b6aedae 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -38,7 +38,7 @@
#include "script_debugger_local.h"
#include "script_debugger_remote.h"
#include "message_queue.h"
-#include "path_remap.h"
+
#include "input_map.h"
#include "io/resource_loader.h"
#include "scene/main/scene_main_loop.h"
@@ -85,7 +85,7 @@ AudioServer *audio_server=NULL;
static MessageQueue *message_queue=NULL;
static Performance *performance = NULL;
-static PathRemap *path_remap;
+
static PackedData *packed_data=NULL;
#ifdef MINIZIP_ENABLED
static ZipArchive *zip_packed_data=NULL;
@@ -183,8 +183,6 @@ void Main::print_help(const char* p_binary) {
#ifdef TOOLS_ENABLED
OS::get_singleton()->print("\t-doctool FILE: Dump the whole engine api to FILE in XML format. If FILE exists, it will be merged.\n");
OS::get_singleton()->print("\t-nodocbase: Disallow dump the base types (used with -doctool).\n");
- OS::get_singleton()->print("\t-optimize FILE Save an optimized copy of scene to FILE.\n");
- OS::get_singleton()->print("\t-optimize_preset [preset] Use a given preset for optimization.\n");
OS::get_singleton()->print("\t-export [target] Export the project using given export target.\n");
#endif
}
@@ -215,7 +213,6 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
register_core_settings(); //here globals is present
- path_remap = memnew( PathRemap );
translation_server = memnew( TranslationServer );
performance = memnew( Performance );
globals->add_singleton(GlobalConfig::Singleton("Performance",performance));
@@ -874,8 +871,6 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
memdelete(packed_data);
if (file_access_network_client)
memdelete(file_access_network_client);
- if(path_remap)
- memdelete(path_remap);
// Note 1: *zip_packed_data live into *packed_data
// Note 2: PackedData::~PackedData destroy this.
@@ -935,8 +930,6 @@ Error Main::setup2() {
}
MAIN_PRINT("Main: Load Remaps");
- path_remap->load_remaps();
-
Color clear = GLOBAL_DEF("rendering/viewport/default_clear_color",Color(0.3,0.3,0.3));
VisualServer::get_singleton()->set_default_clear_color(clear);
@@ -1046,6 +1039,7 @@ Error Main::setup2() {
translation_server->load_translations();
+ audio_server->load_default_bus_layout();
if (use_debug_profiler && script_debugger) {
script_debugger->profiling_start();
@@ -1078,12 +1072,9 @@ bool Main::start() {
String script;
String test;
String screen;
- String optimize;
- String optimize_preset;
String _export_platform;
String _import;
String _import_script;
- String dumpstrings;
bool noquit=false;
bool export_debug=false;
bool project_manager_request = false;
@@ -1112,10 +1103,6 @@ bool Main::start() {
Engine::get_singleton()->_custom_level=args[i+1];
} else if (args[i]=="-test") {
test=args[i+1];
- } else if (args[i]=="-optimize") {
- optimize=args[i+1];
- } else if (args[i]=="-optimize_preset") {
- optimize_preset=args[i+1];
} else if (args[i]=="-export") {
editor=true; //needs editor
_export_platform=args[i+1];
@@ -1129,9 +1116,6 @@ bool Main::start() {
} else if (args[i]=="-import_script") {
editor=true; //needs editor
_import_script=args[i+1];
- } else if (args[i]=="-dumpstrings") {
- editor=true; //needs editor
- dumpstrings=args[i+1];
} else {
// The parameter does not match anything known, don't skip the next argument
parsed_pair=false;
@@ -1166,10 +1150,6 @@ bool Main::start() {
return false;
}
- if (optimize!="")
- editor=true; //need editor
-
-
#endif
@@ -1403,22 +1383,7 @@ bool Main::start() {
Error serr = editor_node->load_scene(local_game_path);
- if (serr==OK) {
- if (optimize!="") {
-
- editor_node->save_optimized_copy(optimize,optimize_preset);
- if (!noquit)
- sml->quit();
- }
-
- if (dumpstrings!="") {
-
- editor_node->save_translatable_strings(dumpstrings);
- if (!noquit)
- sml->quit();
- }
- }
}
OS::get_singleton()->set_context(OS::CONTEXT_EDITOR);
@@ -1790,8 +1755,6 @@ void Main::cleanup() {
memdelete(input_map);
if (translation_server)
memdelete( translation_server );
- if (path_remap)
- memdelete(path_remap);
if (globals)
memdelete(globals);
if (engine)
diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp
index 4f3516c097..d0fc241734 100644
--- a/modules/gdscript/gd_functions.cpp
+++ b/modules/gdscript/gd_functions.cpp
@@ -159,85 +159,85 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
case MATH_SIN: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::sin(*p_args[0]);
+ r_ret=Math::sin((double)*p_args[0]);
} break;
case MATH_COS: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::cos(*p_args[0]);
+ r_ret=Math::cos((double)*p_args[0]);
} break;
case MATH_TAN: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::tan(*p_args[0]);
+ r_ret=Math::tan((double)*p_args[0]);
} break;
case MATH_SINH: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::sinh(*p_args[0]);
+ r_ret=Math::sinh((double)*p_args[0]);
} break;
case MATH_COSH: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::cosh(*p_args[0]);
+ r_ret=Math::cosh((double)*p_args[0]);
} break;
case MATH_TANH: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::tanh(*p_args[0]);
+ r_ret=Math::tanh((double)*p_args[0]);
} break;
case MATH_ASIN: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::asin(*p_args[0]);
+ r_ret=Math::asin((double)*p_args[0]);
} break;
case MATH_ACOS: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::acos(*p_args[0]);
+ r_ret=Math::acos((double)*p_args[0]);
} break;
case MATH_ATAN: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::atan(*p_args[0]);
+ r_ret=Math::atan((double)*p_args[0]);
} break;
case MATH_ATAN2: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::atan2(*p_args[0],*p_args[1]);
+ r_ret=Math::atan2((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_SQRT: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::sqrt(*p_args[0]);
+ r_ret=Math::sqrt((double)*p_args[0]);
} break;
case MATH_FMOD: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::fmod(*p_args[0],*p_args[1]);
+ r_ret=Math::fmod((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_FPOSMOD: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::fposmod(*p_args[0],*p_args[1]);
+ r_ret=Math::fposmod((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_FLOOR: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::floor(*p_args[0]);
+ r_ret=Math::floor((double)*p_args[0]);
} break;
case MATH_CEIL: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::ceil(*p_args[0]);
+ r_ret=Math::ceil((double)*p_args[0]);
} break;
case MATH_ROUND: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::round(*p_args[0]);
+ r_ret=Math::round((double)*p_args[0]);
} break;
case MATH_ABS: {
VALIDATE_ARG_COUNT(1);
@@ -247,7 +247,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_ret=ABS(i);
} else if (p_args[0]->get_type()==Variant::REAL) {
- real_t r = *p_args[0];
+ double r = *p_args[0];
r_ret=Math::abs(r);
} else {
@@ -279,58 +279,58 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::pow(*p_args[0],*p_args[1]);
+ r_ret=Math::pow((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_LOG: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::log(*p_args[0]);
+ r_ret=Math::log((double)*p_args[0]);
} break;
case MATH_EXP: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::exp(*p_args[0]);
+ r_ret=Math::exp((double)*p_args[0]);
} break;
case MATH_ISNAN: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::is_nan(*p_args[0]);
+ r_ret=Math::is_nan((double)*p_args[0]);
} break;
case MATH_ISINF: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::is_inf(*p_args[0]);
+ r_ret=Math::is_inf((double)*p_args[0]);
} break;
case MATH_EASE: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::ease(*p_args[0],*p_args[1]);
+ r_ret=Math::ease((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_DECIMALS: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::step_decimals(*p_args[0]);
+ r_ret=Math::step_decimals((double)*p_args[0]);
} break;
case MATH_STEPIFY: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::stepify(*p_args[0],*p_args[1]);
+ r_ret=Math::stepify((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_LERP: {
VALIDATE_ARG_COUNT(3);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
VALIDATE_ARG_NUM(2);
- r_ret=Math::lerp(*p_args[0],*p_args[1],*p_args[2]);
+ r_ret=Math::lerp((double)*p_args[0],(double)*p_args[1],(double)*p_args[2]);
} break;
case MATH_DECTIME: {
VALIDATE_ARG_COUNT(3);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
VALIDATE_ARG_NUM(2);
- r_ret=Math::dectime(*p_args[0],*p_args[1],*p_args[2]);
+ r_ret=Math::dectime((double)*p_args[0],(double)*p_args[1],(double)*p_args[2]);
} break;
case MATH_RANDOMIZE: {
Math::randomize();
@@ -346,7 +346,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::random(*p_args[0],*p_args[1]);
+ r_ret=Math::random((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_SEED: {
VALIDATE_ARG_COUNT(1);
@@ -369,22 +369,22 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
case MATH_DEG2RAD: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::deg2rad(*p_args[0]);
+ r_ret=Math::deg2rad((double)*p_args[0]);
} break;
case MATH_RAD2DEG: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::rad2deg(*p_args[0]);
+ r_ret=Math::rad2deg((double)*p_args[0]);
} break;
case MATH_LINEAR2DB: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::linear2db(*p_args[0]);
+ r_ret=Math::linear2db((double)*p_args[0]);
} break;
case MATH_DB2LINEAR: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::db2linear(*p_args[0]);
+ r_ret=Math::db2linear((double)*p_args[0]);
} break;
case LOGIC_MAX: {
VALIDATE_ARG_COUNT(2);
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index 70659326e5..34c39c8024 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/modules/gdscript/gd_parser.cpp
@@ -1704,7 +1704,7 @@ GDParser::PatternNode *GDParser::_parse_pattern(bool p_static)
}
switch (token) {
- // dictionary
+ // array
case GDTokenizer::TK_BRACKET_OPEN: {
tokenizer->advance();
pattern->pt_type = GDParser::PatternNode::PT_ARRAY;
@@ -1759,7 +1759,7 @@ GDParser::PatternNode *GDParser::_parse_pattern(bool p_static)
pattern->bind = tokenizer->get_token_identifier();
tokenizer->advance();
} break;
- // array
+ // dictionary
case GDTokenizer::TK_CURLY_BRACKET_OPEN: {
tokenizer->advance();
pattern->pt_type = GDParser::PatternNode::PT_DICTIONARY;
@@ -1826,17 +1826,16 @@ GDParser::PatternNode *GDParser::_parse_pattern(bool p_static)
}
}
} break;
+ case GDTokenizer::TK_WILDCARD: {
+ tokenizer->advance();
+ pattern->pt_type = PatternNode::PT_WILDCARD;
+ } break;
// all the constants like strings and numbers
default: {
Node *value = _parse_and_reduce_expression(pattern, p_static);
if (error_set) {
return NULL;
}
- if (value->type == Node::TYPE_IDENTIFIER && static_cast<IdentifierNode*>(value)->name == "_") {
- // wildcard pattern
- pattern->pt_type = PatternNode::PT_WILDCARD;
- break;
- }
if (value->type != Node::TYPE_IDENTIFIER && value->type != Node::TYPE_CONSTANT) {
_set_error("Only constant expressions or variables allowed in a pattern");
diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp
index 70fc991bcc..5be2a2beae 100644
--- a/modules/gdscript/gd_tokenizer.cpp
+++ b/modules/gdscript/gd_tokenizer.cpp
@@ -119,6 +119,7 @@ const char* GDTokenizer::token_names[TK_MAX]={
"':'",
"'\\n'",
"PI",
+"_",
"Error",
"EOF",
"Cursor"};
@@ -899,6 +900,7 @@ void GDTokenizerText::_advance() {
{TK_CF_PASS,"pass"},
{TK_SELF,"self"},
{TK_CONST_PI,"PI"},
+ {TK_WILDCARD,"_"},
{TK_ERROR,NULL}
};
diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h
index 9a6f4df9c4..5d955ff1ae 100644
--- a/modules/gdscript/gd_tokenizer.h
+++ b/modules/gdscript/gd_tokenizer.h
@@ -127,6 +127,7 @@ public:
TK_DOLLAR,
TK_NEWLINE,
TK_CONST_PI,
+ TK_WILDCARD,
TK_ERROR,
TK_EOF,
TK_CURSOR, //used for code completion
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 051d1d85cd..db47ee43ce 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -38,7 +38,7 @@
GDScriptLanguage *script_language_gd=NULL;
ResourceFormatLoaderGDScript *resource_loader_gd=NULL;
ResourceFormatSaverGDScript *resource_saver_gd=NULL;
-
+#if 0
#ifdef TOOLS_ENABLED
#include "tools/editor/editor_import_export.h"
@@ -135,7 +135,7 @@ static void register_editor_plugin() {
#endif
-
+#endif
void register_gdscript_types() {
ClassDB::register_class<GDScript>();
@@ -148,11 +148,12 @@ void register_gdscript_types() {
ResourceLoader::add_resource_format_loader(resource_loader_gd);
resource_saver_gd=memnew( ResourceFormatSaverGDScript );
ResourceSaver::add_resource_format_saver(resource_saver_gd);
-
+#if 0
#ifdef TOOLS_ENABLED
EditorNode::add_init_callback(register_editor_plugin);
#endif
+#endif
}
void unregister_gdscript_types() {
diff --git a/modules/stb_vorbis/SCsub b/modules/stb_vorbis/SCsub
new file mode 100644
index 0000000000..897d05961c
--- /dev/null
+++ b/modules/stb_vorbis/SCsub
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+Import('env')
+Import('env_modules')
+
+# Thirdparty source files
+
+env_stb_vorbis = env_modules.Clone()
+
+env_stb_vorbis.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
new file mode 100644
index 0000000000..31bf5ac292
--- /dev/null
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
@@ -0,0 +1,236 @@
+
+#include "audio_stream_ogg_vorbis.h"
+#include "thirdparty/stb_vorbis/stb_vorbis.c"
+#include "os/file_access.h"
+
+
+void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame* p_buffer,int p_frames) {
+
+ ERR_FAIL_COND(!active);
+
+ int todo=p_frames;
+
+ while(todo) {
+
+ int mixed = stb_vorbis_get_samples_float_interleaved(ogg_stream,2,(float*)p_buffer,todo*2);
+ todo-=mixed;
+
+ if (todo) {
+ //end of file!
+ if (false) {
+ //loop
+ seek_pos(0);
+ loops++;
+ } else {
+ for(int i=mixed;i<p_frames;i++) {
+ p_buffer[i]=AudioFrame(0,0);
+ }
+ active=false;
+ }
+ }
+ }
+
+
+}
+
+float AudioStreamPlaybackOGGVorbis::get_stream_sampling_rate() {
+
+ return vorbis_stream->sample_rate;
+}
+
+
+void AudioStreamPlaybackOGGVorbis::start(float p_from_pos) {
+
+ seek_pos(p_from_pos);
+ active=true;
+ loops=0;
+ _begin_resample();
+
+
+}
+
+void AudioStreamPlaybackOGGVorbis::stop() {
+
+ active=false;
+}
+bool AudioStreamPlaybackOGGVorbis::is_playing() const {
+
+ return active;
+}
+
+int AudioStreamPlaybackOGGVorbis::get_loop_count() const {
+
+ return loops;
+}
+
+float AudioStreamPlaybackOGGVorbis::get_pos() const {
+
+ return float(frames_mixed)/vorbis_stream->sample_rate;
+}
+void AudioStreamPlaybackOGGVorbis::seek_pos(float p_time) {
+
+ if (!active)
+ return;
+
+ stb_vorbis_seek(ogg_stream, uint32_t(p_time*vorbis_stream->sample_rate));
+}
+
+float AudioStreamPlaybackOGGVorbis::get_length() const {
+
+ return vorbis_stream->length;
+}
+
+AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
+ if (ogg_alloc.alloc_buffer) {
+ AudioServer::get_singleton()->audio_data_free(ogg_alloc.alloc_buffer);
+ stb_vorbis_close(ogg_stream);
+ }
+}
+
+Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() {
+
+
+
+ Ref<AudioStreamPlaybackOGGVorbis> ovs;
+ printf("instance at %p, data %p\n",this,data);
+
+ ERR_FAIL_COND_V(data==NULL,ovs);
+
+ ovs.instance();
+ ovs->vorbis_stream=Ref<AudioStreamOGGVorbis>(this);
+ ovs->ogg_alloc.alloc_buffer=(char*)AudioServer::get_singleton()->audio_data_alloc(decode_mem_size);
+ ovs->ogg_alloc.alloc_buffer_length_in_bytes=decode_mem_size;
+ ovs->frames_mixed=0;
+ ovs->active=false;
+ ovs->loops=0;
+ int error ;
+ ovs->ogg_stream = stb_vorbis_open_memory( (const unsigned char*)data, data_len, &error, &ovs->ogg_alloc );
+ if (!ovs->ogg_stream) {
+
+ AudioServer::get_singleton()->audio_data_free(ovs->ogg_alloc.alloc_buffer);
+ ovs->ogg_alloc.alloc_buffer=NULL;
+ ERR_FAIL_COND_V(!ovs->ogg_stream,Ref<AudioStreamPlaybackOGGVorbis>());
+ }
+
+ return ovs;
+}
+
+String AudioStreamOGGVorbis::get_stream_name() const {
+
+ return "";//return stream_name;
+}
+
+Error AudioStreamOGGVorbis::setup(const uint8_t *p_data,uint32_t p_data_len) {
+
+
+#define MAX_TEST_MEM (1<<20)
+
+ uint32_t alloc_try=1024;
+ PoolVector<char> alloc_mem;
+ PoolVector<char>::Write w;
+ stb_vorbis * ogg_stream=NULL;
+ stb_vorbis_alloc ogg_alloc;
+
+ while(alloc_try<MAX_TEST_MEM) {
+
+ alloc_mem.resize(alloc_try);
+ w = alloc_mem.write();
+
+ ogg_alloc.alloc_buffer=w.ptr();
+ ogg_alloc.alloc_buffer_length_in_bytes=alloc_try;
+
+ int error;
+ ogg_stream = stb_vorbis_open_memory( (const unsigned char*)p_data, p_data_len, &error, &ogg_alloc );
+
+ if (!ogg_stream && error==VORBIS_outofmem) {
+ w = PoolVector<char>::Write();
+ alloc_try*=2;
+ } else {
+ break;
+ }
+ }
+ ERR_FAIL_COND_V(alloc_try==MAX_TEST_MEM,ERR_OUT_OF_MEMORY);
+ ERR_FAIL_COND_V(ogg_stream==NULL,ERR_FILE_CORRUPT);
+
+ stb_vorbis_info info = stb_vorbis_get_info(ogg_stream);
+
+ channels = info.channels;
+ sample_rate = info.sample_rate;
+ decode_mem_size = alloc_try;
+ //does this work? (it's less mem..)
+ //decode_mem_size = ogg_alloc.alloc_buffer_length_in_bytes + info.setup_memory_required + info.temp_memory_required + info.max_frame_size;
+
+ //print_line("succeded "+itos(ogg_alloc.alloc_buffer_length_in_bytes)+" setup "+itos(info.setup_memory_required)+" setup temp "+itos(info.setup_temp_memory_required)+" temp "+itos(info.temp_memory_required)+" maxframe"+itos(info.max_frame_size));
+
+ length=stb_vorbis_stream_length_in_seconds(ogg_stream);
+ stb_vorbis_close(ogg_stream);
+
+ data = AudioServer::get_singleton()->audio_data_alloc(p_data_len,p_data);
+ data_len=p_data_len;
+
+ printf("create at %p, data %p\n",this,data);
+ return OK;
+}
+
+AudioStreamOGGVorbis::AudioStreamOGGVorbis() {
+
+
+ data=NULL;
+ length=0;
+ sample_rate=1;
+ channels=1;
+ decode_mem_size=0;
+}
+
+
+
+
+RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path, const String& p_original_path, Error *r_error) {
+ if (r_error)
+ *r_error=OK;
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ if (!f) {
+ *r_error=ERR_CANT_OPEN;
+ ERR_FAIL_COND_V(!f,RES());
+ }
+
+ size_t len = f->get_len();
+
+ PoolVector<uint8_t> data;
+ data.resize(len);
+ PoolVector<uint8_t>::Write w = data.write();
+
+ f->get_buffer(w.ptr(),len);
+
+ memdelete(f);
+
+ Ref<AudioStreamOGGVorbis> ogg_stream;
+ ogg_stream.instance();
+
+ Error err = ogg_stream->setup(w.ptr(),len);
+
+ if (err!=OK) {
+ *r_error=err;
+ ogg_stream.unref();
+ ERR_FAIL_V(RES());
+ }
+
+ return ogg_stream;
+}
+
+void ResourceFormatLoaderAudioStreamOGGVorbis::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("ogg");
+}
+String ResourceFormatLoaderAudioStreamOGGVorbis::get_resource_type(const String &p_path) const {
+
+ if (p_path.get_extension().to_lower()=="ogg")
+ return "AudioStreamOGGVorbis";
+ return "";
+}
+
+bool ResourceFormatLoaderAudioStreamOGGVorbis::handles_type(const String& p_type) const {
+ return (p_type=="AudioStream" || p_type=="AudioStreamOGG" || p_type=="AudioStreamOGGVorbis");
+}
+
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.h b/modules/stb_vorbis/audio_stream_ogg_vorbis.h
new file mode 100644
index 0000000000..4555423f85
--- /dev/null
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.h
@@ -0,0 +1,84 @@
+#ifndef AUDIO_STREAM_STB_VORBIS_H
+#define AUDIO_STREAM_STB_VORBIS_H
+
+#include "servers/audio/audio_stream.h"
+#include "io/resource_loader.h"
+
+#define STB_VORBIS_HEADER_ONLY
+#include "thirdparty/stb_vorbis/stb_vorbis.c"
+#undef STB_VORBIS_HEADER_ONLY
+
+
+class AudioStreamOGGVorbis;
+
+class AudioStreamPlaybackOGGVorbis : public AudioStreamPlaybackResampled {
+
+ GDCLASS( AudioStreamPlaybackOGGVorbis, AudioStreamPlaybackResampled )
+
+ stb_vorbis * ogg_stream;
+ stb_vorbis_alloc ogg_alloc;
+ uint32_t frames_mixed;
+ bool active;
+ int loops;
+
+friend class AudioStreamOGGVorbis;
+
+ Ref<AudioStreamOGGVorbis> vorbis_stream;
+protected:
+
+ virtual void _mix_internal(AudioFrame* p_buffer, int p_frames);
+ virtual float get_stream_sampling_rate();
+
+public:
+ virtual void start(float p_from_pos=0.0);
+ virtual void stop();
+ virtual bool is_playing() const;
+
+ virtual int get_loop_count() const; //times it looped
+
+ virtual float get_pos() const;
+ virtual void seek_pos(float p_time);
+
+ virtual float get_length() const; //if supported, otherwise return 0
+
+ AudioStreamPlaybackOGGVorbis() { }
+ ~AudioStreamPlaybackOGGVorbis();
+};
+
+class AudioStreamOGGVorbis : public AudioStream {
+
+ GDCLASS( AudioStreamOGGVorbis, AudioStream )
+ OBJ_SAVE_TYPE( AudioStream ) //children are all saved as AudioStream, so they can be exchanged
+
+friend class AudioStreamPlaybackOGGVorbis;
+
+ void *data;
+ uint32_t data_len;
+
+ int decode_mem_size;
+ float sample_rate;
+ int channels;
+ float length;
+
+public:
+
+
+ virtual Ref<AudioStreamPlayback> instance_playback();
+ virtual String get_stream_name() const;
+
+ Error setup(const uint8_t *p_data, uint32_t p_data_len);
+
+ AudioStreamOGGVorbis();
+};
+
+class ResourceFormatLoaderAudioStreamOGGVorbis : public ResourceFormatLoader {
+public:
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String& p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+
+
+#endif
diff --git a/modules/stb_vorbis/config.py b/modules/stb_vorbis/config.py
new file mode 100644
index 0000000000..fb920482f5
--- /dev/null
+++ b/modules/stb_vorbis/config.py
@@ -0,0 +1,7 @@
+
+def can_build(platform):
+ return True
+
+
+def configure(env):
+ pass
diff --git a/scene/resources/audio_stream.cpp b/modules/stb_vorbis/register_types.cpp
index 7c269de007..143ad6f47e 100644
--- a/scene/resources/audio_stream.cpp
+++ b/modules/stb_vorbis/register_types.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* audio_stream.cpp */
+/* register_types.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -26,36 +26,19 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "audio_stream.h"
+#include "register_types.h"
+#include "audio_stream_ogg_vorbis.h"
-//////////////////////////////
-
-
-void AudioStreamPlayback::_bind_methods() {
-
- ClassDB::bind_method(_MD("play","from_pos_sec"),&AudioStreamPlayback::play,DEFVAL(0));
- ClassDB::bind_method(_MD("stop"),&AudioStreamPlayback::stop);
- ClassDB::bind_method(_MD("is_playing"),&AudioStreamPlayback::is_playing);
-
- ClassDB::bind_method(_MD("set_loop","enabled"),&AudioStreamPlayback::set_loop);
- ClassDB::bind_method(_MD("has_loop"),&AudioStreamPlayback::has_loop);
-
- ClassDB::bind_method(_MD("get_loop_count"),&AudioStreamPlayback::get_loop_count);
-
- ClassDB::bind_method(_MD("seek_pos","pos"),&AudioStreamPlayback::seek_pos);
- ClassDB::bind_method(_MD("get_pos"),&AudioStreamPlayback::get_pos);
-
- ClassDB::bind_method(_MD("get_length"),&AudioStreamPlayback::get_length);
- ClassDB::bind_method(_MD("get_channels"),&AudioStreamPlayback::get_channels);
- ClassDB::bind_method(_MD("get_mix_rate"),&AudioStreamPlayback::get_mix_rate);
- ClassDB::bind_method(_MD("get_minimum_buffer_size"),&AudioStreamPlayback::get_minimum_buffer_size);
+static ResourceFormatLoaderAudioStreamOGGVorbis *vorbis_stream_loader = NULL;
+void register_stb_vorbis_types() {
+ vorbis_stream_loader = memnew( ResourceFormatLoaderAudioStreamOGGVorbis );
+ ResourceLoader::add_resource_format_loader(vorbis_stream_loader);
+ ClassDB::register_class<AudioStreamOGGVorbis>();
}
+void unregister_stb_vorbis_types() {
-void AudioStream::_bind_methods() {
-
-
+ memdelete( vorbis_stream_loader );
}
-
diff --git a/modules/stb_vorbis/register_types.h b/modules/stb_vorbis/register_types.h
new file mode 100644
index 0000000000..2824aa9f0c
--- /dev/null
+++ b/modules/stb_vorbis/register_types.h
@@ -0,0 +1,30 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan 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. */
+/*************************************************************************/
+void register_stb_vorbis_types();
+void unregister_stb_vorbis_types();
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 169af6fbec..a0f23a511f 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -610,85 +610,85 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func,const Variant** p_inp
case VisualScriptBuiltinFunc::MATH_SIN: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::sin(*p_inputs[0]);
+ *r_return=Math::sin((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_COS: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::cos(*p_inputs[0]);
+ *r_return=Math::cos((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_TAN: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::tan(*p_inputs[0]);
+ *r_return=Math::tan((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_SINH: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::sinh(*p_inputs[0]);
+ *r_return=Math::sinh((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_COSH: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::cosh(*p_inputs[0]);
+ *r_return=Math::cosh((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_TANH: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::tanh(*p_inputs[0]);
+ *r_return=Math::tanh((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_ASIN: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::asin(*p_inputs[0]);
+ *r_return=Math::asin((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_ACOS: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::acos(*p_inputs[0]);
+ *r_return=Math::acos((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_ATAN: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::atan(*p_inputs[0]);
+ *r_return=Math::atan((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_ATAN2: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- *r_return=Math::atan2(*p_inputs[0],*p_inputs[1]);
+ *r_return=Math::atan2((double)*p_inputs[0],(double)*p_inputs[1]);
} break;
case VisualScriptBuiltinFunc::MATH_SQRT: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::sqrt(*p_inputs[0]);
+ *r_return=Math::sqrt((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_FMOD: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- *r_return=Math::fmod(*p_inputs[0],*p_inputs[1]);
+ *r_return=Math::fmod((double)*p_inputs[0],(double)*p_inputs[1]);
} break;
case VisualScriptBuiltinFunc::MATH_FPOSMOD: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- *r_return=Math::fposmod(*p_inputs[0],*p_inputs[1]);
+ *r_return=Math::fposmod((double)*p_inputs[0],(double)*p_inputs[1]);
} break;
case VisualScriptBuiltinFunc::MATH_FLOOR: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::floor(*p_inputs[0]);
+ *r_return=Math::floor((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_CEIL: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::ceil(*p_inputs[0]);
+ *r_return=Math::ceil((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_ROUND: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::round(*p_inputs[0]);
+ *r_return=Math::round((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_ABS: {
@@ -730,58 +730,58 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func,const Variant** p_inp
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- *r_return=Math::pow(*p_inputs[0],*p_inputs[1]);
+ *r_return=Math::pow((double)*p_inputs[0],(double)*p_inputs[1]);
} break;
case VisualScriptBuiltinFunc::MATH_LOG: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::log(*p_inputs[0]);
+ *r_return=Math::log((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_EXP: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::exp(*p_inputs[0]);
+ *r_return=Math::exp((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_ISNAN: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::is_nan(*p_inputs[0]);
+ *r_return=Math::is_nan((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_ISINF: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::is_inf(*p_inputs[0]);
+ *r_return=Math::is_inf((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_EASE: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- *r_return=Math::ease(*p_inputs[0],*p_inputs[1]);
+ *r_return=Math::ease((double)*p_inputs[0],(double)*p_inputs[1]);
} break;
case VisualScriptBuiltinFunc::MATH_DECIMALS: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::step_decimals(*p_inputs[0]);
+ *r_return=Math::step_decimals((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_STEPIFY: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- *r_return=Math::stepify(*p_inputs[0],*p_inputs[1]);
+ *r_return=Math::stepify((double)*p_inputs[0],(double)*p_inputs[1]);
} break;
case VisualScriptBuiltinFunc::MATH_LERP: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
VALIDATE_ARG_NUM(2);
- *r_return=Math::lerp(*p_inputs[0],*p_inputs[1],*p_inputs[2]);
+ *r_return=Math::lerp((double)*p_inputs[0],(double)*p_inputs[1],(double)*p_inputs[2]);
} break;
case VisualScriptBuiltinFunc::MATH_DECTIME: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
VALIDATE_ARG_NUM(2);
- *r_return=Math::dectime(*p_inputs[0],*p_inputs[1],*p_inputs[2]);
+ *r_return=Math::dectime((double)*p_inputs[0],(double)*p_inputs[1],(double)*p_inputs[2]);
} break;
case VisualScriptBuiltinFunc::MATH_RANDOMIZE: {
Math::randomize();
@@ -797,7 +797,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func,const Variant** p_inp
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- *r_return=Math::random(*p_inputs[0],*p_inputs[1]);
+ *r_return=Math::random((double)*p_inputs[0],(double)*p_inputs[1]);
} break;
case VisualScriptBuiltinFunc::MATH_SEED: {
@@ -820,22 +820,22 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func,const Variant** p_inp
case VisualScriptBuiltinFunc::MATH_DEG2RAD: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::deg2rad(*p_inputs[0]);
+ *r_return=Math::deg2rad((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_RAD2DEG: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::rad2deg(*p_inputs[0]);
+ *r_return=Math::rad2deg((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_LINEAR2DB: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::linear2db(*p_inputs[0]);
+ *r_return=Math::linear2db((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::MATH_DB2LINEAR: {
VALIDATE_ARG_NUM(0);
- *r_return=Math::db2linear(*p_inputs[0]);
+ *r_return=Math::db2linear((double)*p_inputs[0]);
} break;
case VisualScriptBuiltinFunc::LOGIC_MAX: {
diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template
index 873eef0566..c46a15bd12 100644
--- a/platform/android/build.gradle.template
+++ b/platform/android/build.gradle.template
@@ -52,11 +52,10 @@ android {
java.srcDirs = ['src'
$$GRADLE_JAVA_DIRS$$
]
- resources.srcDirs = [
+ res.srcDirs = [
'res'
$$GRADLE_RES_DIRS$$
]
- res.srcDirs = ['res']
// libs.srcDirs = ['libs']
aidl.srcDirs = [
'aidl'
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 33283eccea..8e1fda74ed 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -38,7 +38,7 @@
#include "os/os.h"
#include "platform/android/logo.h"
#include <string.h>
-
+#if 0
static const char* android_perms[]={
"ACCESS_CHECKIN_PROPERTIES",
@@ -1915,3 +1915,4 @@ void register_android_exporter() {
EditorImportExport::get_singleton()->add_export_platform(exporter);
}
+#endif
diff --git a/platform/bb10/export/export.cpp b/platform/bb10/export/export.cpp
index cc994c8f24..3e6dadb094 100644
--- a/platform/bb10/export/export.cpp
+++ b/platform/bb10/export/export.cpp
@@ -40,7 +40,7 @@
#include "io/xml_parser.h"
#define MAX_DEVICES 5
-
+#if 0
class EditorExportPlatformBB10 : public EditorExportPlatform {
GDCLASS( EditorExportPlatformBB10,EditorExportPlatform );
@@ -827,3 +827,4 @@ void register_bb10_exporter() {
}
+#endif
diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h
index da146fcdd0..4c2064663a 100644
--- a/platform/javascript/audio_driver_javascript.h
+++ b/platform/javascript/audio_driver_javascript.h
@@ -36,8 +36,6 @@
class AudioDriverJavaScript : public AudioDriver {
public:
- void set_singleton();
-
virtual const char* get_name() const;
virtual Error init();
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 55b05a9123..a701823b2e 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -14,9 +14,7 @@ def get_name():
def can_build():
import os
- if (not os.environ.has_key("EMSCRIPTEN_ROOT")):
- return False
- return True
+ return os.environ.has_key("EMSCRIPTEN_ROOT")
def get_opts():
@@ -79,9 +77,8 @@ def configure(env):
# These flags help keep the file size down
env.Append(CPPFLAGS=["-fno-exceptions", '-DNO_SAFE_CAST', '-fno-rtti'])
env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-DPTHREAD_NO_RENAME', '-DNO_FCNTL', '-DMPC_FIXED_POINT', '-DTYPED_METHOD_BIND', '-DNO_THREADS'])
- env.Append(CPPFLAGS=['-DGLES2_ENABLED'])
+ env.Append(CPPFLAGS=['-DGLES3_ENABLED'])
env.Append(CPPFLAGS=['-DGLES_NO_CLIENT_ARRAYS'])
-# env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DMPC_FIXED_POINT'])
if env['wasm'] == 'yes':
env.Append(LINKFLAGS=['-s', 'BINARYEN=1'])
@@ -101,14 +98,10 @@ def configure(env):
env.Append(CPPFLAGS=['-DJAVASCRIPT_EVAL_ENABLED'])
env.Append(LINKFLAGS=['-O2'])
+ env.Append(LINKFLAGS=['-s', 'USE_WEBGL2=1'])
# env.Append(LINKFLAGS=['-g4'])
# print "CCCOM is:", env.subst('$CCCOM')
# print "P: ", env['p'], " Platofrm: ", env['platform']
import methods
-
- env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')})
- env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')})
- #env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } )
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index e0ff9932cc..e487383ef4 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -38,6 +38,9 @@
#include "os/os.h"
#include "platform/javascript/logo.h"
#include "string.h"
+
+
+#if 0
class EditorExportPlatformJavaScript : public EditorExportPlatform {
GDCLASS( EditorExportPlatformJavaScript,EditorExportPlatform );
@@ -181,8 +184,8 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t>& p_html, const St
String current_line = lines[i];
current_line = current_line.replace("$GODOT_TMEM",itos((1<<(max_memory+5))*1024*1024));
current_line = current_line.replace("$GODOT_BASE",p_name);
- current_line = current_line.replace("$GODOT_CANVAS_WIDTH",GlobalConfig::get_singleton()->get("display/width"));
- current_line = current_line.replace("$GODOT_CANVAS_HEIGHT",GlobalConfig::get_singleton()->get("display/height"));
+ current_line = current_line.replace("$GODOT_CANVAS_WIDTH",GlobalConfig::get_singleton()->get("display/window/width"));
+ current_line = current_line.replace("$GODOT_CANVAS_HEIGHT",GlobalConfig::get_singleton()->get("display/window/height"));
current_line = current_line.replace("$GODOT_HEAD_TITLE",!html_title.empty()?html_title:(String) GlobalConfig::get_singleton()->get("application/name"));
current_line = current_line.replace("$GODOT_HEAD_INCLUDE",html_head_include);
current_line = current_line.replace("$GODOT_STYLE_FONT_FAMILY",html_font_family);
@@ -424,3 +427,4 @@ void register_javascript_exporter() {
}
+#endif
diff --git a/platform/javascript/godot_shell.html b/platform/javascript/godot_shell.html
index a8b9594935..65f3b4a340 100644
--- a/platform/javascript/godot_shell.html
+++ b/platform/javascript/godot_shell.html
@@ -277,10 +277,10 @@ $GODOT_STYLE_INCLUDE
statusElement.appendChild(closeNote);
Presentation.setStatusVisible(true);
},
- isWebGLAvailable: function isWebGLAvailable() {
+ isWebGL2Available: function isWebGL2Available() {
var context;
try {
- context = canvasElement.getContext("webgl") || canvasElement.getContext("experimental-webgl");
+ context = canvasElement.getContext("webgl2") || canvasElement.getContext("experimental-webgl2");
} catch (e) {}
return !!context;
},
@@ -319,12 +319,12 @@ $GODOT_STYLE_INCLUDE
outputElement.firstChild.remove();
}
var msg = document.createElement("div");
- if (text.trim().startsWith("**ERROR**")
- || text.startsWith("**EXCEPTION**")) {
+ if (String.prototype.trim.call(text).startsWith("**ERROR**")
+ || String.prototype.trim.call(text).startsWith("**EXCEPTION**")) {
msg.style.color = "#d44";
- } else if (text.trim().startsWith("**WARNING**")) {
+ } else if (String.prototype.trim.call(text).startsWith("**WARNING**")) {
msg.style.color = "#ccc000";
- } else if (text.trim().startsWith("**SCRIPT ERROR**")) {
+ } else if (String.prototype.trim.call(text).startsWith("**SCRIPT ERROR**")) {
msg.style.color = "#c6d";
}
msg.textContent = text;
@@ -395,8 +395,8 @@ $GODOT_STYLE_INCLUDE
}
};
- if (!Presentation.isWebGLAvailable()) {
- Presentation.setStatus("WebGL appears to be unsupported in the current browser.\nPlease try updating or use a different browser.");
+ if (!Presentation.isWebGL2Available()) {
+ Presentation.setStatus("WebGL2 appears to be unsupported in the current browser.\nPlease try updating or use a different browser.");
Presentation.preventLoading = true;
} else {
Presentation.setStatus("Downloading...");
diff --git a/platform/javascript/javascript_eval.cpp b/platform/javascript/javascript_eval.cpp
index a79e5473c2..72b7ab06cd 100644
--- a/platform/javascript/javascript_eval.cpp
+++ b/platform/javascript/javascript_eval.cpp
@@ -156,7 +156,7 @@ Variant JavaScript::eval(const String& p_code, bool p_use_global_exec_context) {
void JavaScript::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("eval", "code", "use_global_execution_context"), &JavaScript::eval, false);
+ ClassDB::bind_method(_MD("eval", "code", "use_global_execution_context"), &JavaScript::eval, false);
}
JavaScript::JavaScript() {
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 317a6676a4..b8c3dea3b4 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -28,7 +28,7 @@
/*************************************************************************/
#include "os_javascript.h"
-#include "drivers/gles2/rasterizer_gles2.h"
+#include "drivers/gles3/rasterizer_gles3.h"
#include "core/io/file_access_buffered_fa.h"
#include "drivers/unix/file_access_unix.h"
#include "drivers/unix/dir_access_unix.h"
@@ -47,7 +47,7 @@ int OS_JavaScript::get_video_driver_count() const {
const char * OS_JavaScript::get_video_driver_name(int p_driver) const {
- return "GLES2";
+ return "GLES3";
}
OS::VideoMode OS_JavaScript::get_default_video_mode() const {
@@ -237,30 +237,20 @@ void OS_JavaScript::initialize(const VideoMode& p_desired,int p_video_driver,int
print_line("Init Audio");
AudioDriverManager::add_driver(&audio_driver_javascript);
+ audio_driver_javascript.set_singleton();
+ if (audio_driver_javascript.init() != OK) {
- if (true) {
- RasterizerGLES2 *rasterizer_gles22=memnew( RasterizerGLES2(false,false,false,false) );
- rasterizer_gles22->set_use_framebuffers(false); //not supported by emscripten
- if (gl_extensions)
- rasterizer_gles22->set_extensions(gl_extensions);
- rasterizer = rasterizer_gles22;
- } else {
- //rasterizer = memnew( RasterizerGLES1(true, false) );
+ ERR_PRINT("Initializing audio failed.");
}
+ RasterizerGLES3::register_config();
+ RasterizerGLES3::make_current();
+
print_line("Init VS");
- visual_server = memnew( VisualServerRaster(rasterizer) );
- visual_server->init();
+ visual_server = memnew( VisualServerRaster() );
visual_server->cursor_set_visible(false, 0);
- /*AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
-
- if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
-
- ERR_PRINT("Initializing audio failed.");
- }*/
-
print_line("Init Physicsserver");
physics_server = memnew( PhysicsServerSW );
@@ -767,14 +757,6 @@ void OS_JavaScript::main_loop_request_quit() {
main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
}
-void OS_JavaScript::reload_gfx() {
-
- if (gfx_init_func)
- gfx_init_func(gfx_init_ud,use_gl2,video_mode.width,video_mode.height,video_mode.fullscreen);
- if (rasterizer)
- rasterizer->reload_vram();
-}
-
Error OS_JavaScript::shell_open(String p_uri) {
/* clang-format off */
EM_ASM_({
@@ -877,7 +859,6 @@ OS_JavaScript::OS_JavaScript(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, Get
main_loop=NULL;
last_id=1;
gl_extensions=NULL;
- rasterizer=NULL;
window_maximized=false;
get_data_dir_func=p_get_data_dir_func;
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index d11494a8aa..582f128ce8 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -33,8 +33,6 @@
#include "drivers/unix/os_unix.h"
#include "os/main_loop.h"
#include "servers/physics/physics_server_sw.h"
-#include "servers/spatial_sound/spatial_sound_server_sw.h"
-#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
#include "servers/audio_server.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
#include "servers/visual/rasterizer.h"
@@ -70,7 +68,6 @@ private:
int64_t time_to_save_sync;
int64_t last_sync_time;
- Rasterizer *rasterizer;
VisualServer *visual_server;
PhysicsServer *physics_server;
Physics2DServer *physics_2d_server;
@@ -165,8 +162,6 @@ public:
void set_opengl_extensions(const char* p_gl_extensions);
- void reload_gfx();
-
virtual Error shell_open(String p_uri);
virtual String get_data_dir() const;
String get_executable_path() const;
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 1cb41cede2..3a97827c16 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -39,7 +39,7 @@
#include "os/os.h"
#include "platform/osx/logo.h"
#include "string.h"
-
+#if 0
class EditorExportPlatformOSX : public EditorExportPlatform {
@@ -546,3 +546,4 @@ void register_osx_exporter() {
}
+#endif
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index f31c91ef6d..167a5831cf 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -65,7 +65,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
-
+#if 0
#include "version.h"
#include "export.h"
#include "object.h"
@@ -2390,3 +2390,4 @@ void register_uwp_exporter() {
Ref<EditorExportPlatformUWP> exporter = Ref<EditorExportPlatformUWP>(memnew(EditorExportPlatformUWP));
EditorImportExport::get_singleton()->add_export_platform(exporter);
}
+#endif
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index 1ad61844d0..88d534887b 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -29,7 +29,7 @@
#include "export.h"
#include "platform/windows/logo.h"
#include "tools/editor/editor_import_export.h"
-
+#if 0
void register_windows_exporter() {
Image img(_windows_logo);
@@ -50,3 +50,4 @@ void register_windows_exporter() {
}
+#endif
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index d1d769adf7..b230dda9cb 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -254,6 +254,25 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) // Check For Windows Messages
{
+ case WM_SETFOCUS:
+ {
+ window_has_focus = true;
+ // Re-capture cursor if we're in one of the capture modes
+ if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED) {
+ SetCapture(hWnd);
+ }
+ break;
+ }
+ case WM_KILLFOCUS:
+ {
+ window_has_focus = false;
+
+ // Release capture if we're in one of the capture modes
+ if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED) {
+ ReleaseCapture();
+ }
+ break;
+ }
case WM_ACTIVATE: // Watch For Window Activate Message
{
minimized = HIWORD(wParam) != 0;
@@ -266,19 +285,17 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
alt_mem=false;
control_mem=false;
shift_mem=false;
- if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED) {
RECT clipRect;
GetClientRect(hWnd, &clipRect);
ClientToScreen(hWnd, (POINT*) &clipRect.left);
ClientToScreen(hWnd, (POINT*) &clipRect.right);
ClipCursor(&clipRect);
SetCapture(hWnd);
-
}
} else {
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
alt_mem=false;
-
};
return 0; // Return To The Message Loop
@@ -345,6 +362,9 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
}
+ // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
+ if (!window_has_focus && mouse_mode==MOUSE_MODE_CAPTURED)
+ break;
/*
LPARAM extra = GetMessageExtraInfo();
if (IsPenEvent(extra)) {
@@ -376,7 +396,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
mm.button_mask|=(wParam&MK_XBUTTON2)?(1<<6):0;*/
mm.x=GET_X_LPARAM(lParam);
mm.y=GET_Y_LPARAM(lParam);
-
+
if (mouse_mode==MOUSE_MODE_CAPTURED) {
Point2i c(video_mode.width/2,video_mode.height/2);
@@ -410,7 +430,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
mm.relative_y=mm.y-old_y;
old_x=mm.x;
old_y=mm.y;
- if (main_loop)
+ if (window_has_focus && main_loop)
input->parse_input_event(event);
@@ -714,9 +734,8 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
joypad->probe_joypads();
} break;
case WM_SETCURSOR: {
-
if(LOWORD(lParam) == HTCLIENT) {
- if(mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED) {
+ if(window_has_focus && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED)) {
//Hide the cursor
if(hCursor == NULL)
hCursor = SetCursor(NULL);
@@ -948,7 +967,7 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_
main_loop=NULL;
outside=true;
-
+ window_has_focus=true;
WNDCLASSEXW wc;
video_mode=p_desired;
@@ -1326,17 +1345,17 @@ void OS_Windows::set_mouse_mode(MouseMode p_mode) {
if (mouse_mode==p_mode)
return;
mouse_mode=p_mode;
- if (p_mode==MOUSE_MODE_CAPTURED) {
+ if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED) {
RECT clipRect;
GetClientRect(hWnd, &clipRect);
ClientToScreen(hWnd, (POINT*) &clipRect.left);
ClientToScreen(hWnd, (POINT*) &clipRect.right);
ClipCursor(&clipRect);
- SetCapture(hWnd);
center=Point2i(video_mode.width/2,video_mode.height/2);
POINT pos = { (int) center.x, (int) center.y };
ClientToScreen(hWnd, &pos);
- SetCursorPos(pos.x, pos.y);
+ if (mouse_mode==MOUSE_MODE_CAPTURED)
+ SetCursorPos(pos.x, pos.y);
} else {
ReleaseCapture();
ClipCursor(NULL);
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index a5c8ecbe1b..2c8fa64f8e 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -118,6 +118,7 @@ class OS_Windows : public OS {
bool control_mem;
bool meta_mem;
bool force_quit;
+ bool window_has_focus;
uint32_t last_button_state;
CursorShape cursor_shape;
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index b5f6359d21..89cf639114 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -61,6 +61,7 @@ def get_opts():
('use_static_cpp', 'link stdc++ statically', 'no'),
('use_sanitizer', 'Use llvm compiler sanitize address', 'no'),
('use_leak_sanitizer', 'Use llvm compiler sanitize memory leaks', 'no'),
+ ('use_lto', 'Use link time optimization', 'no'),
('pulseaudio', 'Detect & Use pulseaudio', 'yes'),
('udev', 'Use udev for gamepad connection callbacks', 'no'),
('debug_release', 'Add debug symbols to release version', 'no'),
@@ -97,12 +98,12 @@ def configure(env):
env.extra_suffix = ".llvm"
if (env["use_sanitizer"] == "yes"):
- env.Append(CXXFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer'])
+ env.Append(CCFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer'])
env.Append(LINKFLAGS=['-fsanitize=address'])
env.extra_suffix += "s"
if (env["use_leak_sanitizer"] == "yes"):
- env.Append(CXXFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer'])
+ env.Append(CCFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer'])
env.Append(LINKFLAGS=['-fsanitize=address'])
env.extra_suffix += "s"
@@ -111,22 +112,28 @@ def configure(env):
# env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
# env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
- if (env["target"] == "release"):
+ if (env["use_lto"] == "yes"):
+ env.Append(CCFLAGS=['-flto'])
+ env.Append(LINKFLAGS=['-flto'])
+
+
+ env.Append(CCFLAGS=['-pipe'])
+ env.Append(LINKFLAGS=['-pipe'])
+ if (env["target"] == "release"):
+ env.Prepend(CCFLAGS=['-Ofast'])
if (env["debug_release"] == "yes"):
- env.Append(CCFLAGS=['-g2'])
- else:
- env.Append(CCFLAGS=['-O3', '-ffast-math'])
+ env.Prepend(CCFLAGS=['-g2'])
elif (env["target"] == "release_debug"):
- env.Append(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED'])
+ env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED'])
if (env["debug_release"] == "yes"):
- env.Append(CCFLAGS=['-g2'])
+ env.Prepend(CCFLAGS=['-g2'])
elif (env["target"] == "debug"):
- env.Append(CCFLAGS=['-g2', '-Wall', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ env.Prepend(CCFLAGS=['-g2', '-Wall', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
env.ParseConfig('pkg-config x11 --cflags --libs')
env.ParseConfig('pkg-config xinerama --cflags --libs')
diff --git a/platform/x11/export/export.cpp b/platform/x11/export/export.cpp
index c1af323453..5a4751b387 100644
--- a/platform/x11/export/export.cpp
+++ b/platform/x11/export/export.cpp
@@ -30,7 +30,7 @@
#include "platform/x11/logo.h"
#include "tools/editor/editor_import_export.h"
#include "scene/resources/texture.h"
-
+#if 0
void register_x11_exporter() {
Image img(_x11_logo);
@@ -50,3 +50,4 @@ void register_x11_exporter() {
}
}
+#endif
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 41746c2431..e792d0465e 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -295,6 +295,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
}
+
ERR_FAIL_COND(!visual_server);
ERR_FAIL_COND(x11_window==0);
@@ -449,6 +450,8 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
physics_2d_server->init();
input = memnew( InputDefault );
+
+ window_has_focus = true; // Set focus to true at init
#ifdef JOYDEV_ENABLED
joypad = memnew( JoypadLinux(input));
#endif
@@ -517,17 +520,21 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) {
if (p_mode==mouse_mode)
return;
- if (mouse_mode==MOUSE_MODE_CAPTURED)
+ if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED)
XUngrabPointer(x11_display, CurrentTime);
- if (mouse_mode!=MOUSE_MODE_VISIBLE && p_mode==MOUSE_MODE_VISIBLE)
- XUndefineCursor(x11_display,x11_window);
- if (p_mode!=MOUSE_MODE_VISIBLE && mouse_mode==MOUSE_MODE_VISIBLE) {
- XDefineCursor(x11_display,x11_window,null_cursor);
+
+ // The only modes that show a cursor are VISIBLE and CONFINED
+ bool showCursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
+
+ if (showCursor) {
+ XUndefineCursor(x11_display,x11_window); // show cursor
+ } else {
+ XDefineCursor(x11_display,x11_window,null_cursor); // hide cursor
}
mouse_mode=p_mode;
- if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
while(true) {
//flush pending motion events
@@ -768,13 +775,31 @@ void OS_X11::set_window_position(const Point2& p_position) {
}
Size2 OS_X11::get_window_size() const {
- XWindowAttributes xwa;
- XGetWindowAttributes(x11_display, x11_window, &xwa);
- return Size2i(xwa.width, xwa.height);
+ // Use current_videomode width and height instead of XGetWindowAttributes
+ // since right after a XResizeWindow the attributes may not be updated yet
+ return Size2i(current_videomode.width, current_videomode.height);
}
void OS_X11::set_window_size(const Size2 p_size) {
+ // If window resizable is disabled we need to update the attributes first
+ if (is_window_resizable() == false) {
+ XSizeHints *xsh;
+ xsh = XAllocSizeHints();
+ xsh->flags = PMinSize | PMaxSize;
+ xsh->min_width = p_size.x;
+ xsh->max_width = p_size.x;
+ xsh->min_height = p_size.y;
+ xsh->max_height = p_size.y;
+ XSetWMNormalHints(x11_display, x11_window, xsh);
+ XFree(xsh);
+ }
+
+ // Resize the window
XResizeWindow(x11_display, x11_window, p_size.x, p_size.y);
+
+ // Update our videomode width and height
+ current_videomode.width = p_size.x;
+ current_videomode.height = p_size.y;
}
void OS_X11::set_window_fullscreen(bool p_enabled) {
@@ -788,15 +813,15 @@ bool OS_X11::is_window_fullscreen() const {
void OS_X11::set_window_resizable(bool p_enabled) {
XSizeHints *xsh;
+ Size2 size = get_window_size();
+
xsh = XAllocSizeHints();
xsh->flags = p_enabled ? 0L : PMinSize | PMaxSize;
if(!p_enabled) {
- XWindowAttributes xwa;
- XGetWindowAttributes(x11_display,x11_window,&xwa);
- xsh->min_width = xwa.width;
- xsh->max_width = xwa.width;
- xsh->min_height = xwa.height;
- xsh->max_height = xwa.height;
+ xsh->min_width = size.x;
+ xsh->max_width = size.x;
+ xsh->min_height = size.y;
+ xsh->max_height = size.y;
}
XSetWMNormalHints(x11_display, x11_window, xsh);
XFree(xsh);
@@ -1253,6 +1278,10 @@ void OS_X11::process_xevents() {
do_mouse_warp=false;
+
+ // Is the current mouse mode one where it needs to be grabbed.
+ bool mouse_mode_grab = mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED;
+
while (XPending(x11_display) > 0) {
XEvent event;
XNextEvent(x11_display, &event);
@@ -1271,35 +1300,45 @@ void OS_X11::process_xevents() {
minimized = (visibility->state == VisibilityFullyObscured);
} break;
case LeaveNotify: {
-
- if (main_loop && mouse_mode!=MOUSE_MODE_CAPTURED)
+ if (main_loop && !mouse_mode_grab)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
if (input)
input->set_mouse_in_window(false);
} break;
case EnterNotify: {
-
- if (main_loop && mouse_mode!=MOUSE_MODE_CAPTURED)
+ if (main_loop && !mouse_mode_grab)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
if (input)
input->set_mouse_in_window(true);
} break;
case FocusIn:
minimized = false;
+ window_has_focus = true;
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
- if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ if (mouse_mode_grab) {
+ // Show and update the cursor if confined and the window regained focus.
+ if (mouse_mode==MOUSE_MODE_CONFINED)
+ XUndefineCursor(x11_display, x11_window);
+ else if (mouse_mode==MOUSE_MODE_CAPTURED) // or re-hide it in captured mode
+ XDefineCursor(x11_display, x11_window, null_cursor);
+
XGrabPointer(
- x11_display, x11_window, True,
+ x11_display, x11_window, True,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime);
}
break;
case FocusOut:
+ window_has_focus = false;
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
- if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ if (mouse_mode_grab) {
//dear X11, I try, I really try, but you never work, you do whathever you want.
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ // Show the cursor if we're in captured mode so it doesn't look weird.
+ XUndefineCursor(x11_display, x11_window);
+ }
XUngrabPointer(x11_display, CurrentTime);
}
break;
@@ -1319,7 +1358,7 @@ void OS_X11::process_xevents() {
/* exit in case of a mouse button press */
last_timestamp=event.xbutton.time;
- if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
event.xbutton.x=last_mouse_pos.x;
event.xbutton.y=last_mouse_pos.y;
}
@@ -1342,7 +1381,6 @@ void OS_X11::process_xevents() {
mouse_event.mouse_button.pressed=(event.type==ButtonPress);
-
if (event.type==ButtonPress && event.xbutton.button==1) {
uint64_t diff = get_ticks_usec()/1000 - last_click_ms;
@@ -1376,7 +1414,6 @@ void OS_X11::process_xevents() {
// PLEASE DO ME A FAVOR AND DIE DROWNED IN A FECAL
// MOUNTAIN BECAUSE THAT'S WHERE YOU BELONG.
-
while(true) {
if (mouse_mode==MOUSE_MODE_CAPTURED && event.xmotion.x==current_videomode.width/2 && event.xmotion.y==current_videomode.height/2) {
//this is likely the warp event since it was warped here
@@ -1418,7 +1455,7 @@ void OS_X11::process_xevents() {
Point2i new_center = pos;
pos = last_mouse_pos + ( pos - center );
center=new_center;
- do_mouse_warp=true;
+ do_mouse_warp=window_has_focus; // warp the cursor if we're focused in
#else
//Dear X11, thanks for making my life miserable
@@ -1461,8 +1498,11 @@ void OS_X11::process_xevents() {
last_mouse_pos=pos;
// printf("rel: %d,%d\n", rel.x, rel.y );
-
- input->parse_input_event( motion_event);
+ // Don't propagate the motion event unless we have focus
+ // this is so that the relative motion doesn't get messed up
+ // after we regain focus.
+ if (window_has_focus || !mouse_mode_grab)
+ input->parse_input_event( motion_event);
} break;
case KeyPress:
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index 3245df32c6..3ec358f103 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -134,7 +134,7 @@ class OS_X11 : public OS_Unix {
bool force_quit;
bool minimized;
-
+ bool window_has_focus;
bool do_mouse_warp;
const char *cursor_theme;
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 04f096f229..4364e5f1fc 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -243,6 +243,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2>& p_polygon) {
_update_parent();
}
update();
+ update_configuration_warning();
}
Vector<Point2> CollisionPolygon2D::get_polygon() const {
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index a92065d6fb..45fc734aef 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -159,6 +159,7 @@ void CollisionShape2D::set_shape(const Ref<Shape2D>& p_shape) {
if (shape.is_valid())
shape->connect("changed",this,"_shape_changed");
+ update_configuration_warning();
}
Ref<Shape2D> CollisionShape2D::get_shape() const {
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
index cd99f30f6d..1051d3f5ff 100644
--- a/scene/2d/particles_2d.cpp
+++ b/scene/2d/particles_2d.cpp
@@ -364,7 +364,7 @@ void Particles2D::_process_particles(float p_delta) {
p.rot=Math::deg2rad(param[PARAM_INITIAL_ANGLE]+param[PARAM_INITIAL_ANGLE]*randomness[PARAM_INITIAL_ANGLE]*_rand_from_seed(&rand_seed));
active_count++;
- p.frame=Math::fmod(param[PARAM_ANIM_INITIAL_POS]+randomness[PARAM_ANIM_INITIAL_POS]*_rand_from_seed(&rand_seed),1.0);
+ p.frame=Math::fmod(param[PARAM_ANIM_INITIAL_POS]+randomness[PARAM_ANIM_INITIAL_POS]*_rand_from_seed(&rand_seed),1.0f);
} else {
@@ -438,7 +438,7 @@ void Particles2D::_process_particles(float p_delta) {
p.pos+=p.velocity*frame_time;
p.rot+=Math::lerp(param[PARAM_SPIN_VELOCITY],param[PARAM_SPIN_VELOCITY]*randomness[PARAM_SPIN_VELOCITY]*_rand_from_seed(&rand_seed),randomness[PARAM_SPIN_VELOCITY])*frame_time;
float anim_spd=param[PARAM_ANIM_SPEED_SCALE]+param[PARAM_ANIM_SPEED_SCALE]*randomness[PARAM_ANIM_SPEED_SCALE]*_rand_from_seed(&rand_seed);
- p.frame=Math::fposmod(p.frame+(frame_time/lifetime)*anim_spd,1.0);
+ p.frame=Math::fposmod(p.frame+(frame_time/lifetime)*anim_spd,1.0f);
active_count++;
@@ -555,7 +555,7 @@ void Particles2D::_notification(int p_what) {
float a=color.a;
//float preh=h;
h+=huerot;
- h=Math::abs(Math::fposmod(h,1.0));
+ h=Math::abs(Math::fposmod(h,1.0f));
//print_line("rand: "+rtos(randomness[PARAM_HUE_VARIATION])+" rand: "+rtos(huerand));
//print_line(itos(i)+":hue: "+rtos(preh)+" + "+rtos(huerot)+" = "+rtos(h));
color.set_hsv(h,s,v);
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index feecbd9e20..96d90a1de6 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -1262,7 +1262,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2& p_linear_velocity,const V
//all is a wall
move_and_slide_on_wall=true;
} else {
- if ( get_collision_normal().dot(p_floor_direction) > Math::cos(Math::deg2rad(45))) { //floor
+ if ( get_collision_normal().dot(p_floor_direction) > Math::cos(Math::deg2rad((float)45))) { //floor
move_and_slide_on_floor=true;
@@ -1272,7 +1272,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2& p_linear_velocity,const V
revert_motion();
return Vector2();
}
- } else if ( get_collision_normal().dot(p_floor_direction) < Math::cos(Math::deg2rad(45))) { //ceiling
+ } else if ( get_collision_normal().dot(p_floor_direction) < Math::cos(Math::deg2rad((float)45))) { //ceiling
move_and_slide_on_ceiling=true;
} else {
move_and_slide_on_wall=true;
diff --git a/scene/3d/baked_light_instance.cpp b/scene/3d/baked_light_instance.cpp
index 514c73a488..b67b75d48f 100644
--- a/scene/3d/baked_light_instance.cpp
+++ b/scene/3d/baked_light_instance.cpp
@@ -389,8 +389,8 @@ void BakedLight::_plot_face(int p_idx, int p_level, const Vector3 *p_vtx, const
Vector2 uv = get_uv(intersection,p_vtx,p_uv);
- int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
- int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0f)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0f)*bake_texture_size,0,bake_texture_size-1);
int ofs = uv_y*bake_texture_size+uv_x;
albedo_accum.r+=p_material.albedo[ofs].r;
@@ -415,8 +415,8 @@ void BakedLight::_plot_face(int p_idx, int p_level, const Vector3 *p_vtx, const
Vector2 uv = get_uv(inters,p_vtx,p_uv);
- int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
- int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0f)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0f)*bake_texture_size,0,bake_texture_size-1);
int ofs = uv_y*bake_texture_size+uv_x;
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index 8035ce1cc7..b29ae211de 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/gi_probe.cpp
@@ -510,8 +510,8 @@ void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const V
Vector2 uv = get_uv(intersection,p_vtx,p_uv);
- int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
- int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0f)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0f)*bake_texture_size,0,bake_texture_size-1);
int ofs = uv_y*bake_texture_size+uv_x;
albedo_accum.r+=p_material.albedo[ofs].r;
@@ -539,8 +539,8 @@ void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const V
Vector2 uv = get_uv(inters,p_vtx,p_uv);
- int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
- int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0f)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0f)*bake_texture_size,0,bake_texture_size-1);
int ofs = uv_y*bake_texture_size+uv_x;
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index 6843a7e9b3..69706a6039 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -620,7 +620,7 @@ void Spatial::set_visible(bool p_visible) {
bool Spatial::is_visible() const {
- return !data.visible;
+ return data.visible;
}
void Spatial::rotate(const Vector3& p_normal,float p_radians) {
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 7fa8458fe9..e02b2b2b41 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -118,17 +118,20 @@ bool AnimationPlayer::_get(const StringName& p_name,Variant &r_ret) const {
} else if (name=="blend_times") {
- Array array;
-
- array.resize(blend_times.size()*3);
- int idx=0;
+ Vector<BlendKey> keys;
for(Map<BlendKey, float >::Element *E=blend_times.front();E;E=E->next()) {
- array.set(idx*3+0,E->key().from);
- array.set(idx*3+1,E->key().to);
- array.set(idx*3+2,E->get());
- idx++;
+ keys.ordered_insert(E->key());
}
+
+ Array array;
+ for(int i=0;i<keys.size();i++) {
+
+ array.push_back(keys[i].from);
+ array.push_back(keys[i].to);
+ array.push_back(blend_times[keys[i]]);
+ }
+
r_ret=array;
} else if (name=="autoplay") {
r_ret=autoplay;
@@ -476,7 +479,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p
}
#endif
- static_cast<Node2D*>(pa->object)->set_rotation(Math::deg2rad(value));
+ static_cast<Node2D*>(pa->object)->set_rotation(Math::deg2rad((double)value));
} break;
case SP_NODE2D_SCALE: {
#ifdef DEBUG_ENABLED
@@ -690,7 +693,7 @@ void AnimationPlayer::_animation_update_transforms() {
}
#endif
- static_cast<Node2D*>(pa->object)->set_rotation(Math::deg2rad(pa->value_accum));
+ static_cast<Node2D*>(pa->object)->set_rotation(Math::deg2rad((double)pa->value_accum));
} break;
case SP_NODE2D_SCALE: {
#ifdef DEBUG_ENABLED
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index 41bae6c928..7fab651213 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -142,7 +142,7 @@ private:
StringName from;
StringName to;
- bool operator<(const BlendKey& bk) const { return from==bk.from?to<bk.to:from<bk.from; }
+ bool operator<(const BlendKey& bk) const { return from==bk.from?String(to)<String(bk.to):String(from)<String(bk.from); }
};
diff --git a/scene/audio/audio_player.cpp b/scene/audio/audio_player.cpp
new file mode 100644
index 0000000000..9fd005e6fb
--- /dev/null
+++ b/scene/audio/audio_player.cpp
@@ -0,0 +1,301 @@
+#include "audio_player.h"
+
+
+void AudioPlayer::_mix_audio() {
+
+ if (!stream_playback.is_valid()) {
+ return;
+ }
+
+ if (!active) {
+ return;
+ }
+
+ if (setseek>=0.0) {
+ stream_playback->start(setseek);
+ setseek=-1.0; //reset seek
+
+ }
+
+ int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
+
+ //get data
+ AudioFrame *buffer = mix_buffer.ptr();
+ int buffer_size = mix_buffer.size();
+
+ //mix
+ stream_playback->mix(buffer,1.0,buffer_size);
+
+ //multiply volume interpolating to avoid clicks if this changes
+ float vol = Math::db2linear(mix_volume_db);
+ float vol_inc = (Math::db2linear(volume_db) - vol)/float(buffer_size);
+
+ for(int i=0;i<buffer_size;i++) {
+ buffer[i]*=vol;
+ vol+=vol_inc;
+ }
+ //set volume for next mix
+ mix_volume_db = volume_db;
+
+ AudioFrame * targets[3]={NULL,NULL,NULL};
+
+ if (AudioServer::get_singleton()->get_speaker_mode()==AudioServer::SPEAKER_MODE_STEREO) {
+ targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,0);
+ } else {
+ switch(mix_target) {
+ case MIX_TARGET_STEREO: {
+ targets[0]=AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,1);
+ } break;
+ case MIX_TARGET_SURROUND: {
+ targets[0]=AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,1);
+ targets[1]=AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,2);
+ if (AudioServer::get_singleton()->get_speaker_mode()==AudioServer::SPEAKER_SURROUND_71) {
+ targets[2]=AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,3);
+ }
+ } break;
+ case MIX_TARGET_CENTER: {
+ targets[0]=AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,0);
+ } break;
+
+ }
+ }
+
+ for(int c=0;c<3;c++) {
+ if (!targets[c])
+ break;
+ for(int i=0;i<buffer_size;i++) {
+ targets[c][i]+=buffer[i];
+ }
+ }
+
+
+}
+
+void AudioPlayer::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+
+ AudioServer::get_singleton()->add_callback(_mix_audios,this);
+ if (autoplay && !get_tree()->is_editor_hint()) {
+ play();
+ }
+ }
+
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+
+ AudioServer::get_singleton()->remove_callback(_mix_audios,this);
+
+ }
+}
+
+void AudioPlayer::set_stream(Ref<AudioStream> p_stream) {
+
+ AudioServer::get_singleton()->lock();
+
+ mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
+
+ if (stream_playback.is_valid()) {
+ stream_playback.unref();
+ stream.unref();
+ active=false;
+ setseek=-1;
+ }
+
+ stream=p_stream;
+ stream_playback=p_stream->instance_playback();
+
+ if (stream_playback.is_null()) {
+ stream.unref();
+ ERR_FAIL_COND(stream_playback.is_null());
+ }
+
+ AudioServer::get_singleton()->unlock();
+
+}
+
+Ref<AudioStream> AudioPlayer::get_stream() const {
+
+ return stream;
+}
+
+void AudioPlayer::set_volume_db(float p_volume) {
+
+ volume_db=p_volume;
+}
+float AudioPlayer::get_volume_db() const {
+
+ return volume_db;
+}
+
+void AudioPlayer::play(float p_from_pos) {
+
+ if (stream_playback.is_valid()) {
+ mix_volume_db=volume_db; //reset volume ramp
+ setseek=p_from_pos;
+ active=true;
+ }
+}
+
+void AudioPlayer::seek(float p_seconds) {
+
+ if (stream_playback.is_valid()) {
+ setseek=p_seconds;
+ }
+}
+
+void AudioPlayer::stop() {
+
+ if (stream_playback.is_valid()) {
+ active=false;
+ }
+
+
+}
+
+bool AudioPlayer::is_playing() const {
+
+ if (stream_playback.is_valid()) {
+ return active && stream_playback->is_playing();
+ }
+
+ return false;
+}
+
+float AudioPlayer::get_pos() {
+
+ if (stream_playback.is_valid()) {
+ return stream_playback->get_pos();
+ }
+
+ return 0;
+}
+
+void AudioPlayer::set_bus(const StringName& p_bus) {
+
+ //if audio is active, must lock this
+ AudioServer::get_singleton()->lock();
+ bus=p_bus;
+ AudioServer::get_singleton()->unlock();
+
+}
+StringName AudioPlayer::get_bus() const {
+
+ for(int i=0;i<AudioServer::get_singleton()->get_bus_count();i++) {
+ if (AudioServer::get_singleton()->get_bus_name(i)==bus) {
+ return bus;
+ }
+ }
+ return "Master";
+}
+
+void AudioPlayer::set_autoplay(bool p_enable) {
+
+ autoplay=p_enable;
+}
+bool AudioPlayer::is_autoplay_enabled() {
+
+ return autoplay;
+}
+
+void AudioPlayer::set_mix_target(MixTarget p_target) {
+
+ mix_target=p_target;
+}
+
+AudioPlayer::MixTarget AudioPlayer::get_mix_target() const{
+
+ return mix_target;
+}
+
+void AudioPlayer::_set_playing(bool p_enable) {
+
+ if (p_enable)
+ play();
+ else
+ stop();
+}
+bool AudioPlayer::_is_active() const {
+
+ return active;
+}
+
+
+void AudioPlayer::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="bus") {
+
+ String options;
+ for(int i=0;i<AudioServer::get_singleton()->get_bus_count();i++) {
+ if (i>0)
+ options+=",";
+ String name = AudioServer::get_singleton()->get_bus_name(i);
+ options+=name;
+ }
+
+ property.hint_string=options;
+ }
+}
+
+void AudioPlayer::_bus_layout_changed() {
+
+ _change_notify();
+}
+
+void AudioPlayer::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_stream","stream:AudioStream"),&AudioPlayer::set_stream);
+ ClassDB::bind_method(_MD("get_stream"),&AudioPlayer::get_stream);
+
+ ClassDB::bind_method(_MD("set_volume_db","volume_db"),&AudioPlayer::set_volume_db);
+ ClassDB::bind_method(_MD("get_volume_db"),&AudioPlayer::get_volume_db);
+
+ ClassDB::bind_method(_MD("play","from_pos"),&AudioPlayer::play,DEFVAL(0.0));
+ ClassDB::bind_method(_MD("seek","to_pos"),&AudioPlayer::seek);
+ ClassDB::bind_method(_MD("stop"),&AudioPlayer::stop);
+
+ ClassDB::bind_method(_MD("is_playing"),&AudioPlayer::is_playing);
+ ClassDB::bind_method(_MD("get_pos"),&AudioPlayer::get_pos);
+
+ ClassDB::bind_method(_MD("set_bus","bus"),&AudioPlayer::set_bus);
+ ClassDB::bind_method(_MD("get_bus"),&AudioPlayer::get_bus);
+
+ ClassDB::bind_method(_MD("set_autoplay","enable"),&AudioPlayer::set_autoplay);
+ ClassDB::bind_method(_MD("is_autoplay_enabled"),&AudioPlayer::is_autoplay_enabled);
+
+ ClassDB::bind_method(_MD("set_mix_target","mix_target"),&AudioPlayer::set_mix_target);
+ ClassDB::bind_method(_MD("get_mix_target"),&AudioPlayer::get_mix_target);
+
+ ClassDB::bind_method(_MD("_set_playing","enable"),&AudioPlayer::_set_playing);
+ ClassDB::bind_method(_MD("_is_active"),&AudioPlayer::_is_active);
+
+ ClassDB::bind_method(_MD("_bus_layout_changed"),&AudioPlayer::_bus_layout_changed);
+
+
+ ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"stream",PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"),_SCS("set_stream"),_SCS("get_stream") );
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"volume_db",PROPERTY_HINT_RANGE,"-80,24"),_SCS("set_volume_db"),_SCS("get_volume_db") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"playing",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR),_SCS("_set_playing"),_SCS("_is_active" ));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"autoplay"),_SCS("set_autoplay"),_SCS("is_autoplay_enabled") );
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"mix_target",PROPERTY_HINT_ENUM,"Stereo,Surround,Center"),_SCS("set_mix_target"),_SCS("get_mix_target"));
+ ADD_PROPERTY( PropertyInfo(Variant::STRING,"bus",PROPERTY_HINT_ENUM,""),_SCS("set_bus"),_SCS("get_bus"));
+
+}
+
+AudioPlayer::AudioPlayer() {
+
+ mix_volume_db=0;
+ volume_db=0;
+ autoplay=false;
+ setseek=-1;
+ active=false;
+ mix_target=MIX_TARGET_STEREO;
+
+ AudioServer::get_singleton()->connect("bus_layout_changed",this,"_bus_layout_changed");
+}
+
+
+
+AudioPlayer::~AudioPlayer() {
+
+
+}
+
diff --git a/scene/audio/audio_player.h b/scene/audio/audio_player.h
new file mode 100644
index 0000000000..249e5d0381
--- /dev/null
+++ b/scene/audio/audio_player.h
@@ -0,0 +1,75 @@
+#ifndef AUDIOPLAYER_H
+#define AUDIOPLAYER_H
+
+#include "scene/main/node.h"
+#include "servers/audio/audio_stream.h"
+
+
+class AudioPlayer : public Node {
+
+ GDCLASS( AudioPlayer, Node )
+
+public:
+
+ enum MixTarget {
+ MIX_TARGET_STEREO,
+ MIX_TARGET_SURROUND,
+ MIX_TARGET_CENTER
+ };
+private:
+ Ref<AudioStreamPlayback> stream_playback;
+ Ref<AudioStream> stream;
+ Vector<AudioFrame> mix_buffer;
+
+ volatile float setseek;
+ volatile bool active;
+
+ float mix_volume_db;
+ float volume_db;
+ bool autoplay;
+ StringName bus;
+
+ MixTarget mix_target;
+
+ void _mix_audio();
+ static void _mix_audios(void *self) { reinterpret_cast<AudioPlayer*>(self)->_mix_audio(); }
+
+ void _set_playing(bool p_enable);
+ bool _is_active() const;
+
+ void _bus_layout_changed();
+
+protected:
+
+ void _validate_property(PropertyInfo& property) const;
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_stream(Ref<AudioStream> p_stream);
+ Ref<AudioStream> get_stream() const;
+
+ void set_volume_db(float p_volume);
+ float get_volume_db() const;
+
+ void play(float p_from_pos=0.0);
+ void seek(float p_seconds);
+ void stop();
+ bool is_playing() const;
+ float get_pos();
+
+ void set_bus(const StringName& p_bus);
+ StringName get_bus() const;
+
+ void set_autoplay(bool p_enable);
+ bool is_autoplay_enabled();
+
+ void set_mix_target(MixTarget p_target);
+ MixTarget get_mix_target() const;
+
+ AudioPlayer();
+ ~AudioPlayer();
+};
+
+VARIANT_ENUM_CAST(AudioPlayer::MixTarget)
+#endif // AUDIOPLAYER_H
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index f28595b622..2d1d437668 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -74,17 +74,21 @@ void Button::_notification(int p_what) {
//print_line(get_text()+": "+itos(is_flat())+" hover "+itos(get_draw_mode()));
+ Ref<StyleBox> style = get_stylebox("normal");
+
switch( get_draw_mode() ) {
case DRAW_NORMAL: {
+ style = get_stylebox("normal");
if (!flat)
- get_stylebox("normal" )->draw( ci, Rect2(Point2(0,0), size) );
+ style->draw( ci, Rect2(Point2(0,0), size) );
color=get_color("font_color");
} break;
case DRAW_PRESSED: {
- get_stylebox("pressed" )->draw( ci, Rect2(Point2(0,0), size) );
+ style = get_stylebox("pressed");
+ style->draw( ci, Rect2(Point2(0,0), size) );
if (has_color("font_color_pressed"))
color=get_color("font_color_pressed");
else
@@ -93,13 +97,15 @@ void Button::_notification(int p_what) {
} break;
case DRAW_HOVER: {
- get_stylebox("hover" )->draw( ci, Rect2(Point2(0,0), size) );
+ style = get_stylebox("hover");
+ style->draw( ci, Rect2(Point2(0,0), size) );
color=get_color("font_color_hover");
} break;
case DRAW_DISABLED: {
- get_stylebox("disabled" )->draw( ci, Rect2(Point2(0,0), size) );
+ style = get_stylebox("disabled");
+ style->draw( ci, Rect2(Point2(0,0), size) );
color=get_color("font_color_disabled");
} break;
@@ -111,7 +117,6 @@ void Button::_notification(int p_what) {
style->draw(ci,Rect2(Point2(),size));
}
- Ref<StyleBox> style = get_stylebox("normal" );
Ref<Font> font=get_font("font");
Ref<Texture> _icon;
if (icon.is_null() && has_icon("icon"))
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index d5c1034c9c..5ecafccaca 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -141,8 +141,8 @@ void Range::set_as_ratio(double p_value) {
if (shared->exp_ratio && get_min()>0) {
- double exp_min = Math::log(get_min())/Math::log(2);
- double exp_max = Math::log(get_max())/Math::log(2);
+ double exp_min = Math::log(get_min())/Math::log((double)2);
+ double exp_max = Math::log(get_max())/Math::log((double)2);
v = Math::pow(2,exp_min+(exp_max-exp_min)*p_value);
} else {
@@ -160,9 +160,9 @@ double Range::get_as_ratio() const {
if (shared->exp_ratio && get_min()>0) {
- double exp_min = Math::log(get_min())/Math::log(2);
- double exp_max = Math::log(get_max())/Math::log(2);
- double v = Math::log(get_value())/Math::log(2);
+ double exp_min = Math::log(get_min())/Math::log((double)2);
+ double exp_max = Math::log(get_max())/Math::log((double)2);
+ double v = Math::log(get_value())/Math::log((double)2);
return (v - exp_min) / (exp_max - exp_min);
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index ec6be0d19d..8920f8f056 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -162,7 +162,7 @@ void SpinBox::_gui_input(const InputEvent& p_event) {
if (drag.enabled) {
float diff_y = drag.mouse_pos.y - cpos.y;
- diff_y=Math::pow(ABS(diff_y),1.8)*SGN(diff_y);
+ diff_y=Math::pow(ABS(diff_y),1.8f)*SGN(diff_y);
diff_y*=0.1;
drag.mouse_pos=cpos;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index d1a8c458ba..6036b3f9df 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -482,14 +482,6 @@ void TextEdit::_notification(int p_what) {
Color color = cache.font_color;
int in_region=-1;
- if (line_length_guideline) {
- int x=xmargin_beg+cache.font->get_char_size('0').width*line_length_guideline_col-cursor.x_ofs;
- if (x>xmargin_beg && x<xmargin_end) {
- Color guideline_color(color.r,color.g,color.b,color.a*0.25f);
- VisualServer::get_singleton()->canvas_item_add_line(ci,Point2(x,0),Point2(x,cache.size.height),guideline_color);
- }
- }
-
if (syntax_coloring) {
if (cache.background_color.a>0.01) {
@@ -1080,6 +1072,14 @@ void TextEdit::_notification(int p_what) {
}
}
+ if (line_length_guideline) {
+ int x=xmargin_beg+cache.font->get_char_size('0').width*line_length_guideline_col-cursor.x_ofs;
+ if (x>xmargin_beg && x<xmargin_end) {
+ VisualServer::get_singleton()->canvas_item_add_line(ci,Point2(x,0),Point2(x,cache.size.height),cache.line_length_guideline_color);
+ }
+ }
+
+
bool completion_below = false;
if (completion_active) {
// code completion box
@@ -3484,6 +3484,7 @@ void TextEdit::_update_caches() {
cache.selection_color=get_color("selection_color");
cache.mark_color=get_color("mark_color");
cache.current_line_color=get_color("current_line_color");
+ cache.line_length_guideline_color=get_color("line_length_guideline_color");
cache.breakpoint_color=get_color("breakpoint_color");
cache.brace_mismatch_color=get_color("brace_mismatch_color");
cache.word_highlighted_color=get_color("word_highlighted_color");
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 6113fd72c2..437e22ca40 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -91,6 +91,7 @@ class TextEdit : public Control {
Color mark_color;
Color breakpoint_color;
Color current_line_color;
+ Color line_length_guideline_color;
Color brace_mismatch_color;
Color word_highlighted_color;
Color search_result_color;
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp
index f6a33b5643..7d8373976b 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress.cpp
@@ -46,7 +46,9 @@ void TextureProgress::set_over_texture(const Ref<Texture>& p_texture) {
over=p_texture;
update();
- minimum_size_changed();
+ if (under.is_null()) {
+ minimum_size_changed();
+ }
}
Ref<Texture> TextureProgress::get_over_texture() const{
@@ -302,4 +304,5 @@ TextureProgress::TextureProgress()
rad_init_angle=0;
rad_center_off=Point2();
rad_max_degrees=360;
+ set_mouse_filter(MOUSE_FILTER_PASS);
}
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index cbb077ef5d..6a4b59c5ec 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -160,7 +160,7 @@ TextureRect::TextureRect() {
expand=false;
- set_mouse_filter(MOUSE_FILTER_IGNORE);
+ set_mouse_filter(MOUSE_FILTER_PASS);
stretch_mode=STRETCH_SCALE_ON_EXPAND;
}
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 2cfebb7c1e..1a7392f27e 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -943,7 +943,7 @@ void Tree::draw_item_rect(const TreeItem::Cell& p_cell,const Rect2i& p_rect,cons
bmsize.width=p_cell.icon_max_w;
}
- p_cell.draw_icon(ci,rect.pos + Size2i(0,Math::floor((rect.size.y-bmsize.y)/2)),bmsize);
+ p_cell.draw_icon(ci,rect.pos + Size2i(0,Math::floor((real_t)(rect.size.y-bmsize.y)/2)),bmsize);
rect.pos.x+=bmsize.x+cache.hseparation;
rect.size.x-=bmsize.x+cache.hseparation;
@@ -1008,7 +1008,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
/* Draw label, if height fits */
- bool skip=(p_item==root && hide_root);
+ bool skip=(p_item==root && hide_root);
if (!skip && (p_pos.y+label_h-cache.offset.y)>0) {
@@ -1173,7 +1173,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
Ref<Texture> checked = cache.checked;
Ref<Texture> unchecked = cache.unchecked;
Point2i check_ofs=item_rect.pos;
- check_ofs.y+=Math::floor((item_rect.size.y-checked->get_height())/2);
+ check_ofs.y+=Math::floor((real_t)(item_rect.size.y-checked->get_height())/2);
if (p_item->cells[i].checked) {
@@ -1711,8 +1711,15 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
case TreeItem::CELL_MODE_CHECK: {
bring_up_editor=false; //checkboxes are not edited with editor
- p_item->set_checked(col, !c.checked);
- item_edited(col, p_item);
+ if (force_edit_checkbox_only_on_checkbox) {
+ if (x < cache.checked->get_width()) {
+ p_item->set_checked(col, !c.checked);
+ item_edited(col, p_item);
+ }
+ } else {
+ p_item->set_checked(col, !c.checked);
+ item_edited(col, p_item);
+ }
click_handled = true;
//p_item->edited_signal.call(col);
@@ -2321,7 +2328,7 @@ void Tree::_gui_input(InputEvent p_event) {
TreeItem::Cell &c=popup_edited_item->cells[popup_edited_item_col];
float diff_y = -b.relative_y;
- diff_y=Math::pow(ABS(diff_y),1.8)*SGN(diff_y);
+ diff_y=Math::pow(ABS(diff_y),1.8f)*SGN(diff_y);
diff_y*=0.1;
range_drag_base=CLAMP(range_drag_base + c.step * diff_y, c.min, c.max);
popup_edited_item->set_range(popup_edited_item_col,range_drag_base);
@@ -3555,6 +3562,16 @@ bool Tree::get_single_select_cell_editing_only_when_already_selected() const {
return force_select_on_already_selected;
}
+void Tree::set_edit_checkbox_cell_only_when_checkbox_is_pressed(bool p_enable) {
+
+ force_edit_checkbox_only_on_checkbox=p_enable;
+}
+
+bool Tree::get_edit_checkbox_cell_only_when_checkbox_is_pressed() const {
+
+ return force_edit_checkbox_only_on_checkbox;
+}
+
void Tree::set_allow_rmb_select(bool p_allow) {
@@ -3733,6 +3750,7 @@ Tree::Tree() {
force_select_on_already_selected=false;
allow_rmb_select=false;
+ force_edit_checkbox_only_on_checkbox=false;
set_clip_contents(true);
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index d715ff4772..351cc4cb50 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -452,6 +452,7 @@ friend class TreeItem;
bool scrolling;
bool force_select_on_already_selected;
+ bool force_edit_checkbox_only_on_checkbox;
bool hide_folding;
@@ -531,6 +532,10 @@ public:
void set_single_select_cell_editing_only_when_already_selected(bool p_enable);
bool get_single_select_cell_editing_only_when_already_selected() const;
+ void set_edit_checkbox_cell_only_when_checkbox_is_pressed(bool p_enable);
+ bool get_edit_checkbox_cell_only_when_checkbox_is_pressed() const;
+
+
void set_allow_rmb_select(bool p_allow);
bool get_allow_rmb_select() const;
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index 907b5a771f..46c0eeca65 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -28,6 +28,7 @@
/*************************************************************************/
#include "video_player.h"
#include "os/os.h"
+#include "servers/audio_server.h"
/*
int VideoPlayer::InternalStream::get_channel_count() const {
diff --git a/scene/io/resource_format_image.cpp b/scene/io/resource_format_image.cpp
index 2d098d01f5..4d15ab86fd 100644
--- a/scene/io/resource_format_image.cpp
+++ b/scene/io/resource_format_image.cpp
@@ -27,6 +27,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "resource_format_image.h"
+
+#if 0
#include "scene/resources/texture.h"
#include "io/image_loader.h"
#include "globals.h"
@@ -260,3 +262,4 @@ ResourceFormatLoaderImage::ResourceFormatLoaderImage() {
GLOBAL_DEF("rendering/image_loader/repeat",false);
}
+#endif
diff --git a/scene/io/resource_format_image.h b/scene/io/resource_format_image.h
index 6e4ead2a0b..0638e97787 100644
--- a/scene/io/resource_format_image.h
+++ b/scene/io/resource_format_image.h
@@ -29,6 +29,8 @@
#ifndef RESOURCE_FORMAT_IMAGE_H
#define RESOURCE_FORMAT_IMAGE_H
+#if 0
+
#include "io/resource_loader.h"
#include "io/resource_saver.h"
/**
@@ -49,3 +51,4 @@ public:
};
#endif
+#endif
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 14acf9583d..989c048682 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1796,6 +1796,42 @@ Control* Viewport::_gui_find_control_at_pos(CanvasItem* p_node,const Point2& p_g
return NULL;
}
+bool Viewport::_gui_drop(Control *p_at_control,Point2 p_at_pos,bool p_just_check) {
+
+
+ { //attempt grab, try parent controls too
+ CanvasItem *ci=p_at_control;
+ while(ci) {
+
+ Control *control = ci->cast_to<Control>();
+ if (control) {
+
+
+ if (control->can_drop_data(p_at_pos,gui.drag_data)) {
+ if (!p_just_check) {
+ control->drop_data(p_at_pos,gui.drag_data);
+ }
+
+ return true;
+ }
+
+ if (control->data.mouse_filter==Control::MOUSE_FILTER_STOP)
+ break;
+ }
+
+ p_at_pos = ci->get_transform().xform(p_at_pos);
+
+ if (ci->is_set_as_toplevel())
+ break;
+
+ ci=ci->get_parent_item();
+ }
+ }
+
+ return false;
+}
+
+
void Viewport::_gui_input_event(InputEvent p_event) {
@@ -1901,9 +1937,28 @@ void Viewport::_gui_input_event(InputEvent p_event) {
}*/
#endif
- if (gui.mouse_focus->get_focus_mode()!=Control::FOCUS_NONE && gui.mouse_focus!=gui.key_focus && p_event.mouse_button.button_index==BUTTON_LEFT) {
- // also get keyboard focus
- gui.mouse_focus->grab_focus();
+ if (p_event.mouse_button.button_index==BUTTON_LEFT) { //assign focus
+ CanvasItem *ci=gui.mouse_focus;
+ while(ci) {
+
+ Control *control = ci->cast_to<Control>();
+ if (control) {
+ if (control->get_focus_mode()!=Control::FOCUS_NONE) {
+ if (control!=gui.key_focus) {
+ control->grab_focus();
+ }
+ break;
+ }
+
+ if (control->data.mouse_filter==Control::MOUSE_FILTER_STOP)
+ break;
+ }
+
+ if (ci->is_set_as_toplevel())
+ break;
+
+ ci=ci->get_parent_item();
+ }
}
@@ -1918,8 +1973,8 @@ void Viewport::_gui_input_event(InputEvent p_event) {
if (gui.drag_data.get_type()!=Variant::NIL && p_event.mouse_button.button_index==BUTTON_LEFT) {
//alternate drop use (when using force_drag(), as proposed by #5342
- if (gui.mouse_focus && gui.mouse_focus->can_drop_data(pos,gui.drag_data)) {
- gui.mouse_focus->drop_data(pos,gui.drag_data);
+ if (gui.mouse_focus) {
+ _gui_drop(gui.mouse_focus,pos,false);
}
gui.drag_data=Variant();
@@ -1946,9 +2001,9 @@ void Viewport::_gui_input_event(InputEvent p_event) {
if (gui.mouse_over) {
Size2 pos = mpos;
pos = gui.focus_inv_xform.xform(pos);
- if (gui.mouse_over->can_drop_data(pos,gui.drag_data)) {
- gui.mouse_over->drop_data(pos,gui.drag_data);
- }
+
+ _gui_drop(gui.mouse_over,pos,false);
+
}
if (gui.drag_preview && p_event.mouse_button.button_index==BUTTON_LEFT) {
@@ -2009,11 +2064,33 @@ void Viewport::_gui_input_event(InputEvent p_event) {
gui.drag_accum+=Point2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y);
float len = gui.drag_accum.length();
if (len>10) {
- gui.drag_data=gui.mouse_focus->get_drag_data(gui.focus_inv_xform.xform(mpos)-gui.drag_accum);
- if (gui.drag_data.get_type()!=Variant::NIL) {
- gui.mouse_focus=NULL;
+ { //attempt grab, try parent controls too
+ CanvasItem *ci=gui.mouse_focus;
+ while(ci) {
+
+ Control *control = ci->cast_to<Control>();
+ if (control) {
+
+ gui.drag_data=control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos)-gui.drag_accum);
+ if (gui.drag_data.get_type()!=Variant::NIL) {
+
+ gui.mouse_focus=NULL;
+ }
+
+ if (control->data.mouse_filter==Control::MOUSE_FILTER_STOP)
+ break;
+ }
+
+ if (ci->is_set_as_toplevel())
+ break;
+
+ ci=ci->get_parent_item();
+ }
}
+
+
+
gui.drag_attempted=true;
if (gui.drag_data.get_type()!=Variant::NIL) {
@@ -2140,7 +2217,7 @@ void Viewport::_gui_input_event(InputEvent p_event) {
if (gui.drag_data.get_type()!=Variant::NIL && p_event.mouse_motion.button_mask&BUTTON_MASK_LEFT) {
- bool can_drop = over->can_drop_data(pos,gui.drag_data);
+ bool can_drop = _gui_drop(over,pos,true);
if (!can_drop) {
OS::get_singleton()->set_cursor_shape( OS::CURSOR_FORBIDDEN );
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 2831d177c9..59e34d5c62 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -306,6 +306,8 @@ friend class Control;
Vector2 _get_window_offset() const;
+ bool _gui_drop(Control *p_at_control,Point2 p_at_pos,bool p_just_check);
+
friend class Listener;
void _listener_transform_changed_notify();
void _listener_set(Listener* p_listener);
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 1932f9cbf6..0ad140f7c3 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -139,7 +139,7 @@
#include "scene/main/timer.h"
-//#include "scene/audio/stream_player.h"
+#include "scene/audio/audio_player.h"
//#include "scene/audio/event_player.h"
//#include "scene/audio/sound_room_params.h"
#include "scene/resources/sphere_shape.h"
@@ -177,7 +177,7 @@
#include "scene/resources/world_2d.h"
//#include "scene/resources/sample_library.h"
-#include "scene/resources/audio_stream.h"
+//#include "scene/resources/audio_stream.h"
#include "scene/resources/gibberish_stream.h"
#include "scene/resources/bit_mask.h"
#include "scene/resources/color_ramp.h"
@@ -230,7 +230,6 @@
#include "scene/resources/scene_format_text.h"
-static ResourceFormatLoaderImage *resource_loader_image=NULL;
//static ResourceFormatLoaderWAV *resource_loader_wav=NULL;
@@ -245,6 +244,8 @@ static ResourceFormatLoaderText *resource_loader_text=NULL;
static ResourceFormatLoaderDynamicFont *resource_loader_dynamic_font=NULL;
+static ResourceFormatLoaderStreamTexture *resource_loader_stream_texture=NULL;
+
//static SceneStringNames *string_names;
void register_scene_types() {
@@ -255,14 +256,14 @@ void register_scene_types() {
Node::init_node_hrcr();
- resource_loader_image = memnew( ResourceFormatLoaderImage );
- ResourceLoader::add_resource_format_loader( resource_loader_image );
-
//resource_loader_wav = memnew( ResourceFormatLoaderWAV );
//ResourceLoader::add_resource_format_loader( resource_loader_wav );
resource_loader_dynamic_font = memnew( ResourceFormatLoaderDynamicFont );
ResourceLoader::add_resource_format_loader( resource_loader_dynamic_font );
+ resource_loader_stream_texture = memnew( ResourceFormatLoaderStreamTexture);
+ ResourceLoader::add_resource_format_loader( resource_loader_stream_texture );
+
#ifdef TOOLS_ENABLED
//scene first!
@@ -570,6 +571,7 @@ void register_scene_types() {
ClassDB::register_virtual_class<Texture>();
ClassDB::register_virtual_class<SkyBox>();
ClassDB::register_class<ImageSkyBox>();
+ ClassDB::register_class<StreamTexture>();
ClassDB::register_class<ImageTexture>();
ClassDB::register_class<AtlasTexture>();
ClassDB::register_class<LargeTexture>();
@@ -592,10 +594,7 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
- ClassDB::register_virtual_class<AudioStream>();
- ClassDB::register_virtual_class<AudioStreamPlayback>();
-//TODO: Adapt to the new AudioStream API or drop (GH-3307)
- //ClassDB::register_type<AudioStreamGibberish>();
+ ClassDB::register_class<AudioPlayer>();
ClassDB::register_virtual_class<VideoStream>();
OS::get_singleton()->yield(); //may take time to init
@@ -646,9 +645,9 @@ void unregister_scene_types() {
clear_default_theme();
- memdelete( resource_loader_image );
// memdelete( resource_loader_wav );
memdelete( resource_loader_dynamic_font );
+ memdelete( resource_loader_stream_texture );
#ifdef TOOLS_ENABLED
diff --git a/scene/resources/audio_stream_resampled.h b/scene/resources/audio_stream_resampled.h
index 761643b027..7ceb6cef84 100644
--- a/scene/resources/audio_stream_resampled.h
+++ b/scene/resources/audio_stream_resampled.h
@@ -29,7 +29,7 @@
#ifndef AUDIO_STREAM_RESAMPLED_H
#define AUDIO_STREAM_RESAMPLED_H
-#include "scene/resources/audio_stream.h"
+//#include "scene/resources/audio_stream.h"
#if 0
diff --git a/scene/resources/capsule_shape.cpp b/scene/resources/capsule_shape.cpp
index db83a20f38..23538c1957 100644
--- a/scene/resources/capsule_shape.cpp
+++ b/scene/resources/capsule_shape.cpp
@@ -42,8 +42,8 @@ Vector<Vector3> CapsuleShape::_gen_debug_mesh_lines() {
Vector3 d(0,0,height*0.5);
for(int i=0;i<360;i++) {
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+1);
+ float ra=Math::deg2rad((float)i);
+ float rb=Math::deg2rad((float)i+1);
Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*radius;
Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*radius;
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index e201cb16ac..3392c68e75 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -498,7 +498,7 @@ Vector2 Curve2D::interpolatef(real_t p_findex) const {
else if (p_findex>=points.size())
p_findex=points.size();
- return interpolate((int)p_findex,Math::fmod(p_findex,1.0));
+ return interpolate((int)p_findex,Math::fmod(p_findex,(real_t)1.0));
}
@@ -653,7 +653,7 @@ Vector2 Curve2D::interpolate_baked(float p_offset,bool p_cubic) const{
return r[bpc-1];
int idx = Math::floor((double)p_offset/(double)bake_interval);
- float frac = Math::fmod(p_offset,bake_interval);
+ float frac = Math::fmod(p_offset,(float)bake_interval);
if (idx>=bpc-1) {
return r[bpc-1];
@@ -974,7 +974,7 @@ Vector3 Curve3D::interpolatef(real_t p_findex) const {
else if (p_findex>=points.size())
p_findex=points.size();
- return interpolate((int)p_findex,Math::fmod(p_findex,1.0));
+ return interpolate((int)p_findex,Math::fmod(p_findex,(real_t)1.0));
}
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index 46fd770a27..5b5868ba14 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -45,7 +45,7 @@ static const unsigned char button_normal_png[]={
static const unsigned char button_pressed_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x3,0x0,0x0,0x0,0x28,0x2d,0xf,0x53,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x93,0x50,0x4c,0x54,0x45,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x31,0x2f,0x37,0x46,0x43,0x4f,0x47,0x44,0x50,0x55,0x52,0x5f,0x55,0x52,0x60,0x3d,0x3a,0x45,0x56,0x52,0x60,0x56,0x52,0x60,0x43,0x40,0x4c,0x42,0x40,0x4b,0x3a,0x38,0x41,0x36,0x34,0x3d,0x44,0x42,0x4e,0x36,0x34,0x3e,0x46,0x42,0x4f,0x38,0x35,0x3f,0x47,0x45,0x50,0x39,0x37,0x40,0x49,0x46,0x53,0x3a,0x38,0x42,0x4a,0x47,0x54,0x3b,0x39,0x43,0x4b,0x49,0x55,0x3c,0x3a,0x44,0x4e,0x4a,0x58,0x3e,0x3b,0x46,0x50,0x4d,0x5a,0x3f,0x3d,0x48,0x3f,0x3d,0x47,0x45,0x42,0x4d,0x41,0x3e,0x49,0x40,0x3e,0x48,0x52,0x4e,0x5c,0x51,0x4e,0x5b,0xff,0xff,0xff,0x32,0xd2,0xb4,0xc,0x0,0x0,0x0,0x16,0x74,0x52,0x4e,0x53,0x4,0xa,0x11,0x19,0x1f,0x22,0x24,0x15,0x25,0x34,0x3f,0x46,0x47,0x48,0x77,0xef,0xef,0xef,0xef,0x77,0xef,0xed,0x6b,0x28,0x52,0x7a,0x0,0x0,0x0,0x1,0x62,0x4b,0x47,0x44,0x30,0xae,0xdc,0x2d,0xe4,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x95,0x49,0x44,0x41,0x54,0x18,0xd3,0x65,0xcf,0xdb,0x12,0x42,0x50,0x14,0x6,0xe0,0xb5,0x8f,0xf6,0x11,0xa5,0x24,0x9,0x49,0x22,0xd2,0xfb,0xbf,0x5d,0x9b,0x31,0xfb,0xa2,0xbe,0xcb,0x7f,0x66,0x1d,0x7e,0x0,0x84,0x9,0x65,0xdc,0x61,0x94,0x60,0x4,0x80,0x2,0x21,0x95,0x36,0xd6,0x1a,0xad,0xa4,0x8,0x10,0x60,0x11,0x46,0xe9,0x69,0x95,0x46,0xa1,0xc0,0x40,0x64,0x9c,0x9d,0x37,0x59,0x2c,0x9,0x50,0x95,0x5f,0xbc,0x5c,0x51,0x60,0xba,0xb8,0x7a,0x85,0x66,0xc0,0x4d,0x59,0x79,0xa5,0xe1,0xc0,0x6d,0x7d,0xf3,0x6a,0xbb,0x4,0xcd,0xdd,0x6b,0x96,0xc0,0xb4,0xf,0xaf,0x75,0x23,0x4c,0x77,0x4f,0xaf,0x73,0x4b,0xa9,0xea,0x87,0xd7,0x66,0xe8,0xdd,0x59,0x22,0x77,0xe3,0xf4,0x5e,0x4d,0xe3,0xde,0x3d,0x86,0x45,0x72,0x98,0x3f,0xab,0xf9,0x98,0xb8,0xd7,0xff,0xca,0xfd,0xd6,0xff,0x2,0x86,0xd,0x15,0x51,0x39,0x7d,0xa8,0x8e,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xc9,0xad,0xc8,0x52,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xb8,0xf0,0x70,0xee,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x7,0x1c,0xc,0x14,0x2b,0xf9,0x77,0x52,0x64,0x0,0x0,0x1,0x92,0x49,0x44,0x41,0x54,0x38,0xcb,0x8d,0x93,0x4d,0x4e,0x1b,0x41,0x10,0x85,0xbf,0xea,0xaa,0x1e,0x20,0x83,0xf9,0x9,0x36,0xb2,0x85,0x72,0x84,0x8,0x65,0x11,0xe5,0xc,0x9c,0x80,0x73,0x10,0xee,0xc1,0x41,0x38,0x1,0xab,0xec,0xa3,0x2c,0x2,0x8a,0xe0,0x2,0x51,0xc2,0x48,0x46,0x42,0x64,0xc6,0x91,0x21,0xf4,0x74,0x16,0x2e,0xb0,0x71,0x2,0xf2,0x93,0x9e,0xba,0x16,0xdd,0xaf,0x5e,0xa9,0x5f,0x9,0x60,0x40,0x1,0x2c,0x1,0xcb,0x5e,0x2b,0x10,0x78,0x8a,0x16,0x48,0xc0,0x1d,0x30,0x6,0x6e,0x81,0x3b,0xf3,0x87,0x25,0xb0,0x9,0xac,0x7b,0xbd,0xc,0x88,0x13,0x20,0x3b,0xc7,0xc0,0x8,0xb8,0x1,0xae,0x81,0x91,0xf9,0xe5,0xad,0x77,0xbb,0x1f,0xf6,0x7b,0xdd,0xfe,0x41,0x4a,0x69,0x2d,0x93,0xf9,0x1f,0x4,0x41,0x55,0x7f,0xd,0xaf,0xaa,0xa3,0xaf,0x67,0x9f,0x8f,0x81,0x64,0xde,0xb1,0xbb,0xdd,0x1b,0x7c,0xac,0x9b,0x9b,0xce,0xd9,0xb7,0x2f,0xfc,0xf3,0x5e,0xa6,0xe5,0xee,0xdb,0xf7,0x6b,0xdb,0xbd,0xc1,0x21,0xf0,0x9,0x18,0x5,0x60,0x5,0xd8,0x48,0x6d,0xdb,0x39,0xbf,0x38,0xc5,0x34,0x62,0x36,0x47,0x9d,0xf2,0xfc,0xe2,0x94,0xd4,0xb6,0x1d,0x60,0x3,0x58,0x31,0x20,0x2,0x65,0x40,0x88,0x31,0x92,0xbd,0xbb,0x8,0xe4,0x3c,0x39,0x67,0x91,0x33,0x84,0x89,0xa5,0x12,0x88,0xf,0x3f,0x10,0x45,0x5,0xb3,0xc8,0x73,0x10,0x11,0xb2,0xab,0x8b,0xa,0xde,0xb8,0x30,0x9f,0xb0,0x8,0xa2,0xc4,0x58,0xb0,0x8,0x82,0x28,0xde,0x58,0xcc,0xff,0x5c,0x45,0x64,0x61,0x1,0x99,0xcc,0xa5,0x80,0x4e,0x5,0xc2,0xcb,0x2,0xe2,0x41,0x10,0x40,0xc2,0x53,0x81,0xc,0xa8,0x8a,0x52,0x2c,0xe8,0x40,0x27,0x23,0x28,0x90,0xcd,0xe3,0x79,0x1b,0x34,0x50,0x14,0x4b,0xf0,0x4c,0x88,0x66,0xbd,0x4,0xd,0x78,0x94,0x93,0x79,0x3c,0x9b,0x18,0x63,0x7a,0xbd,0xb9,0xa5,0xcd,0xa8,0x7e,0xb4,0x3a,0x2f,0x15,0x10,0xca,0x72,0x95,0x18,0x8b,0x4,0x34,0xc0,0xd8,0x80,0x1a,0x18,0x56,0xd5,0xcf,0x93,0x41,0x7f,0x67,0xaf,0xb3,0xba,0x1e,0x5e,0x8a,0xb2,0x99,0xb5,0x97,0xd5,0x8f,0x13,0x60,0x8,0xd4,0x2,0x74,0x9d,0x6f,0x80,0xbe,0x2f,0x55,0xe9,0x26,0xc2,0xcc,0x26,0x66,0x5f,0xa4,0x6b,0xa0,0x2,0xbe,0x3,0x57,0xe6,0x56,0x1e,0x66,0x1a,0x2,0xaf,0x3c,0x24,0x36,0x67,0xe0,0x1e,0xf8,0x3,0xfc,0xf6,0x6d,0xac,0x81,0xe6,0x2f,0x7c,0x22,0x6d,0x74,0x25,0xb,0xb3,0xa2,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -540,12 +540,12 @@ static const unsigned char vslider_bg_png[]={
static const unsigned char vslider_grabber_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0xf8,0x49,0x44,0x41,0x54,0x28,0xcf,0xbd,0x90,0xaf,0x4b,0x43,0x51,0x18,0x86,0x9f,0xf3,0x43,0xcf,0x76,0xae,0xde,0xb9,0xc9,0x1c,0x82,0x86,0xa1,0x16,0x15,0x87,0xc3,0x20,0x68,0x30,0x58,0xb4,0x5a,0x6c,0x62,0x37,0x88,0xff,0x81,0xc5,0xe4,0x5f,0x70,0x8b,0x75,0x45,0xb3,0xc1,0xa6,0x41,0x4,0x19,0xc,0x19,0x18,0x4,0x8d,0xb,0x82,0xdb,0xd8,0x81,0x29,0xf7,0x1e,0x8b,0x6e,0x43,0x30,0xea,0x93,0x5e,0xf8,0x5e,0x5e,0x78,0x3e,0xf8,0x73,0xc4,0x40,0x92,0x18,0x46,0x9,0x18,0xc6,0xd3,0xa1,0x89,0x23,0xee,0x17,0x86,0xc8,0x14,0xa7,0x97,0x57,0x4a,0xdb,0xe1,0xa2,0xc9,0x4b,0xdf,0xac,0x3d,0x9d,0x47,0x15,0x5e,0x89,0x5,0x20,0xb0,0x23,0xc5,0x83,0xc3,0xc2,0xa6,0x99,0xea,0xaa,0xf,0x62,0xc0,0xa0,0x1b,0xf,0x27,0xd1,0x19,0x6d,0x8d,0x66,0x6c,0x75,0x6d,0xf7,0x54,0xcd,0x3a,0x1c,0xc9,0xd7,0x60,0x8c,0x2d,0xcc,0xec,0x70,0x41,0x5b,0x63,0x8e,0xf6,0xe6,0x8f,0xdf,0x82,0x4e,0xef,0x8,0xe0,0xe9,0x92,0x5d,0x22,0x0,0x89,0x48,0x59,0xd4,0xef,0x16,0x8a,0xe4,0xba,0xde,0xaa,0x2e,0x94,0x53,0xb9,0x4,0x8f,0xef,0x29,0xa5,0x71,0x77,0x57,0x15,0x5a,0x8a,0x4,0xf7,0xfc,0x72,0x73,0x39,0xc7,0xf8,0x44,0x90,0x11,0x2,0x24,0x92,0x34,0xba,0xf1,0x18,0xdd,0xdf,0xf2,0xde,0xd7,0xc,0x75,0x7e,0x6b,0x7d,0x63,0x5f,0x4c,0x9a,0x9c,0xfa,0xa1,0xf9,0x8d,0xc4,0x12,0x62,0xd1,0x83,0x8f,0xfa,0x7,0x3e,0x1,0x87,0xd0,0x4a,0x12,0xcf,0xee,0xfb,0xd8,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xc9,0xad,0xc8,0x52,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xb8,0xf0,0x70,0xee,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xb7,0xff,0x88,0x5,0x1d,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe1,0x1,0x12,0x1,0x36,0x8,0x50,0xb9,0xa7,0x53,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xf6,0x49,0x44,0x41,0x54,0x28,0xcf,0xbd,0x90,0xb1,0x4a,0x42,0x51,0x0,0x86,0xbf,0x73,0x8e,0x71,0xe5,0x9a,0x5c,0x41,0xd0,0x66,0x6b,0x33,0x1c,0x7c,0x80,0xa0,0xa5,0x17,0x8,0xa2,0x2d,0x84,0xf0,0x1,0xa2,0x25,0xf1,0x9,0x9a,0x1c,0xda,0x5b,0xb2,0x47,0xa8,0xa5,0xc1,0xa0,0x51,0x88,0xa2,0x29,0xa,0xc1,0x84,0x8,0x43,0xf4,0x96,0x17,0xcf,0xed,0xde,0x73,0x9c,0xcc,0x5c,0xda,0xea,0x9f,0x3f,0xfe,0x9f,0xef,0x87,0x3f,0x8f,0x0,0x40,0xe1,0xe2,0x91,0x42,0x10,0x32,0xe6,0x3,0x8d,0xc1,0xce,0x1,0x45,0xb6,0xba,0xbb,0xba,0xed,0x95,0x8c,0xd0,0x7d,0xff,0xe1,0xee,0xe2,0xb6,0xdd,0x79,0x61,0xc4,0xd7,0xc,0x48,0x57,0x2b,0xeb,0xb5,0x28,0xaf,0x1,0xc5,0x12,0x4e,0xac,0x7b,0x6f,0x57,0x27,0x8d,0xcf,0xe,0x1,0x56,0x1,0xb9,0x9d,0xba,0x28,0x6,0x18,0xc,0x31,0x21,0x5a,0xda,0x4c,0xb6,0xbc,0xb9,0x35,0x7c,0xea,0xbd,0x13,0x4a,0x20,0xe5,0x95,0xf4,0x6c,0x12,0x30,0x84,0xf8,0x44,0x6b,0xfb,0xcd,0x83,0x3d,0x1c,0xf9,0x8b,0x80,0x4a,0xba,0x88,0x4,0x30,0x1e,0xdd,0x3b,0x1b,0xf1,0x77,0x87,0x24,0x81,0x8b,0x79,0x3e,0x3b,0x6a,0x5d,0x33,0x51,0x80,0x2d,0x38,0x2b,0x65,0xb5,0x6c,0x91,0x28,0x92,0xa4,0xad,0xec,0x76,0xcf,0x8f,0xf,0x1f,0xdb,0xc,0x31,0xb,0x9a,0xb1,0xd0,0x3,0xfb,0xda,0x3a,0xbd,0xbc,0x89,0xfa,0xf8,0x73,0xcd,0x9f,0x47,0x45,0x4,0xf8,0x4,0x18,0xfe,0x2f,0x53,0x8,0x62,0x5c,0xcf,0x1f,0x5f,0xcb,0x2c,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char vslider_grabber_hl_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x3,0x0,0x0,0x0,0x28,0x2d,0xf,0x53,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0xc6,0x50,0x4c,0x54,0x45,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x17,0x2a,0x29,0x3a,0x69,0x69,0x5b,0xa6,0xa5,0x61,0xb3,0xbc,0x63,0xb7,0xc8,0x65,0xbb,0xca,0x60,0xaf,0xb1,0x48,0x83,0x83,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0xf,0xf,0x55,0x9b,0x9a,0x60,0xb2,0xbd,0x5e,0xb1,0xcd,0x61,0xb3,0xc2,0x0,0x0,0x0,0x27,0x48,0x47,0x62,0xb4,0xbd,0x51,0x93,0x92,0x68,0xc0,0xcf,0x0,0x0,0x0,0x56,0x9d,0x9c,0x68,0xc1,0xcf,0x2d,0x52,0x52,0x63,0xb7,0xbf,0x52,0x96,0x95,0x62,0xb3,0xbf,0x5e,0xb0,0xcd,0x0,0x0,0x0,0x3,0x5,0x5,0x36,0x63,0x63,0x63,0xb4,0xb6,0x60,0xb1,0xbc,0x63,0xb7,0xc7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x55,0xa3,0xc8,0x4f,0x98,0xc4,0x4b,0x93,0xc2,0x4c,0x94,0xc2,0x54,0xa2,0xc8,0x5a,0xab,0xcb,0x4e,0x97,0xc4,0x49,0x8f,0xc0,0x47,0x8c,0xbf,0x48,0x8e,0xc0,0x52,0x9e,0xc6,0x51,0x9d,0xc6,0x5a,0xac,0xcc,0x53,0x9f,0xc7,0x4d,0x96,0xc3,0x4b,0x92,0xc2,0xff,0xff,0xff,0xec,0x37,0x7,0xf6,0x0,0x0,0x0,0x31,0x74,0x52,0x4e,0x53,0x0,0x1,0x3,0xa,0x17,0x22,0x28,0x27,0x1c,0xd,0x5,0x14,0x31,0x65,0xaf,0xdb,0xf0,0xef,0xc1,0x6e,0x16,0xb,0x2c,0x9c,0xe0,0xfc,0xe8,0x4,0x4f,0xdb,0x73,0xf4,0xc,0x7d,0xf7,0x55,0xdc,0x95,0xe0,0xfe,0x13,0x28,0x64,0xc5,0xde,0xf0,0x2,0x1a,0x24,0x77,0x58,0x79,0x88,0x0,0x0,0x0,0x1,0x62,0x4b,0x47,0x44,0x41,0x89,0xde,0x6c,0x4e,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x7d,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0x20,0xf,0x30,0x32,0x31,0xb3,0xb0,0xb2,0xb1,0x73,0x70,0x32,0x41,0xf8,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,0x2,0x82,0x42,0xc2,0x22,0x20,0x11,0x46,0x51,0x31,0x71,0x9,0x49,0x43,0x23,0x63,0x13,0x53,0x29,0x61,0x4e,0x6,0x6,0x69,0x6e,0x19,0x59,0x33,0x73,0xb,0x4b,0x20,0xb0,0x32,0x15,0xe2,0x60,0x60,0x10,0x95,0x93,0xb7,0x6,0x73,0x81,0xc0,0x44,0x90,0x9d,0x81,0x41,0x41,0x51,0xc9,0x6,0x45,0x40,0x5a,0x44,0x59,0xc5,0x16,0x59,0xb,0x3,0xa3,0x82,0x98,0xaa,0x9a,0xba,0x9d,0xbd,0x3,0xd4,0x50,0x90,0xb5,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x30,0x6b,0x41,0x40,0x4f,0x41,0xdf,0x0,0xc9,0x61,0x24,0x2,0x0,0x9d,0x96,0x10,0xf9,0x6,0xb2,0x58,0x28,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xc9,0xad,0xc8,0x52,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xb8,0xf0,0x70,0xee,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x3,0x0,0x0,0x0,0x28,0x2d,0xf,0x53,0x0,0x0,0x0,0xc3,0x50,0x4c,0x54,0x45,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x17,0x2a,0x29,0x3a,0x69,0x69,0x5b,0xa6,0xa5,0x61,0xb3,0xbc,0x63,0xb7,0xc8,0x65,0xbb,0xca,0x60,0xaf,0xb1,0x48,0x83,0x83,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0xf,0xf,0x55,0x9b,0x9a,0x60,0xb2,0xbd,0x5e,0xb1,0xcd,0x61,0xb3,0xc2,0x0,0x0,0x0,0x27,0x48,0x47,0x62,0xb4,0xbd,0x51,0x93,0x92,0x68,0xc0,0xcf,0x0,0x0,0x0,0x56,0x9d,0x9c,0x68,0xc1,0xcf,0x2d,0x52,0x52,0x63,0xb7,0xbf,0x52,0x96,0x95,0x62,0xb3,0xbf,0x5e,0xb0,0xcd,0x0,0x0,0x0,0x3,0x5,0x5,0x36,0x63,0x63,0x63,0xb4,0xb6,0x60,0xb1,0xbc,0x63,0xb7,0xc7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x55,0xa3,0xc8,0x4f,0x98,0xc4,0x4b,0x93,0xc2,0x4c,0x94,0xc2,0x54,0xa2,0xc8,0x5a,0xab,0xcb,0x4e,0x97,0xc4,0x49,0x8f,0xc0,0x47,0x8c,0xbf,0x48,0x8e,0xc0,0x52,0x9e,0xc6,0x51,0x9d,0xc6,0x5a,0xac,0xcc,0x53,0x9f,0xc7,0x4d,0x96,0xc3,0x4b,0x92,0xc2,0xff,0xff,0xff,0x76,0xbd,0x27,0x7a,0x0,0x0,0x0,0x1,0x74,0x52,0x4e,0x53,0x0,0x40,0xe6,0xd8,0x66,0x0,0x0,0x0,0x1,0x62,0x4b,0x47,0x44,0x0,0x88,0x5,0x1d,0x48,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe1,0x1,0x12,0x1,0x36,0x11,0x34,0xd2,0xf,0x93,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x48,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0xa0,0x12,0x10,0x14,0xe0,0xe7,0xe3,0x45,0xe2,0x4b,0x9a,0x18,0x1b,0x19,0x1a,0x48,0x88,0x8b,0xc1,0xe4,0x4d,0x2c,0x2d,0x80,0xc0,0xdc,0xcc,0x54,0x6,0x22,0x20,0x60,0x6c,0x1,0x1,0xe6,0x56,0x72,0x68,0x2,0xd6,0x8a,0xa8,0x5a,0x6c,0x94,0x11,0x86,0xda,0xdb,0xd9,0xaa,0xa9,0xaa,0x20,0x59,0xab,0xa3,0xad,0xc5,0x40,0x3d,0x0,0x0,0xbf,0x8e,0xc,0xed,0xed,0xc7,0x67,0x72,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
diff --git a/scene/resources/default_theme/vslider_grabber.png b/scene/resources/default_theme/vslider_grabber.png
index a61a6a57c9..afc490be45 100644
--- a/scene/resources/default_theme/vslider_grabber.png
+++ b/scene/resources/default_theme/vslider_grabber.png
Binary files differ
diff --git a/scene/resources/default_theme/vslider_grabber_hl.png b/scene/resources/default_theme/vslider_grabber_hl.png
index 548dbbbff8..548972e115 100644
--- a/scene/resources/default_theme/vslider_grabber_hl.png
+++ b/scene/resources/default_theme/vslider_grabber_hl.png
Binary files differ
diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp
index a913687e7f..9719f321d6 100644
--- a/scene/resources/scene_format_text.cpp
+++ b/scene/resources/scene_format_text.cpp
@@ -32,7 +32,8 @@
#include "version.h"
#include "os/dir_access.h"
-#define FORMAT_VERSION 1
+//version 2: changed names for basis, rect3, poolvectors, etc.
+#define FORMAT_VERSION 2
#include "version.h"
#include "os/dir_access.h"
@@ -1158,7 +1159,7 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant& p_variant,b
static String _valprop(const String& p_name) {
if (p_name.find("\"")!=-1 || p_name.find("=")!=-1 || p_name.find(" ")!=-1)
- return "\""+p_name.c_escape()+"\"";
+ return "\""+p_name.c_escape_multiline()+"\"";
return p_name;
}
@@ -1360,13 +1361,11 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path,const RES& p_re
}
if (groups.size()) {
- String sgroups=" groups=[ ";
+ String sgroups=" groups=[\n";
for(int j=0;j<groups.size();j++) {
- if (j>0)
- sgroups+=", ";
- sgroups+="\""+groups[j].operator String().c_escape()+"\"";
+ sgroups+="\""+String(groups[j]).c_escape()+"\",\n";
}
- sgroups+=" ]";
+ sgroups+="]";
header+=sgroups;
}
diff --git a/scene/resources/sphere_shape.cpp b/scene/resources/sphere_shape.cpp
index bcfb164b4c..c7c4d94aad 100644
--- a/scene/resources/sphere_shape.cpp
+++ b/scene/resources/sphere_shape.cpp
@@ -37,8 +37,8 @@ Vector<Vector3> SphereShape::_gen_debug_mesh_lines() {
for(int i=0;i<=360;i++) {
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+1);
+ float ra=Math::deg2rad((float)i);
+ float rb=Math::deg2rad((float)i+1);
Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index a1ad5d8237..a853b62254 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -453,6 +453,335 @@ ImageTexture::~ImageTexture() {
VisualServer::get_singleton()->free( texture );
}
+//////////////////////////////////////////
+
+
+
+uint32_t StreamTexture::get_flags() const {
+
+ return flags;
+}
+Image::Format StreamTexture::get_format() const {
+
+ return format;
+}
+
+
+Error StreamTexture::_load_data(const String& p_path,int &tw,int &th,int& flags,Image& image,int p_size_limit) {
+
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ ERR_FAIL_COND_V(!f,ERR_CANT_OPEN);
+
+ uint8_t header[4];
+ f->get_buffer(header,4);
+ if (header[0]!='G' || header[1]!='D' || header[2]!='S' || header[3]!='T') {
+ memdelete(f);
+ ERR_FAIL_COND_V(header[0]!='G' || header[1]!='D' || header[2]!='S' || header[3]!='T',ERR_FILE_CORRUPT);
+ }
+
+ tw = f->get_32();
+ th = f->get_32();
+ flags= f->get_32(); //texture flags!
+ uint32_t df = f->get_32(); //data format
+
+ print_line("width: "+itos(tw));
+ print_line("height: "+itos(th));
+ print_line("flags: "+itos(flags));
+ print_line("df: "+itos(df));
+
+ if (!(df&FORMAT_BIT_STREAM)) {
+ p_size_limit=0;
+ }
+
+
+ if (df&FORMAT_BIT_LOSSLESS || df&FORMAT_BIT_LOSSY) {
+ //look for a PNG or WEBP file inside
+
+ int sw=tw;
+ int sh=th;
+
+ uint32_t mipmaps = f->get_32();
+ uint32_t size = f->get_32();
+
+ print_line("mipmaps: "+itos(mipmaps));
+
+ while(mipmaps>1 && p_size_limit>0 && (sw>p_size_limit || sh>p_size_limit)) {
+
+ f->seek(f->get_pos()+size);
+ mipmaps = f->get_32();
+ size = f->get_32();
+
+ sw=MAX(sw>>1,1);
+ sh=MAX(sh>>1,1);
+ mipmaps--;
+ }
+
+ //mipmaps need to be read independently, they will be later combined
+ Vector<Image> mipmap_images;
+ int total_size=0;
+
+ for(int i=0;i<mipmaps;i++) {
+ PoolVector<uint8_t> pv;
+ pv.resize(size);
+ {
+ PoolVector<uint8_t>::Write w = pv.write();
+ f->get_buffer(w.ptr(),size);
+ }
+
+ Image img;
+ if (df&FORMAT_BIT_LOSSLESS) {
+ img = Image::lossless_unpacker(pv);
+ } else {
+ img = Image::lossy_unpacker(pv);
+ }
+
+ if (img.empty()) {
+ memdelete(f);
+ ERR_FAIL_COND_V(img.empty(),ERR_FILE_CORRUPT);
+ }
+ total_size+=img.get_data().size();
+
+ mipmap_images.push_back(img);
+ }
+
+ print_line("mipmap read total: "+itos(mipmap_images.size()));
+
+
+ memdelete(f); //no longer needed
+
+ if (mipmap_images.size()==1) {
+
+ image=mipmap_images[0];
+ return OK;
+
+ } else {
+ PoolVector<uint8_t> img_data;
+ img_data.resize(total_size);
+
+ {
+ PoolVector<uint8_t>::Write w=img_data.write();
+
+ int ofs=0;
+ for(int i=0;i<mipmap_images.size();i++) {
+
+ PoolVector<uint8_t> id = mipmap_images[i].get_data();
+ int len = id.size();
+ PoolVector<uint8_t>::Read r = id.read();
+ copymem(&w[ofs],r.ptr(),len);
+ ofs+=len;
+ }
+ }
+
+ image = Image(sw,sh,true,mipmap_images[0].get_format(),img_data);
+ return OK;
+ }
+
+ } else {
+
+ //look for regular format
+ Image::Format format = (Image::Format)(df&FORMAT_MASK_IMAGE_FORMAT);
+ bool mipmaps = df&FORMAT_BIT_HAS_MIPMAPS;
+
+ if (!mipmaps) {
+ int size = Image::get_image_data_size(tw,th,format,0);
+
+ PoolVector<uint8_t> img_data;
+ img_data.resize(size);
+
+ {
+ PoolVector<uint8_t>::Write w=img_data.write();
+ f->get_buffer(w.ptr(),size);
+ }
+
+ memdelete(f);
+
+ image = Image(tw,th,false,format,img_data);
+ return OK;
+ } else {
+
+ int sw=tw;
+ int sh=th;
+
+ int mipmaps = Image::get_image_required_mipmaps(tw,th,format);
+ int total_size = Image::get_image_data_size(tw,th,format,mipmaps);
+ int idx=0;
+ int ofs=0;
+
+
+ while(mipmaps>1 && p_size_limit>0 && (sw>p_size_limit || sh>p_size_limit)) {
+
+ sw=MAX(sw>>1,1);
+ sh=MAX(sh>>1,1);
+ mipmaps--;
+ idx++;
+ }
+
+ if (idx>0) {
+ ofs=Image::get_image_data_size(tw,th,format,idx-1);
+ }
+
+ if (total_size - ofs <=0) {
+ memdelete(f);
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ f->seek(f->get_pos()+ofs);
+
+
+ PoolVector<uint8_t> img_data;
+ img_data.resize(total_size - ofs);
+
+ {
+ PoolVector<uint8_t>::Write w=img_data.write();
+ int bytes = f->get_buffer(w.ptr(),total_size - ofs);
+
+ memdelete(f);
+
+ if (bytes != total_size - ofs) {
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+ }
+
+ image = Image(sw,sh,true,format,img_data);
+
+ return OK;
+ }
+ }
+
+ return ERR_BUG; //unreachable
+}
+
+Error StreamTexture::load(const String& p_path) {
+
+
+ int lw,lh,lflags;
+ Image image;
+ Error err = _load_data(p_path,lw,lh,lflags,image);
+ if (err)
+ return err;
+
+ VS::get_singleton()->texture_allocate(texture,image.get_width(),image.get_height(),image.get_format(),lflags);
+ VS::get_singleton()->texture_set_data(texture,image);
+
+ w=lw;
+ h=lh;
+ flags=lflags;
+ path_to_file=p_path;
+ format=image.get_format();
+
+ return OK;
+}
+String StreamTexture::get_load_path() const {
+
+ return path_to_file;
+}
+
+int StreamTexture::get_width() const {
+
+ return w;
+}
+int StreamTexture::get_height() const {
+
+ return h;
+}
+RID StreamTexture::get_rid() const {
+
+ return texture;
+}
+
+
+void StreamTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
+
+ if ((w|h)==0)
+ return;
+ VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, Size2(w,h)),texture,false,p_modulate,p_transpose);
+
+}
+void StreamTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
+
+ if ((w|h)==0)
+ return;
+ VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,texture,p_tile,p_modulate,p_transpose);
+
+}
+void StreamTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const{
+
+ if ((w|h)==0)
+ return;
+ VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,texture,p_src_rect,p_modulate,p_transpose);
+}
+
+bool StreamTexture::has_alpha() const {
+
+ return false;
+}
+void StreamTexture::set_flags(uint32_t p_flags){
+
+}
+
+void StreamTexture::reload_from_file() {
+
+ load(path_to_file);
+}
+
+void StreamTexture::_bind_methods() {
+
+ ClassDB::bind_method(_MD("load","path"),&StreamTexture::load);
+ ClassDB::bind_method(_MD("get_load_path"),&StreamTexture::get_load_path);
+
+ ADD_PROPERTY( PropertyInfo(Variant::STRING,"load_path",PROPERTY_HINT_FILE,"*.stex"),_SCS("load"),_SCS("get_load_path"));
+}
+
+
+StreamTexture::StreamTexture() {
+
+ format=Image::FORMAT_MAX;
+ flags=0;
+ w=0;
+ h=0;
+
+ texture = VS::get_singleton()->texture_create();
+}
+
+StreamTexture::~StreamTexture() {
+
+ VS::get_singleton()->free(texture);
+}
+
+
+
+RES ResourceFormatLoaderStreamTexture::load(const String &p_path,const String& p_original_path,Error *r_error) {
+
+ Ref<StreamTexture> st;
+ st.instance();
+ Error err = st->load(p_path);
+ if (r_error)
+ *r_error=err;
+ if (err!=OK)
+ return RES();
+
+ return st;
+}
+
+void ResourceFormatLoaderStreamTexture::get_recognized_extensions(List<String> *p_extensions) const{
+
+ p_extensions->push_back("stex");
+}
+bool ResourceFormatLoaderStreamTexture::handles_type(const String& p_type) const{
+ return p_type=="StreamTexture";
+
+}
+String ResourceFormatLoaderStreamTexture::get_resource_type(const String &p_path) const{
+
+ if (p_path.get_extension().to_lower()=="stex")
+ return "StreamTexture";
+ return "";
+}
+
+
+
+
//////////////////////////////////////////
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index aac3514af3..919c588894 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -31,6 +31,7 @@
#include "resource.h"
#include "servers/visual_server.h"
+#include "io/resource_loader.h"
#include "math_2d.h"
/**
@@ -160,6 +161,76 @@ public:
};
+
+class StreamTexture : public Texture {
+
+ GDCLASS( StreamTexture, Texture );
+public:
+ enum DataFormat {
+ DATA_FORMAT_IMAGE,
+ DATA_FORMAT_LOSSLESS,
+ DATA_FORMAT_LOSSY
+ };
+
+ enum FormatBits {
+ FORMAT_MASK_IMAGE_FORMAT=(1<<20)-1,
+ FORMAT_BIT_LOSSLESS=1<<20,
+ FORMAT_BIT_LOSSY=1<<21,
+ FORMAT_BIT_STREAM=1<<22,
+ FORMAT_BIT_HAS_MIPMAPS=1<<23,
+ };
+
+private:
+
+ Error _load_data(const String &p_path, int &tw, int &th, int& flags, Image& image, int p_size_limit=0);
+ String path_to_file;
+ RID texture;
+ Image::Format format;
+ uint32_t flags;
+ int w,h;
+
+ virtual void reload_from_file();
+
+protected:
+
+ static void _bind_methods();
+
+public:
+
+
+ uint32_t get_flags() const;
+ Image::Format get_format() const;
+ Error load(const String& p_path);
+ String get_load_path() const;
+
+ int get_width() const;
+ int get_height() const;
+ virtual RID get_rid() const;
+
+ virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+ virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+ virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+
+ virtual bool has_alpha() const;
+ virtual void set_flags(uint32_t p_flags);
+
+ StreamTexture();
+ ~StreamTexture();
+
+};
+
+
+class ResourceFormatLoaderStreamTexture : public ResourceFormatLoader {
+public:
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String& p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+
+};
+
+
+
VARIANT_ENUM_CAST( ImageTexture::Storage );
class AtlasTexture : public Texture {
diff --git a/servers/audio/SCsub b/servers/audio/SCsub
index ccc76e823f..afaffcfe93 100644
--- a/servers/audio/SCsub
+++ b/servers/audio/SCsub
@@ -5,3 +5,5 @@ Import('env')
env.add_source_files(env.servers_sources, "*.cpp")
Export('env')
+
+SConscript("effects/SCsub")
diff --git a/servers/audio/audio_effect.h b/servers/audio/audio_effect.h
index 2fcd22251b..02eb258f99 100644
--- a/servers/audio/audio_effect.h
+++ b/servers/audio/audio_effect.h
@@ -10,7 +10,7 @@ class AudioEffectInstance : public Reference {
public:
- virtual void process(AudioFrame *p_frames,int p_frame_count)=0;
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count)=0;
};
diff --git a/servers/audio/audio_filter_sw.cpp b/servers/audio/audio_filter_sw.cpp
index cdfe1a29f0..e97eb75d04 100644
--- a/servers/audio/audio_filter_sw.cpp
+++ b/servers/audio/audio_filter_sw.cpp
@@ -142,9 +142,9 @@ void AudioFilterSW::prepare_coefficients(Coeffs *p_coeffs) {
//this one is extra tricky
double hicutoff=resonance;
double centercutoff = (cutoff+resonance)/2.0;
- double bandwidth=(Math::log(centercutoff)-Math::log(hicutoff))/Math::log(2);
+ double bandwidth=(Math::log(centercutoff)-Math::log(hicutoff))/Math::log((double)2);
omega=2.0*Math_PI*centercutoff/sampling_rate;
- alpha = Math::sin(omega)*Math::sinh( Math::log(2)/2 * bandwidth * omega/Math::sin(omega) );
+ alpha = Math::sin(omega)*Math::sinh( Math::log((double)2)/2 * bandwidth * omega/Math::sin(omega) );
a0=1+alpha;
p_coeffs->b0 = alpha;
diff --git a/servers/audio/audio_filter_sw.h b/servers/audio/audio_filter_sw.h
index 0f3e2410fd..b711944ca8 100644
--- a/servers/audio/audio_filter_sw.h
+++ b/servers/audio/audio_filter_sw.h
@@ -65,7 +65,7 @@ public:
void set_filter(AudioFilterSW * p_filter);
void process(float *p_samples,int p_amount, int p_stride=1);
void update_coeffs();
- inline void process_one(float& p_sample);
+ _ALWAYS_INLINE_ void process_one(float& p_sample);
Processor();
};
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
new file mode 100644
index 0000000000..f4214838a1
--- /dev/null
+++ b/servers/audio/audio_stream.cpp
@@ -0,0 +1,86 @@
+/*************************************************************************/
+/* audio_stream.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan 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_stream.h"
+
+//////////////////////////////
+
+
+
+void AudioStreamPlaybackResampled::_begin_resample() {
+
+ //clear cubic interpolation history
+ internal_buffer[0]=AudioFrame(0.0,0.0);
+ internal_buffer[1]=AudioFrame(0.0,0.0);
+ internal_buffer[2]=AudioFrame(0.0,0.0);
+ internal_buffer[3]=AudioFrame(0.0,0.0);
+ //mix buffer
+ _mix_internal(internal_buffer+4,INTERNAL_BUFFER_LEN);
+ mix_offset=0;
+}
+
+void AudioStreamPlaybackResampled::mix(AudioFrame* p_buffer,float p_rate_scale,int p_frames) {
+
+ float target_rate = AudioServer::get_singleton()->get_mix_rate() * p_rate_scale;
+
+ uint64_t mix_increment = uint64_t((get_stream_sampling_rate() / double(target_rate)) * double( FP_LEN ));
+
+ for(int i=0;i<p_frames;i++) {
+
+
+
+ uint32_t idx = CUBIC_INTERP_HISTORY + uint32_t(mix_offset >> FP_BITS);
+ //standard cubic interpolation (great quality/performance ratio)
+ //this used to be moved to a LUT for greater performance, but nowadays CPU speed is generally faster than memory.
+ float mu = (mix_offset&FP_MASK)/float(FP_LEN);
+ AudioFrame y0 = internal_buffer[idx-3];
+ AudioFrame y1 = internal_buffer[idx-2];
+ AudioFrame y2 = internal_buffer[idx-1];
+ AudioFrame y3 = internal_buffer[idx-0];
+
+ float mu2 = mu*mu;
+ AudioFrame a0 = y3 - y2 - y0 + y1;
+ AudioFrame a1 = y0 - y1 - a0;
+ AudioFrame a2 = y2 - y0;
+ AudioFrame a3 = y1;
+
+ p_buffer[i] = (a0*mu*mu2 + a1*mu2 + a2*mu + a3);
+
+ mix_offset+=mix_increment;
+
+ while ( (mix_offset >> FP_BITS) >= INTERNAL_BUFFER_LEN ) {
+
+ internal_buffer[0]=internal_buffer[INTERNAL_BUFFER_LEN+0];
+ internal_buffer[1]=internal_buffer[INTERNAL_BUFFER_LEN+1];
+ internal_buffer[2]=internal_buffer[INTERNAL_BUFFER_LEN+2];
+ internal_buffer[3]=internal_buffer[INTERNAL_BUFFER_LEN+3];
+ _mix_internal(internal_buffer+4,INTERNAL_BUFFER_LEN);
+ mix_offset-=(INTERNAL_BUFFER_LEN<<FP_BITS);
+ }
+ }
+}
diff --git a/scene/resources/audio_stream.h b/servers/audio/audio_stream.h
index b79707cd32..d08fedb084 100644
--- a/scene/resources/audio_stream.h
+++ b/servers/audio/audio_stream.h
@@ -34,47 +34,65 @@
class AudioStreamPlayback : public Reference {
- GDCLASS( AudioStreamPlayback, Reference );
-protected:
- static void _bind_methods();
-public:
+ GDCLASS( AudioStreamPlayback, Reference )
+public:
- virtual void play(float p_from_pos=0)=0;
+ virtual void start(float p_from_pos=0.0)=0;
virtual void stop()=0;
virtual bool is_playing() const=0;
- virtual void set_loop(bool p_enable)=0;
- virtual bool has_loop() const=0;
-
- virtual void set_loop_restart_time(float p_time)=0;
-
- virtual int get_loop_count() const=0;
+ virtual int get_loop_count() const=0; //times it looped
virtual float get_pos() const=0;
virtual void seek_pos(float p_time)=0;
- virtual int mix(int16_t* p_bufer,int p_frames)=0;
+ virtual void mix(AudioFrame* p_bufer,float p_rate_scale,int p_frames)=0;
- virtual float get_length() const=0;
- virtual String get_stream_name() const=0;
+ virtual float get_length() const=0; //if supported, otherwise return 0
- virtual int get_channels() const=0;
- virtual int get_mix_rate() const=0;
- virtual int get_minimum_buffer_size() const=0;
};
-class AudioStream : public Resource {
+class AudioStreamPlaybackResampled : public AudioStreamPlayback {
+
+ GDCLASS( AudioStreamPlaybackResampled, AudioStreamPlayback )
+
+
+
+ enum {
+ FP_BITS=16, //fixed point used for resampling
+ FP_LEN=(1<<FP_BITS),
+ FP_MASK=FP_LEN-1,
+ INTERNAL_BUFFER_LEN=256,
+ CUBIC_INTERP_HISTORY=4
+ };
- GDCLASS( AudioStream, Resource );
- OBJ_SAVE_TYPE( AudioStream ); //children are all saved as AudioStream, so they can be exchanged
+ AudioFrame internal_buffer[INTERNAL_BUFFER_LEN+CUBIC_INTERP_HISTORY];
+ uint64_t mix_offset;
protected:
- static void _bind_methods();
+ void _begin_resample();
+ virtual void _mix_internal(AudioFrame* p_bufer,int p_frames)=0;
+ virtual float get_stream_sampling_rate()=0;
+
+public:
+
+ virtual void mix(AudioFrame* p_bufer,float p_rate_scale,int p_frames);
+
+ AudioStreamPlaybackResampled() { mix_offset=0; }
+};
+
+class AudioStream : public Resource {
+
+ GDCLASS( AudioStream, Resource )
+ OBJ_SAVE_TYPE( AudioStream ) //children are all saved as AudioStream, so they can be exchanged
+
+
public:
virtual Ref<AudioStreamPlayback> instance_playback()=0;
+ virtual String get_stream_name() const=0;
};
diff --git a/servers/audio/effects/SCsub b/servers/audio/effects/SCsub
new file mode 100644
index 0000000000..ccc76e823f
--- /dev/null
+++ b/servers/audio/effects/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import('env')
+
+env.add_source_files(env.servers_sources, "*.cpp")
+
+Export('env')
diff --git a/servers/audio/effects/audio_effect_amplify.cpp b/servers/audio/effects/audio_effect_amplify.cpp
new file mode 100644
index 0000000000..d723f8d2fe
--- /dev/null
+++ b/servers/audio/effects/audio_effect_amplify.cpp
@@ -0,0 +1,50 @@
+#include "audio_effect_amplify.h"
+
+
+void AudioEffectAmplifyInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+
+ //multiply volume interpolating to avoid clicks if this changes
+ float volume_db = base->volume_db;
+ float vol = Math::db2linear(mix_volume_db);
+ float vol_inc = (Math::db2linear(volume_db) - vol)/float(p_frame_count);
+
+ for(int i=0;i<p_frame_count;i++) {
+ p_dst_frames[i]=p_src_frames[i]*vol;
+ vol+=vol_inc;
+ }
+ //set volume for next mix
+ mix_volume_db = volume_db;
+
+}
+
+
+Ref<AudioEffectInstance> AudioEffectAmplify::instance() {
+ Ref<AudioEffectAmplifyInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectAmplify>(this);
+ ins->mix_volume_db=volume_db;
+ return ins;
+}
+
+void AudioEffectAmplify::set_volume_db(float p_volume) {
+ volume_db=p_volume;
+}
+
+float AudioEffectAmplify::get_volume_db() const {
+
+ return volume_db;
+}
+
+void AudioEffectAmplify::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_volume_db","volume"),&AudioEffectAmplify::set_volume_db);
+ ClassDB::bind_method(_MD("get_volume_db"),&AudioEffectAmplify::get_volume_db);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"volume_db",PROPERTY_HINT_RANGE,"-80,24,0.01"),_SCS("set_volume_db"),_SCS("get_volume_db"));
+}
+
+AudioEffectAmplify::AudioEffectAmplify()
+{
+ volume_db=0;
+}
diff --git a/servers/audio/effects/audio_effect_amplify.h b/servers/audio/effects/audio_effect_amplify.h
new file mode 100644
index 0000000000..921054e2cd
--- /dev/null
+++ b/servers/audio/effects/audio_effect_amplify.h
@@ -0,0 +1,40 @@
+#ifndef AUDIOEFFECTAMPLIFY_H
+#define AUDIOEFFECTAMPLIFY_H
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectAmplify;
+
+class AudioEffectAmplifyInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectAmplifyInstance,AudioEffectInstance)
+friend class AudioEffectAmplify;
+ Ref<AudioEffectAmplify> base;
+
+ float mix_volume_db;
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectAmplify : public AudioEffect {
+ GDCLASS(AudioEffectAmplify,AudioEffect)
+
+friend class AudioEffectAmplifyInstance;
+ float volume_db;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+
+ Ref<AudioEffectInstance> instance();
+ void set_volume_db(float p_volume);
+ float get_volume_db() const;
+
+ AudioEffectAmplify();
+};
+
+#endif // AUDIOEFFECTAMPLIFY_H
diff --git a/servers/audio/effects/audio_effect_chorus.cpp b/servers/audio/effects/audio_effect_chorus.cpp
new file mode 100644
index 0000000000..d3105343ae
--- /dev/null
+++ b/servers/audio/effects/audio_effect_chorus.cpp
@@ -0,0 +1,365 @@
+#include "audio_effect_chorus.h"
+#include "servers/audio_server.h"
+#include "math_funcs.h"
+
+void AudioEffectChorusInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+ int todo = p_frame_count;
+
+ while(todo) {
+
+ int to_mix = MIN(todo,256); //can't mix too much
+
+ _process_chunk(p_src_frames,p_dst_frames,to_mix);
+
+ p_src_frames+=to_mix;
+ p_dst_frames+=to_mix;
+
+ todo-=to_mix;
+ }
+}
+
+void AudioEffectChorusInstance::_process_chunk(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+
+ //fill ringbuffer
+ for(int i=0;i<p_frame_count;i++) {
+ audio_buffer[(buffer_pos+i)&buffer_mask]=p_src_frames[i];
+ p_dst_frames[i]=p_src_frames[i]*base->dry;
+ }
+
+ float mix_rate = AudioServer::get_singleton()->get_mix_rate();
+
+ /* process voices */
+ for (int vc=0;vc<base->voice_count;vc++) {
+
+ AudioEffectChorus::Voice &v=base->voice[vc];
+
+
+ double time_to_mix=(float)p_frame_count/mix_rate;
+ double cycles_to_mix=time_to_mix*v.rate;
+
+ unsigned int local_rb_pos=buffer_pos;
+ AudioFrame *dst_buff=p_dst_frames;
+ AudioFrame *rb_buff=audio_buffer.ptr();
+
+ double delay_msec=v.delay;
+ unsigned int delay_frames=Math::fast_ftoi((delay_msec/1000.0)*mix_rate);
+ float max_depth_frames=(v.depth/1000.0)*mix_rate;
+
+ uint64_t local_cycles=cycles[vc];
+ uint64_t increment=llrint(cycles_to_mix/(double)p_frame_count*(double)(1<<AudioEffectChorus::CYCLES_FRAC));
+
+ //check the LFO doesnt read ahead of the write pos
+ if ((((int)max_depth_frames)+10)>delay_frames) { //10 as some threshold to avoid precision stuff
+ delay_frames+=(int)max_depth_frames-delay_frames;
+ delay_frames+=10; //threshold to avoid precision stuff
+
+ }
+
+
+
+ //low pass filter
+ if (v.cutoff==0)
+ continue;
+ float auxlp=expf(-2.0*Math_PI*v.cutoff/mix_rate);
+ float c1=1.0-auxlp;
+ float c2=auxlp;
+ AudioFrame h=filter_h[vc];
+ if (v.cutoff>=AudioEffectChorus::MS_CUTOFF_MAX) {
+ c1=1.0; c2=0.0;
+ }
+
+ //vol modifier
+
+ AudioFrame vol_modifier=AudioFrame(base->wet,base->wet) * Math::db2linear(v.level);
+ vol_modifier.l*=CLAMP( 1.0 - v.pan, 0, 1);
+ vol_modifier.r*=CLAMP( 1.0 + v.pan, 0, 1);
+
+
+
+ for (int i=0;i<p_frame_count;i++) {
+
+ /** COMPUTE WAVEFORM **/
+
+ float phase=(float)(local_cycles&AudioEffectChorus::CYCLES_MASK)/(float)(1<<AudioEffectChorus::CYCLES_FRAC);
+
+ float wave_delay=sinf(phase*2.0*Math_PI)*max_depth_frames;
+
+ int wave_delay_frames=lrint(floor(wave_delay));
+ float wave_delay_frac=wave_delay-(float)wave_delay_frames;
+
+ /** COMPUTE RINGBUFFER POS**/
+
+ unsigned int rb_source=local_rb_pos;
+ rb_source-=delay_frames;
+
+ rb_source-=wave_delay_frames;
+
+ /** READ FROM RINGBUFFER, LINEARLY INTERPOLATE */
+
+ AudioFrame val=rb_buff[rb_source&buffer_mask];
+ AudioFrame val_next=rb_buff[(rb_source-1)&buffer_mask];
+
+ val+=(val_next-val)*wave_delay_frac;
+
+ val=val*c1+h*c2;
+ h=val;
+
+ /** MIX VALUE TO OUTPUT **/
+
+ dst_buff[i]+=val*vol_modifier;
+
+ local_cycles+=increment;
+ local_rb_pos++;
+
+ }
+
+ filter_h[vc]=h;
+ cycles[vc]+=Math::fast_ftoi(cycles_to_mix*(double)(1<<AudioEffectChorus::CYCLES_FRAC));
+ }
+
+ buffer_pos+=p_frame_count;
+}
+
+
+Ref<AudioEffectInstance> AudioEffectChorus::instance() {
+
+ Ref<AudioEffectChorusInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectChorus>(this);
+ for(int i=0;i<4;i++) {
+ ins->filter_h[i]=AudioFrame(0,0);
+ ins->cycles[i]=0;
+ }
+
+ float ring_buffer_max_size=AudioEffectChorus::MAX_DELAY_MS+AudioEffectChorus::MAX_DEPTH_MS+AudioEffectChorus::MAX_WIDTH_MS;
+
+ ring_buffer_max_size*=2; //just to avoid complications
+ ring_buffer_max_size/=1000.0;//convert to seconds
+ ring_buffer_max_size*=AudioServer::get_singleton()->get_mix_rate();
+
+ int ringbuff_size=ring_buffer_max_size;
+
+ int bits=0;
+
+ while(ringbuff_size>0) {
+ bits++;
+ ringbuff_size/=2;
+ }
+
+ ringbuff_size=1<<bits;
+ ins->buffer_mask=ringbuff_size-1;
+ ins->buffer_pos=0;
+ ins->audio_buffer.resize(ringbuff_size);
+ for(int i=0;i<ringbuff_size;i++) {
+ ins->audio_buffer[i]=AudioFrame(0,0);
+ }
+
+ return ins;
+}
+
+void AudioEffectChorus::set_voice_count(int p_voices) {
+
+ ERR_FAIL_COND(p_voices<1 || p_voices>=MAX_VOICES);
+ voice_count=p_voices;
+ _change_notify();
+}
+
+
+int AudioEffectChorus::get_voice_count() const{
+
+ return voice_count;
+}
+
+void AudioEffectChorus::set_voice_delay_ms(int p_voice,float p_delay_ms){
+
+ ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+ voice[p_voice].delay=p_delay_ms;
+
+}
+float AudioEffectChorus::get_voice_delay_ms(int p_voice) const{
+
+ ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+ return voice[p_voice].delay;
+}
+
+void AudioEffectChorus::set_voice_rate_hz(int p_voice,float p_rate_hz){
+ ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+ voice[p_voice].rate=p_rate_hz;
+}
+float AudioEffectChorus::get_voice_rate_hz(int p_voice) const{
+
+ ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+
+ return voice[p_voice].rate;
+}
+
+void AudioEffectChorus::set_voice_depth_ms(int p_voice,float p_depth_ms){
+
+ ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+ voice[p_voice].depth=p_depth_ms;
+}
+float AudioEffectChorus::get_voice_depth_ms(int p_voice) const{
+
+ ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+
+ return voice[p_voice].depth;
+}
+
+void AudioEffectChorus::set_voice_level_db(int p_voice,float p_level_db){
+
+ ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+ voice[p_voice].level=p_level_db;
+}
+float AudioEffectChorus::get_voice_level_db(int p_voice) const{
+
+ ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+
+ return voice[p_voice].level;
+}
+
+
+void AudioEffectChorus::set_voice_cutoff_hz(int p_voice,float p_cutoff_hz){
+
+ ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+ voice[p_voice].cutoff=p_cutoff_hz;
+}
+float AudioEffectChorus::get_voice_cutoff_hz(int p_voice) const{
+
+ ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+
+ return voice[p_voice].cutoff;
+}
+
+void AudioEffectChorus::set_voice_pan(int p_voice,float p_pan){
+
+ ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+ voice[p_voice].pan=p_pan;
+}
+float AudioEffectChorus::get_voice_pan(int p_voice) const{
+
+ ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+
+ return voice[p_voice].pan;
+}
+
+
+void AudioEffectChorus::set_wet(float amount){
+
+
+ wet=amount;
+}
+float AudioEffectChorus::get_wet() const{
+
+ return wet;
+}
+
+void AudioEffectChorus::set_dry(float amount){
+
+ dry=amount;
+
+}
+float AudioEffectChorus::get_dry() const{
+
+ return dry;
+}
+
+void AudioEffectChorus::_validate_property(PropertyInfo& property) const {
+
+ if (property.name.begins_with("voice/")) {
+ int voice_idx = property.name.get_slice("/",1).to_int();
+ if (voice_idx>voice_count) {
+ property.usage=0;
+ }
+ }
+}
+
+
+void AudioEffectChorus::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_voice_count","voices"),&AudioEffectChorus::set_voice_count);
+ ClassDB::bind_method(_MD("get_voice_count"),&AudioEffectChorus::get_voice_count);
+
+
+ ClassDB::bind_method(_MD("set_voice_delay_ms","voice_idx","delay_ms"),&AudioEffectChorus::set_voice_delay_ms);
+ ClassDB::bind_method(_MD("get_voice_delay_ms","voice_idx"),&AudioEffectChorus::get_voice_delay_ms);
+
+ ClassDB::bind_method(_MD("set_voice_rate_hz","voice_idx","rate_hz"),&AudioEffectChorus::set_voice_rate_hz);
+ ClassDB::bind_method(_MD("get_voice_rate_hz","voice_idx"),&AudioEffectChorus::get_voice_rate_hz);
+
+ ClassDB::bind_method(_MD("set_voice_depth_ms","voice_idx","depth_ms"),&AudioEffectChorus::set_voice_depth_ms);
+ ClassDB::bind_method(_MD("get_voice_depth_ms","voice_idx"),&AudioEffectChorus::get_voice_depth_ms);
+
+ ClassDB::bind_method(_MD("set_voice_level_db","voice_idx","level_db"),&AudioEffectChorus::set_voice_level_db);
+ ClassDB::bind_method(_MD("get_voice_level_db","voice_idx"),&AudioEffectChorus::get_voice_level_db);
+
+ ClassDB::bind_method(_MD("set_voice_cutoff_hz","voice_idx","cutoff_hz"),&AudioEffectChorus::set_voice_cutoff_hz);
+ ClassDB::bind_method(_MD("get_voice_cutoff_hz","voice_idx"),&AudioEffectChorus::get_voice_cutoff_hz);
+
+ ClassDB::bind_method(_MD("set_voice_pan","voice_idx","pan"),&AudioEffectChorus::set_voice_pan);
+ ClassDB::bind_method(_MD("get_voice_pan","voice_idx"),&AudioEffectChorus::get_voice_pan);
+
+ ClassDB::bind_method(_MD("set_wet","amount"),&AudioEffectChorus::set_wet);
+ ClassDB::bind_method(_MD("get_wet"),&AudioEffectChorus::get_wet);
+
+ ClassDB::bind_method(_MD("set_dry","amount"),&AudioEffectChorus::set_dry);
+ ClassDB::bind_method(_MD("get_dry"),&AudioEffectChorus::get_dry);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"voice_count",PROPERTY_HINT_RANGE,"1,4,1"),_SCS("set_voice_count"),_SCS("get_voice_count"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"dry",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_dry"),_SCS("get_dry"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"wet",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_wet"),_SCS("get_wet"));
+
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/delay_ms",PROPERTY_HINT_RANGE,"0,50,0.01"),_SCS("set_voice_delay_ms"),_SCS("get_voice_delay_ms"),0);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/rate_hz",PROPERTY_HINT_RANGE,"0.1,20,0.1"),_SCS("set_voice_rate_hz"),_SCS("get_voice_rate_hz"),0);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/depth_ms",PROPERTY_HINT_RANGE,"0,20,0.01"),_SCS("set_voice_depth_ms"),_SCS("get_voice_depth_ms"),0);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/level_db",PROPERTY_HINT_RANGE,"-60,24,0.1"),_SCS("set_voice_level_db"),_SCS("get_voice_level_db"),0);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/cutoff_hz",PROPERTY_HINT_RANGE,"1,16000,1"),_SCS("set_voice_cutoff_hz"),_SCS("get_voice_cutoff_hz"),0);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_voice_pan"),_SCS("get_voice_pan"),0);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/delay_ms",PROPERTY_HINT_RANGE,"0,50,0.01"),_SCS("set_voice_delay_ms"),_SCS("get_voice_delay_ms"),1);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/rate_hz",PROPERTY_HINT_RANGE,"0.1,20,0.1"),_SCS("set_voice_rate_hz"),_SCS("get_voice_rate_hz"),1);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/depth_ms",PROPERTY_HINT_RANGE,"0,20,0.01"),_SCS("set_voice_depth_ms"),_SCS("get_voice_depth_ms"),1);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/level_db",PROPERTY_HINT_RANGE,"-60,24,0.1"),_SCS("set_voice_level_db"),_SCS("get_voice_level_db"),1);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/cutoff_hz",PROPERTY_HINT_RANGE,"1,16000,1"),_SCS("set_voice_cutoff_hz"),_SCS("get_voice_cutoff_hz"),1);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_voice_pan"),_SCS("get_voice_pan"),1);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/delay_ms",PROPERTY_HINT_RANGE,"0,50,0.01"),_SCS("set_voice_delay_ms"),_SCS("get_voice_delay_ms"),2);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/rate_hz",PROPERTY_HINT_RANGE,"0.1,20,0.1"),_SCS("set_voice_rate_hz"),_SCS("get_voice_rate_hz"),2);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/depth_ms",PROPERTY_HINT_RANGE,"0,20,0.01"),_SCS("set_voice_depth_ms"),_SCS("get_voice_depth_ms"),2);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/level_db",PROPERTY_HINT_RANGE,"-60,24,0.1"),_SCS("set_voice_level_db"),_SCS("get_voice_level_db"),2);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/cutoff_hz",PROPERTY_HINT_RANGE,"1,16000,1"),_SCS("set_voice_cutoff_hz"),_SCS("get_voice_cutoff_hz"),2);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_voice_pan"),_SCS("get_voice_pan"),2);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/delay_ms",PROPERTY_HINT_RANGE,"0,50,0.01"),_SCS("set_voice_delay_ms"),_SCS("get_voice_delay_ms"),3);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/rate_hz",PROPERTY_HINT_RANGE,"0.1,20,0.1"),_SCS("set_voice_rate_hz"),_SCS("get_voice_rate_hz"),3);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/depth_ms",PROPERTY_HINT_RANGE,"0,20,0.01"),_SCS("set_voice_depth_ms"),_SCS("get_voice_depth_ms"),3);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/level_db",PROPERTY_HINT_RANGE,"-60,24,0.1"),_SCS("set_voice_level_db"),_SCS("get_voice_level_db"),3);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/cutoff_hz",PROPERTY_HINT_RANGE,"1,16000,1"),_SCS("set_voice_cutoff_hz"),_SCS("get_voice_cutoff_hz"),3);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_voice_pan"),_SCS("get_voice_pan"),3);
+
+}
+
+AudioEffectChorus::AudioEffectChorus()
+{
+ voice_count=2;
+ voice[0].delay=15;
+ voice[1].delay=20;
+ voice[0].rate=0.8;
+ voice[1].rate=1.2;
+ voice[0].depth=2;
+ voice[1].depth=3;
+ voice[0].cutoff=8000;
+ voice[1].cutoff=8000;
+ voice[0].pan=-0.5;
+ voice[1].pan=0.5;
+
+ wet=0.5;
+ dry=1.0;
+}
diff --git a/servers/audio/effects/audio_effect_chorus.h b/servers/audio/effects/audio_effect_chorus.h
new file mode 100644
index 0000000000..4cfba5d61a
--- /dev/null
+++ b/servers/audio/effects/audio_effect_chorus.h
@@ -0,0 +1,115 @@
+#ifndef AUDIOEFFECTCHORUS_H
+#define AUDIOEFFECTCHORUS_H
+
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectChorus;
+
+class AudioEffectChorusInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectChorusInstance,AudioEffectInstance)
+friend class AudioEffectChorus;
+ Ref<AudioEffectChorus> base;
+
+ Vector<AudioFrame> audio_buffer;
+ unsigned int buffer_pos;
+ unsigned int buffer_mask;
+
+ AudioFrame filter_h[4];
+ uint64_t cycles[4];
+
+ void _process_chunk(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectChorus : public AudioEffect {
+ GDCLASS(AudioEffectChorus,AudioEffect)
+
+friend class AudioEffectChorusInstance;
+public:
+ enum {
+
+ MAX_DELAY_MS=50,
+ MAX_DEPTH_MS=20,
+ MAX_WIDTH_MS=50,
+ MAX_VOICES=4,
+ CYCLES_FRAC=16,
+ CYCLES_MASK=(1<<CYCLES_FRAC)-1,
+ MAX_CHANNELS=4,
+ MS_CUTOFF_MAX=16000
+ };
+
+private:
+
+ struct Voice {
+
+ float delay;
+ float rate;
+ float depth;
+ float level;
+ float cutoff;
+ float pan;
+
+ Voice() {
+
+ delay=12.0;
+ rate=1;
+ depth=0;
+ level=0;
+ cutoff=MS_CUTOFF_MAX;
+ pan=0;
+
+ }
+
+ } voice[MAX_VOICES];
+
+ int voice_count;
+
+ float wet;
+ float dry;
+
+
+protected:
+ void _validate_property(PropertyInfo& property) const;
+
+ static void _bind_methods();
+public:
+
+ void set_voice_count(int p_voices);
+ int get_voice_count() const;
+
+ void set_voice_delay_ms(int p_voice,float p_delay_ms);
+ float get_voice_delay_ms(int p_voice) const;
+
+ void set_voice_rate_hz(int p_voice,float p_rate_hz);
+ float get_voice_rate_hz(int p_voice) const;
+
+ void set_voice_depth_ms(int p_voice,float p_depth_ms);
+ float get_voice_depth_ms(int p_voice) const;
+
+ void set_voice_level_db(int p_voice,float p_level_db);
+ float get_voice_level_db(int p_voice) const;
+
+ void set_voice_cutoff_hz(int p_voice,float p_cutoff_hz);
+ float get_voice_cutoff_hz(int p_voice) const;
+
+ void set_voice_pan(int p_voice,float p_pan);
+ float get_voice_pan(int p_voice) const;
+
+ void set_wet(float amount);
+ float get_wet() const;
+
+ void set_dry(float amount);
+ float get_dry() const;
+
+ Ref<AudioEffectInstance> instance();
+
+ AudioEffectChorus();
+};
+
+#endif // AUDIOEFFECTCHORUS_H
diff --git a/servers/audio/effects/audio_effect_compressor.cpp b/servers/audio/effects/audio_effect_compressor.cpp
new file mode 100644
index 0000000000..5d116a9543
--- /dev/null
+++ b/servers/audio/effects/audio_effect_compressor.cpp
@@ -0,0 +1,227 @@
+#include "audio_effect_compressor.h"
+#include "servers/audio_server.h"
+
+void AudioEffectCompressorInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+
+ float treshold = Math::db2linear(base->treshold);
+ float sample_rate=AudioServer::get_singleton()->get_mix_rate();
+
+ float ratatcoef = exp(-1 / (0.00001f * sample_rate));
+ float ratrelcoef = exp(-1 / (0.5f * sample_rate));
+ float attime = base->attack_us / 1000000.0;
+ float reltime = base->release_ms / 1000.0;
+ float atcoef = exp(-1 / (attime * sample_rate));
+ float relcoef = exp(-1 / (reltime * sample_rate));
+
+ float makeup = Math::db2linear(base->gain);
+
+ float mix = base->mix;
+ float gr_meter_decay = exp(1 / (1 * sample_rate));
+
+ const AudioFrame *src = p_src_frames;
+
+ if (base->sidechain!=StringName() && current_channel!=-1) {
+
+ int bus = AudioServer::get_singleton()->thread_find_bus_index(base->sidechain);
+ if (bus>=0) {
+ src = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus,current_channel);
+ }
+ }
+
+ for(int i=0;i<p_frame_count;i++) {
+
+ AudioFrame s = src[i];
+ //convert to positive
+ s.l = Math::abs(s.l);
+ s.r = Math::abs(s.r);
+
+ float peak = MAX(s.l,s.r);
+
+ float overdb = 2.08136898f * Math::linear2db(peak/treshold);
+
+ if (overdb<0.0) //we only care about what goes over to compress
+ overdb=0.0;
+
+ if(overdb-rundb>5) // diffeence is too large
+ averatio = 4;
+
+ if(overdb > rundb) {
+ rundb = overdb + atcoef * (rundb - overdb);
+ runratio = averatio + ratatcoef * (runratio - averatio);
+ } else {
+ rundb = overdb + relcoef * (rundb - overdb);
+ runratio = averatio + ratrelcoef * (runratio - averatio);
+ }
+
+ overdb = rundb;
+ averatio = runratio;
+
+ float cratio;
+
+ if(false) { //rato all-in
+ cratio = 12 + averatio;
+ } else {
+ cratio = base->ratio;
+ }
+
+ float gr = -overdb * (cratio-1)/cratio;
+ float grv = Math::db2linear(gr);
+
+ runmax = maxover + relcoef * (runmax - maxover); // highest peak for setting att/rel decays in reltime
+ maxover = runmax;
+
+ if (grv < gr_meter) {
+ gr_meter=grv;
+ } else {
+ gr_meter*=gr_meter_decay;
+ if(gr_meter>1)
+ gr_meter=1;
+ }
+
+
+ p_dst_frames[i] = p_src_frames[i] * grv * makeup * mix + p_src_frames[i] * (1.0-mix);
+
+ }
+
+}
+
+
+Ref<AudioEffectInstance> AudioEffectCompressor::instance() {
+ Ref<AudioEffectCompressorInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectCompressor>(this);
+ ins->rundb=0;
+ ins->runratio=0;
+ ins->averatio=0;
+ ins->runmax=0;
+ ins->maxover=0;
+ ins->gr_meter=1.0;
+ ins->current_channel=-1;
+ return ins;
+}
+
+
+void AudioEffectCompressor::set_treshold(float p_treshold) {
+
+ treshold=p_treshold;
+}
+
+float AudioEffectCompressor::get_treshold() const {
+
+ return treshold;
+}
+
+void AudioEffectCompressor::set_ratio(float p_ratio) {
+
+ ratio=p_ratio;
+}
+float AudioEffectCompressor::get_ratio() const {
+
+ return ratio;
+}
+
+void AudioEffectCompressor::set_gain(float p_gain) {
+
+ gain=p_gain;
+}
+float AudioEffectCompressor::get_gain() const {
+
+ return gain;
+}
+
+void AudioEffectCompressor::set_attack_us(float p_attack_us) {
+
+ attack_us=p_attack_us;
+}
+float AudioEffectCompressor::get_attack_us() const {
+
+ return attack_us;
+}
+
+void AudioEffectCompressor::set_release_ms(float p_release_ms) {
+
+ release_ms=p_release_ms;
+}
+float AudioEffectCompressor::get_release_ms() const {
+
+ return release_ms;
+}
+
+void AudioEffectCompressor::set_mix(float p_mix) {
+
+ mix=p_mix;
+}
+float AudioEffectCompressor::get_mix() const {
+
+ return mix;
+}
+
+void AudioEffectCompressor::set_sidechain(const StringName& p_sidechain) {
+
+ AudioServer::get_singleton()->lock();
+ sidechain=p_sidechain;
+ AudioServer::get_singleton()->unlock();
+}
+
+StringName AudioEffectCompressor::get_sidechain() const {
+
+ return sidechain;
+}
+
+void AudioEffectCompressor::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="sidechain") {
+
+ String buses="";
+ for(int i=0;i<AudioServer::get_singleton()->get_bus_count();i++) {
+ buses+=",";
+ buses+=AudioServer::get_singleton()->get_bus_name(i);
+ }
+
+ property.hint_string=buses;
+ }
+}
+
+void AudioEffectCompressor::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_treshold","treshold"),&AudioEffectCompressor::set_treshold);
+ ClassDB::bind_method(_MD("get_treshold"),&AudioEffectCompressor::get_treshold);
+
+ ClassDB::bind_method(_MD("set_ratio","ratio"),&AudioEffectCompressor::set_ratio);
+ ClassDB::bind_method(_MD("get_ratio"),&AudioEffectCompressor::get_ratio);
+
+ ClassDB::bind_method(_MD("set_gain","gain"),&AudioEffectCompressor::set_gain);
+ ClassDB::bind_method(_MD("get_gain"),&AudioEffectCompressor::get_gain);
+
+ ClassDB::bind_method(_MD("set_attack_us","attack_us"),&AudioEffectCompressor::set_attack_us);
+ ClassDB::bind_method(_MD("get_attack_us"),&AudioEffectCompressor::get_attack_us);
+
+ ClassDB::bind_method(_MD("set_release_ms","release_ms"),&AudioEffectCompressor::set_release_ms);
+ ClassDB::bind_method(_MD("get_release_ms"),&AudioEffectCompressor::get_release_ms);
+
+ ClassDB::bind_method(_MD("set_mix","mix"),&AudioEffectCompressor::set_mix);
+ ClassDB::bind_method(_MD("get_mix"),&AudioEffectCompressor::get_mix);
+
+ ClassDB::bind_method(_MD("set_sidechain","sidechain"),&AudioEffectCompressor::set_sidechain);
+ ClassDB::bind_method(_MD("get_sidechain"),&AudioEffectCompressor::get_sidechain);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"treshold",PROPERTY_HINT_RANGE,"-60,0,0.1"),_SCS("set_treshold"),_SCS("get_treshold"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"ratio",PROPERTY_HINT_RANGE,"1,48,0.1"),_SCS("set_ratio"),_SCS("get_ratio"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"gain",PROPERTY_HINT_RANGE,"-20,20,0.1"),_SCS("set_gain"),_SCS("get_gain"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"attack_us",PROPERTY_HINT_RANGE,"20,2000,1"),_SCS("set_attack_us"),_SCS("get_attack_us"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"release_ms",PROPERTY_HINT_RANGE,"20,2000,1"),_SCS("set_release_ms"),_SCS("get_release_ms"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"mix",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_mix"),_SCS("get_mix"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"sidechain",PROPERTY_HINT_ENUM),_SCS("set_sidechain"),_SCS("get_sidechain"));
+
+}
+
+AudioEffectCompressor::AudioEffectCompressor()
+{
+ treshold=0;
+ ratio=4;
+ gain=0;
+ attack_us=20;
+ release_ms=250;
+ mix=1;
+}
diff --git a/servers/audio/effects/audio_effect_compressor.h b/servers/audio/effects/audio_effect_compressor.h
new file mode 100644
index 0000000000..eb06b3db77
--- /dev/null
+++ b/servers/audio/effects/audio_effect_compressor.h
@@ -0,0 +1,70 @@
+#ifndef AUDIOEFFECTCOMPRESSOR_H
+#define AUDIOEFFECTCOMPRESSOR_H
+
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectCompressor;
+
+class AudioEffectCompressorInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectCompressorInstance,AudioEffectInstance)
+friend class AudioEffectCompressor;
+ Ref<AudioEffectCompressor> base;
+
+ float rundb,averatio,runratio,runmax,maxover,gr_meter;
+ int current_channel;
+public:
+
+ void set_current_channel(int p_channel) { current_channel=p_channel; }
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectCompressor : public AudioEffect {
+ GDCLASS(AudioEffectCompressor,AudioEffect)
+
+friend class AudioEffectCompressorInstance;
+ float treshold;
+ float ratio;
+ float gain;
+ float attack_us;
+ float release_ms;
+ float mix;
+ StringName sidechain;
+
+
+protected:
+ void _validate_property(PropertyInfo& property) const;
+ static void _bind_methods();
+public:
+
+
+ Ref<AudioEffectInstance> instance();
+
+
+ void set_treshold(float p_treshold);
+ float get_treshold() const;
+
+ void set_ratio(float p_ratio);
+ float get_ratio() const;
+
+ void set_gain(float p_gain);
+ float get_gain() const;
+
+ void set_attack_us(float p_attack_us);
+ float get_attack_us() const;
+
+ void set_release_ms(float p_release_ms);
+ float get_release_ms() const;
+
+ void set_mix(float p_mix);
+ float get_mix() const;
+
+ void set_sidechain(const StringName& p_sidechain);
+ StringName get_sidechain() const;
+
+ AudioEffectCompressor();
+};
+
+#endif // AUDIOEFFECTCOMPRESSOR_H
diff --git a/servers/audio/effects/audio_effect_delay.cpp b/servers/audio/effects/audio_effect_delay.cpp
new file mode 100644
index 0000000000..aae2657a63
--- /dev/null
+++ b/servers/audio/effects/audio_effect_delay.cpp
@@ -0,0 +1,326 @@
+#include "audio_effect_delay.h"
+#include "servers/audio_server.h"
+#include "math_funcs.h"
+
+void AudioEffectDelayInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+ int todo = p_frame_count;
+
+ while(todo) {
+
+ int to_mix = MIN(todo,256); //can't mix too much
+
+ _process_chunk(p_src_frames,p_dst_frames,to_mix);
+
+ p_src_frames+=to_mix;
+ p_dst_frames+=to_mix;
+
+ todo-=to_mix;
+ }
+}
+
+void AudioEffectDelayInstance::_process_chunk(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+
+
+ float main_level_f=base->dry;
+
+
+ float mix_rate = AudioServer::get_singleton()->get_mix_rate();
+
+ float tap_1_level_f=base->tap_1_active?Math::db2linear(base->tap_1_level):0.0;
+ int tap_1_delay_frames=int((base->tap_1_delay_ms/1000.0)*mix_rate);;
+
+ float tap_2_level_f=base->tap_2_active?Math::db2linear(base->tap_2_level):0.0;
+ int tap_2_delay_frames=int((base->tap_2_delay_ms/1000.0)*mix_rate);;
+
+ float feedback_level_f=base->feedback_active?Math::db2linear(base->feedback_level):0.0;
+ unsigned int feedback_delay_frames=int((base->feedback_delay_ms/1000.0)*mix_rate);;
+
+
+ AudioFrame tap1_vol=AudioFrame(tap_1_level_f,tap_1_level_f);
+
+ tap1_vol.l*=CLAMP( 1.0 - base->tap_1_pan, 0, 1);
+ tap1_vol.r*=CLAMP( 1.0 + base->tap_1_pan, 0, 1);
+
+ AudioFrame tap2_vol=AudioFrame(tap_2_level_f,tap_2_level_f);
+
+ tap2_vol.l*=CLAMP( 1.0 - base->tap_2_pan, 0, 1);
+ tap2_vol.r*=CLAMP( 1.0 + base->tap_2_pan, 0, 1);
+
+ // feedback lowpass here
+ float lpf_c=expf(-2.0*Math_PI*base->feedback_lowpass/mix_rate); // 0 .. 10khz
+ float lpf_ic=1.0-lpf_c;
+
+ const AudioFrame *src=p_src_frames;
+ AudioFrame *dst=p_dst_frames;
+ AudioFrame *rb_buf=ring_buffer.ptr();
+ AudioFrame *fb_buf=feedback_buffer.ptr();
+
+
+ for (int i=0;i<p_frame_count;i++) {
+
+
+ rb_buf[ring_buffer_pos&ring_buffer_mask]=src[i];
+
+ AudioFrame main_val=src[i]*main_level_f;
+ AudioFrame tap_1_val=rb_buf[(ring_buffer_pos-tap_1_delay_frames)&ring_buffer_mask]*tap1_vol;
+ AudioFrame tap_2_val=rb_buf[(ring_buffer_pos-tap_2_delay_frames)&ring_buffer_mask]*tap2_vol;
+
+ AudioFrame out=main_val+tap_1_val+tap_2_val;
+
+ out+=fb_buf[ feedback_buffer_pos ];
+
+ //apply lowpass and feedback gain
+ AudioFrame fb_in=out*feedback_level_f*lpf_ic+h*lpf_c;
+ fb_in.undenormalise(); //avoid denormals
+
+ h=fb_in;
+ fb_buf[ feedback_buffer_pos ]=fb_in;
+
+ dst[i]=out;
+
+ ring_buffer_pos++;
+
+ if ( (++feedback_buffer_pos) >= feedback_delay_frames )
+ feedback_buffer_pos=0;
+ }
+}
+
+
+
+Ref<AudioEffectInstance> AudioEffectDelay::instance() {
+ Ref<AudioEffectDelayInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectDelay>(this);
+
+ float ring_buffer_max_size=MAX_DELAY_MS+100; //add 100ms of extra room, just in case
+ ring_buffer_max_size/=1000.0;//convert to seconds
+ ring_buffer_max_size*=AudioServer::get_singleton()->get_mix_rate();
+
+ int ringbuff_size=ring_buffer_max_size;
+
+ int bits=0;
+
+ while(ringbuff_size>0) {
+ bits++;
+ ringbuff_size/=2;
+ }
+
+ ringbuff_size=1<<bits;
+ ins->ring_buffer_mask=ringbuff_size-1;
+ ins->ring_buffer_pos=0;
+
+ ins->ring_buffer.resize( ringbuff_size );
+ ins->feedback_buffer.resize( ringbuff_size );
+
+ ins->feedback_buffer_pos=0;
+
+ ins->h=AudioFrame(0,0);
+
+ return ins;
+}
+
+
+void AudioEffectDelay::set_dry(float p_dry) {
+
+ dry=p_dry;
+}
+
+float AudioEffectDelay::get_dry(){
+
+ return dry;
+}
+
+void AudioEffectDelay::set_tap1_active(bool p_active){
+
+ tap_1_active=p_active;
+}
+bool AudioEffectDelay::is_tap1_active() const{
+
+ return tap_1_active;
+}
+
+void AudioEffectDelay::set_tap1_delay_ms(float p_delay_ms){
+
+ tap_1_delay_ms=p_delay_ms;
+}
+float AudioEffectDelay::get_tap1_delay_ms() const{
+
+ return tap_1_delay_ms;
+}
+
+void AudioEffectDelay::set_tap1_level_db(float p_level_db){
+
+ tap_1_level=p_level_db;
+}
+float AudioEffectDelay::get_tap1_level_db() const{
+
+ return tap_1_level;
+}
+
+void AudioEffectDelay::set_tap1_pan(float p_pan){
+
+ tap_1_pan=p_pan;
+}
+float AudioEffectDelay::get_tap1_pan() const{
+
+ return tap_1_pan;
+}
+
+
+void AudioEffectDelay::set_tap2_active(bool p_active){
+
+ tap_2_active=p_active;
+}
+bool AudioEffectDelay::is_tap2_active() const{
+
+ return tap_2_active;
+}
+
+void AudioEffectDelay::set_tap2_delay_ms(float p_delay_ms){
+
+ tap_2_delay_ms=p_delay_ms;
+}
+float AudioEffectDelay::get_tap2_delay_ms() const{
+
+ return tap_2_delay_ms;
+}
+
+void AudioEffectDelay::set_tap2_level_db(float p_level_db){
+
+ tap_2_level=p_level_db;
+}
+float AudioEffectDelay::get_tap2_level_db() const{
+
+ return tap_2_level;
+}
+
+void AudioEffectDelay::set_tap2_pan(float p_pan){
+
+ tap_2_pan=p_pan;
+}
+float AudioEffectDelay::get_tap2_pan() const{
+
+ return tap_2_pan;
+}
+
+void AudioEffectDelay::set_feedback_active(bool p_active){
+
+ feedback_active=p_active;
+}
+bool AudioEffectDelay::is_feedback_active() const{
+
+ return feedback_active;
+}
+
+void AudioEffectDelay::set_feedback_delay_ms(float p_delay_ms){
+
+ feedback_delay_ms=p_delay_ms;
+}
+float AudioEffectDelay::get_feedback_delay_ms() const{
+
+ return feedback_delay_ms;
+}
+
+void AudioEffectDelay::set_feedback_level_db(float p_level_db){
+
+ feedback_level=p_level_db;
+}
+float AudioEffectDelay::get_feedback_level_db() const{
+
+ return feedback_level;
+}
+
+void AudioEffectDelay::set_feedback_lowpass(float p_lowpass){
+
+ feedback_lowpass=p_lowpass;
+}
+float AudioEffectDelay::get_feedback_lowpass() const{
+
+ return feedback_lowpass;
+}
+
+
+void AudioEffectDelay::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_dry","amount"),&AudioEffectDelay::set_dry);
+ ClassDB::bind_method(_MD("get_dry"),&AudioEffectDelay::get_dry);
+
+ ClassDB::bind_method(_MD("set_tap1_active","amount"),&AudioEffectDelay::set_tap1_active);
+ ClassDB::bind_method(_MD("is_tap1_active"),&AudioEffectDelay::is_tap1_active);
+
+ ClassDB::bind_method(_MD("set_tap1_delay_ms","amount"),&AudioEffectDelay::set_tap1_delay_ms);
+ ClassDB::bind_method(_MD("get_tap1_delay_ms"),&AudioEffectDelay::get_tap1_delay_ms);
+
+ ClassDB::bind_method(_MD("set_tap1_level_db","amount"),&AudioEffectDelay::set_tap1_level_db);
+ ClassDB::bind_method(_MD("get_tap1_level_db"),&AudioEffectDelay::get_tap1_level_db);
+
+ ClassDB::bind_method(_MD("set_tap1_pan","amount"),&AudioEffectDelay::set_tap1_pan);
+ ClassDB::bind_method(_MD("get_tap1_pan"),&AudioEffectDelay::get_tap1_pan);
+
+ ClassDB::bind_method(_MD("set_tap2_active","amount"),&AudioEffectDelay::set_tap2_active);
+ ClassDB::bind_method(_MD("is_tap2_active"),&AudioEffectDelay::is_tap2_active);
+
+ ClassDB::bind_method(_MD("set_tap2_delay_ms","amount"),&AudioEffectDelay::set_tap2_delay_ms);
+ ClassDB::bind_method(_MD("get_tap2_delay_ms"),&AudioEffectDelay::get_tap2_delay_ms);
+
+ ClassDB::bind_method(_MD("set_tap2_level_db","amount"),&AudioEffectDelay::set_tap2_level_db);
+ ClassDB::bind_method(_MD("get_tap2_level_db"),&AudioEffectDelay::get_tap2_level_db);
+
+ ClassDB::bind_method(_MD("set_tap2_pan","amount"),&AudioEffectDelay::set_tap2_pan);
+ ClassDB::bind_method(_MD("get_tap2_pan"),&AudioEffectDelay::get_tap2_pan);
+
+
+ ClassDB::bind_method(_MD("set_feedback_active","amount"),&AudioEffectDelay::set_feedback_active);
+ ClassDB::bind_method(_MD("is_feedback_active"),&AudioEffectDelay::is_feedback_active);
+
+ ClassDB::bind_method(_MD("set_feedback_delay_ms","amount"),&AudioEffectDelay::set_feedback_delay_ms);
+ ClassDB::bind_method(_MD("get_feedback_delay_ms"),&AudioEffectDelay::get_feedback_delay_ms);
+
+ ClassDB::bind_method(_MD("set_feedback_level_db","amount"),&AudioEffectDelay::set_feedback_level_db);
+ ClassDB::bind_method(_MD("get_feedback_level_db"),&AudioEffectDelay::get_feedback_level_db);
+
+ ClassDB::bind_method(_MD("set_feedback_lowpass","amount"),&AudioEffectDelay::set_feedback_lowpass);
+ ClassDB::bind_method(_MD("get_feedback_lowpass"),&AudioEffectDelay::get_feedback_lowpass);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"dry",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_dry"),_SCS("get_dry"));
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"tap1/active"),_SCS("set_tap1_active"),_SCS("is_tap1_active"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"tap1/delay_ms",PROPERTY_HINT_RANGE,"0,1500,1"),_SCS("set_tap1_delay_ms"),_SCS("get_tap1_delay_ms"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"tap1/level_db",PROPERTY_HINT_RANGE,"-60,0,0.01"),_SCS("set_tap1_level_db"),_SCS("get_tap1_level_db"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"tap1/pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_tap1_pan"),_SCS("get_tap1_pan"));
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"tap2/active"),_SCS("set_tap2_active"),_SCS("is_tap2_active"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"tap2/delay_ms",PROPERTY_HINT_RANGE,"0,1500,1"),_SCS("set_tap2_delay_ms"),_SCS("get_tap2_delay_ms"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"tap2/level_db",PROPERTY_HINT_RANGE,"-60,0,0.01"),_SCS("set_tap2_level_db"),_SCS("get_tap2_level_db"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"tap2/pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_tap2_pan"),_SCS("get_tap2_pan"));
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"feedback/active"),_SCS("set_feedback_active"),_SCS("is_feedback_active"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"feedback/delay_ms",PROPERTY_HINT_RANGE,"0,1500,1"),_SCS("set_feedback_delay_ms"),_SCS("get_feedback_delay_ms"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"feedback/level_db",PROPERTY_HINT_RANGE,"-60,0,0.01"),_SCS("set_feedback_level_db"),_SCS("get_feedback_level_db"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"feedback/lowpass",PROPERTY_HINT_RANGE,"1,16000,1"),_SCS("set_feedback_lowpass"),_SCS("get_feedback_lowpass"));
+
+
+}
+
+AudioEffectDelay::AudioEffectDelay()
+{
+ tap_1_active=true;
+ tap_1_delay_ms=250;
+ tap_1_level=-6;
+ tap_1_pan=0.2;
+
+ tap_2_active=true;
+ tap_2_delay_ms=500;
+ tap_2_level=-12;
+ tap_2_pan=-0.4;
+
+ feedback_active=false;
+ feedback_delay_ms=340;
+ feedback_level=-6;
+ feedback_lowpass=16000;
+
+ dry=1.0;
+
+}
diff --git a/servers/audio/effects/audio_effect_delay.h b/servers/audio/effects/audio_effect_delay.h
new file mode 100644
index 0000000000..645561138b
--- /dev/null
+++ b/servers/audio/effects/audio_effect_delay.h
@@ -0,0 +1,112 @@
+#ifndef AUDIOEFFECTECHO_H
+#define AUDIOEFFECTECHO_H
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectDelay;
+
+class AudioEffectDelayInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectDelayInstance,AudioEffectInstance)
+friend class AudioEffectDelay;
+ Ref<AudioEffectDelay> base;
+
+ Vector<AudioFrame> ring_buffer;
+
+ unsigned int ring_buffer_pos;
+ unsigned int ring_buffer_mask;
+
+ /* feedback buffer */
+ Vector<AudioFrame> feedback_buffer;
+
+ unsigned int feedback_buffer_pos;
+
+ AudioFrame h;
+ void _process_chunk(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectDelay : public AudioEffect {
+ GDCLASS(AudioEffectDelay,AudioEffect)
+
+friend class AudioEffectDelayInstance;
+ enum {
+
+ MAX_DELAY_MS=3000,
+ MAX_TAPS=2
+ };
+
+ float dry;
+
+ bool tap_1_active;
+ float tap_1_delay_ms;
+ float tap_1_level;
+ float tap_1_pan;
+
+ bool tap_2_active;
+ float tap_2_delay_ms;
+ float tap_2_level;
+ float tap_2_pan;
+
+ bool feedback_active;
+ float feedback_delay_ms;
+ float feedback_level;
+ float feedback_lowpass;
+
+
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ void set_dry(float p_dry);
+ float get_dry();
+
+ void set_tap1_active(bool p_active);
+ bool is_tap1_active() const;
+
+ void set_tap1_delay_ms(float p_delay_ms);
+ float get_tap1_delay_ms() const;
+
+ void set_tap1_level_db(float p_level_db);
+ float get_tap1_level_db() const;
+
+ void set_tap1_pan(float p_pan);
+ float get_tap1_pan() const;
+
+ void set_tap2_active(bool p_active);
+ bool is_tap2_active() const;
+
+ void set_tap2_delay_ms(float p_delay_ms);
+ float get_tap2_delay_ms() const;
+
+ void set_tap2_level_db(float p_level_db);
+ float get_tap2_level_db() const;
+
+ void set_tap2_pan(float p_pan);
+ float get_tap2_pan() const;
+
+ void set_feedback_active(bool p_active);
+ bool is_feedback_active() const;
+
+ void set_feedback_delay_ms(float p_delay_ms);
+ float get_feedback_delay_ms() const;
+
+ void set_feedback_level_db(float p_level_db);
+ float get_feedback_level_db() const;
+
+ void set_feedback_lowpass(float p_lowpass);
+ float get_feedback_lowpass() const;
+
+ Ref<AudioEffectInstance> instance();
+
+ AudioEffectDelay();
+};
+
+
+#endif // AUDIOEFFECTECHO_H
diff --git a/servers/audio/effects/audio_effect_distortion.cpp b/servers/audio/effects/audio_effect_distortion.cpp
new file mode 100644
index 0000000000..3ba409b0a5
--- /dev/null
+++ b/servers/audio/effects/audio_effect_distortion.cpp
@@ -0,0 +1,171 @@
+#include "audio_effect_distortion.h"
+#include "servers/audio_server.h"
+#include "math_funcs.h"
+
+
+
+void AudioEffectDistortionInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+ const float *src = (const float*)p_src_frames;
+ float *dst = (float*)p_dst_frames;
+
+ //float lpf_c=expf(-2.0*Math_PI*keep_hf_hz.get()/(mix_rate*(float)OVERSAMPLE));
+ float lpf_c=expf(-2.0*Math_PI*base->keep_hf_hz/(AudioServer::get_singleton()->get_mix_rate()));
+ float lpf_ic=1.0-lpf_c;
+
+ float drive_f=base->drive;
+ float pregain_f=Math::db2linear(base->pre_gain);
+ float postgain_f=Math::db2linear(base->post_gain);
+
+ float atan_mult=pow(10,drive_f*drive_f*3.0)-1.0+0.001;
+ float atan_div=1.0/(atanf(atan_mult)*(1.0+drive_f*8));
+
+ float lofi_mult=powf(2.0,2.0+(1.0-drive_f)*14); //goes from 16 to 2 bits
+
+ for (int i=0;i<p_frame_count*2;i++) {
+
+ float out=undenormalise(src[i]*lpf_ic+lpf_c*h[i&1]);
+ h[i&1]=out;
+ float a=out;
+ float ha=src[i]-out; //high freqs
+ a*=pregain_f;
+
+ switch (base->mode) {
+
+ case AudioEffectDistortion::MODE_CLIP: {
+
+ a=powf(a,1.0001-drive_f);
+ if (a>1.0)
+ a=1.0;
+ else if (a<(-1.0))
+ a=-1.0;
+
+ } break;
+ case AudioEffectDistortion::MODE_ATAN: {
+
+
+ a=atanf(a*atan_mult)*atan_div;
+
+ } break;
+ case AudioEffectDistortion::MODE_LOFI: {
+
+ a = floorf(a*lofi_mult+0.5)/lofi_mult;
+
+ } break;
+ case AudioEffectDistortion::MODE_OVERDRIVE: {
+
+
+ const double x = a * 0.686306;
+ const double z = 1 + exp (sqrt (fabs (x)) * -0.75);
+ a = (expf(x) - expf(-x * z)) / (expf(x) + expf(-x));
+ } break;
+ case AudioEffectDistortion::MODE_WAVESHAPE: {
+ float x = a;
+ float k= 2*drive_f/(1.00001-drive_f);
+
+ a = (1.0+k)*x/(1.0+k*fabsf(x));
+
+
+ } break;
+ }
+
+ dst[i]=a*postgain_f+ha;
+
+ }
+
+
+}
+
+
+Ref<AudioEffectInstance> AudioEffectDistortion::instance() {
+ Ref<AudioEffectDistortionInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectDistortion>(this);
+ ins->h[0]=0;
+ ins->h[1]=0;
+
+ return ins;
+}
+
+
+void AudioEffectDistortion::set_mode(Mode p_mode) {
+
+ mode=p_mode;
+}
+
+AudioEffectDistortion::Mode AudioEffectDistortion::get_mode() const{
+
+ return mode;
+}
+
+void AudioEffectDistortion::set_pre_gain(float p_pre_gain){
+
+ pre_gain=p_pre_gain;
+}
+float AudioEffectDistortion::get_pre_gain() const{
+
+ return pre_gain;
+}
+
+void AudioEffectDistortion::set_keep_hf_hz(float p_keep_hf_hz){
+
+ keep_hf_hz=p_keep_hf_hz;
+}
+float AudioEffectDistortion::get_keep_hf_hz() const{
+
+ return keep_hf_hz;
+}
+
+void AudioEffectDistortion::set_drive(float p_drive){
+
+ drive=p_drive;
+}
+float AudioEffectDistortion::get_drive() const{
+
+ return drive;
+}
+
+void AudioEffectDistortion::set_post_gain(float p_post_gain){
+
+ post_gain=p_post_gain;
+}
+float AudioEffectDistortion::get_post_gain() const{
+
+ return post_gain;
+}
+
+
+void AudioEffectDistortion::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_mode","mode"),&AudioEffectDistortion::set_mode);
+ ClassDB::bind_method(_MD("get_mode"),&AudioEffectDistortion::get_mode);
+
+ ClassDB::bind_method(_MD("set_pre_gain","pre_gain"),&AudioEffectDistortion::set_pre_gain);
+ ClassDB::bind_method(_MD("get_pre_gain"),&AudioEffectDistortion::get_pre_gain);
+
+ ClassDB::bind_method(_MD("set_keep_hf_hz","keep_hf_hz"),&AudioEffectDistortion::set_keep_hf_hz);
+ ClassDB::bind_method(_MD("get_keep_hf_hz"),&AudioEffectDistortion::get_keep_hf_hz);
+
+ ClassDB::bind_method(_MD("set_drive","drive"),&AudioEffectDistortion::set_drive);
+ ClassDB::bind_method(_MD("get_drive"),&AudioEffectDistortion::get_drive);
+
+
+ ClassDB::bind_method(_MD("set_post_gain","post_gain"),&AudioEffectDistortion::set_post_gain);
+ ClassDB::bind_method(_MD("get_post_gain"),&AudioEffectDistortion::get_post_gain);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Clip,ATan,LoFi,Overdrive,WaveShape"),_SCS("set_mode"),_SCS("get_mode"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"pre_gain",PROPERTY_HINT_RANGE,"-60,60,0.01"),_SCS("set_pre_gain"),_SCS("get_pre_gain"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"keep_hf_hz",PROPERTY_HINT_RANGE,"1,20000,1"),_SCS("set_keep_hf_hz"),_SCS("get_keep_hf_hz"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"drive",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drive"),_SCS("get_drive"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"post_gain",PROPERTY_HINT_RANGE,"-80,24,0.01"),_SCS("set_post_gain"),_SCS("get_post_gain"));
+}
+
+AudioEffectDistortion::AudioEffectDistortion()
+{
+ mode=MODE_CLIP;
+ pre_gain=0;
+ post_gain=0;
+ keep_hf_hz=16000;
+ drive=0;
+}
+
diff --git a/servers/audio/effects/audio_effect_distortion.h b/servers/audio/effects/audio_effect_distortion.h
new file mode 100644
index 0000000000..1d2433faeb
--- /dev/null
+++ b/servers/audio/effects/audio_effect_distortion.h
@@ -0,0 +1,69 @@
+#ifndef AUDIOEFFECTDISTORTION_H
+#define AUDIOEFFECTDISTORTION_H
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectDistortion;
+
+class AudioEffectDistortionInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectDistortionInstance,AudioEffectInstance)
+friend class AudioEffectDistortion;
+ Ref<AudioEffectDistortion> base;
+ float h[2];
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectDistortion : public AudioEffect {
+ GDCLASS(AudioEffectDistortion,AudioEffect)
+public:
+ enum Mode {
+ MODE_CLIP,
+ MODE_ATAN,
+ MODE_LOFI,
+ MODE_OVERDRIVE,
+ MODE_WAVESHAPE,
+ };
+
+friend class AudioEffectDistortionInstance;
+ Mode mode;
+ float pre_gain;
+ float post_gain;
+ float keep_hf_hz;
+ float drive;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+
+ Ref<AudioEffectInstance> instance();
+
+
+ void set_mode(Mode p_mode);
+ Mode get_mode() const;
+
+ void set_pre_gain(float pre_gain);
+ float get_pre_gain() const;
+
+ void set_keep_hf_hz(float keep_hf_hz);
+ float get_keep_hf_hz() const;
+
+ void set_drive(float drive);
+ float get_drive() const;
+
+ void set_post_gain(float post_gain);
+ float get_post_gain() const;
+
+
+
+ AudioEffectDistortion();
+};
+
+VARIANT_ENUM_CAST( AudioEffectDistortion::Mode )
+
+#endif // AUDIOEFFECTDISTORTION_H
diff --git a/servers/audio/effects/audio_effect_eq.cpp b/servers/audio/effects/audio_effect_eq.cpp
new file mode 100644
index 0000000000..3c6a684224
--- /dev/null
+++ b/servers/audio/effects/audio_effect_eq.cpp
@@ -0,0 +1,122 @@
+#include "audio_effect_eq.h"
+#include "servers/audio_server.h"
+
+
+void AudioEffectEQInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+ int band_count = bands[0].size();
+ EQ::BandProcess *proc_l = bands[0].ptr();
+ EQ::BandProcess *proc_r = bands[1].ptr();
+ float *bgain = gains.ptr();
+ for(int i=0;i<band_count;i++) {
+ bgain[i]=Math::db2linear(base->gain[i]);
+ }
+
+
+ for(int i=0;i<p_frame_count;i++) {
+
+ AudioFrame src = p_src_frames[i];
+ AudioFrame dst = AudioFrame(0,0);
+
+ for(int j=0;j<band_count;j++) {
+
+ float l = src.l;
+ float r = src.r;
+
+ proc_l[j].process_one(l);
+ proc_r[j].process_one(r);
+
+ dst.l+=l * bgain[j];
+ dst.r+=r * bgain[j];
+ }
+
+ p_dst_frames[i]=dst;
+ }
+
+}
+
+
+Ref<AudioEffectInstance> AudioEffectEQ::instance() {
+ Ref<AudioEffectEQInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectEQ>(this);
+ ins->gains.resize(eq.get_band_count());
+ for(int i=0;i<2;i++) {
+ ins->bands[i].resize(eq.get_band_count());
+ for(int j=0;j<ins->bands[i].size();j++) {
+ ins->bands[i][j]=eq.get_band_processor(j);
+ }
+ }
+
+ return ins;
+}
+
+void AudioEffectEQ::set_band_gain_db(int p_band,float p_volume) {
+ ERR_FAIL_INDEX(p_band,gain.size());
+ gain[p_band]=p_volume;
+}
+
+float AudioEffectEQ::get_band_gain_db(int p_band) const {
+ ERR_FAIL_INDEX_V(p_band,gain.size(),0);
+
+ return gain[p_band];
+}
+int AudioEffectEQ::get_band_count() const {
+ return gain.size();
+}
+
+bool AudioEffectEQ::_set(const StringName& p_name, const Variant& p_value) {
+
+ const Map<StringName,int>::Element *E=prop_band_map.find(p_name);
+ if (E) {
+ set_band_gain_db(E->get(),p_value);
+ return true;
+ }
+
+ return false;
+}
+
+bool AudioEffectEQ::_get(const StringName& p_name,Variant &r_ret) const{
+
+ const Map<StringName,int>::Element *E=prop_band_map.find(p_name);
+ if (E) {
+ r_ret=get_band_gain_db(E->get());
+ return true;
+ }
+
+ return false;
+
+}
+
+void AudioEffectEQ::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ for(int i=0;i<band_names.size();i++) {
+
+ p_list->push_back(PropertyInfo(Variant::REAL,band_names[i],PROPERTY_HINT_RANGE,"-60,24,0.1"));
+ }
+}
+
+
+
+void AudioEffectEQ::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_band_gain_db","band_idx","volume_db"),&AudioEffectEQ::set_band_gain_db);
+ ClassDB::bind_method(_MD("get_band_gain_db","band_idx"),&AudioEffectEQ::get_band_gain_db);
+ ClassDB::bind_method(_MD("get_band_count"),&AudioEffectEQ::get_band_count);
+
+}
+
+AudioEffectEQ::AudioEffectEQ(EQ::Preset p_preset)
+{
+
+
+ eq.set_mix_rate(AudioServer::get_singleton()->get_mix_rate());
+ eq.set_preset_band_mode(p_preset);
+ gain.resize(eq.get_band_count());
+ for(int i=0;i<gain.size();i++) {
+ gain[i]=0.0;
+ String name = "band_db/"+itos(eq.get_band_frequency(i))+"_hz";
+ prop_band_map[name]=i;
+ band_names.push_back(name);
+ }
+}
diff --git a/servers/audio/effects/audio_effect_eq.h b/servers/audio/effects/audio_effect_eq.h
new file mode 100644
index 0000000000..3fcc2c0056
--- /dev/null
+++ b/servers/audio/effects/audio_effect_eq.h
@@ -0,0 +1,72 @@
+#ifndef AUDIOEFFECTEQ_H
+#define AUDIOEFFECTEQ_H
+
+
+#include "servers/audio/audio_effect.h"
+#include "servers/audio/effects/eq.h"
+
+class AudioEffectEQ;
+
+class AudioEffectEQInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectEQInstance,AudioEffectInstance)
+friend class AudioEffectEQ;
+ Ref<AudioEffectEQ> base;
+
+ Vector<EQ::BandProcess> bands[2];
+ Vector<float> gains;
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectEQ : public AudioEffect {
+ GDCLASS(AudioEffectEQ,AudioEffect)
+
+friend class AudioEffectEQInstance;
+
+ EQ eq;
+ Vector<float> gain;
+ Map<StringName,int> prop_band_map;
+ Vector<String> band_names;
+
+protected:
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+
+
+ static void _bind_methods();
+public:
+
+
+ Ref<AudioEffectInstance> instance();
+ void set_band_gain_db(int p_band,float p_volume);
+ float get_band_gain_db(int p_band) const;
+ int get_band_count() const;
+
+ AudioEffectEQ(EQ::Preset p_preset=EQ::PRESET_6_BANDS);
+};
+
+
+class AudioEffectEQ6 : public AudioEffectEQ {
+ GDCLASS(AudioEffectEQ6,AudioEffectEQ)
+public:
+ AudioEffectEQ6() : AudioEffectEQ(EQ::PRESET_6_BANDS) {}
+};
+
+class AudioEffectEQ10 : public AudioEffectEQ {
+ GDCLASS(AudioEffectEQ10,AudioEffectEQ)
+public:
+ AudioEffectEQ10() : AudioEffectEQ(EQ::PRESET_10_BANDS) {}
+};
+
+class AudioEffectEQ21 : public AudioEffectEQ {
+ GDCLASS(AudioEffectEQ21,AudioEffectEQ)
+public:
+ AudioEffectEQ21() : AudioEffectEQ(EQ::PRESET_21_BANDS) {}
+};
+
+#endif // AUDIOEFFECTEQ_H
diff --git a/servers/audio/effects/audio_effect_filter.cpp b/servers/audio/effects/audio_effect_filter.cpp
new file mode 100644
index 0000000000..4e54ea1f3e
--- /dev/null
+++ b/servers/audio/effects/audio_effect_filter.cpp
@@ -0,0 +1,151 @@
+#include "audio_effect_filter.h"
+#include "servers/audio_server.h"
+
+template<int S>
+void AudioEffectFilterInstance::_process_filter(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+ for(int i=0;i<p_frame_count;i++) {
+ float f = p_src_frames[i].l;
+ filter_process[0][0].process_one(f);
+ if (S>1)
+ filter_process[0][1].process_one(f);
+ if (S>2)
+ filter_process[0][2].process_one(f);
+ if (S>3)
+ filter_process[0][3].process_one(f);
+
+ p_dst_frames[i].l=f;
+ }
+
+ for(int i=0;i<p_frame_count;i++) {
+ float f = p_src_frames[i].r;
+ filter_process[1][0].process_one(f);
+ if (S>1)
+ filter_process[1][1].process_one(f);
+ if (S>2)
+ filter_process[1][2].process_one(f);
+ if (S>3)
+ filter_process[1][3].process_one(f);
+
+ p_dst_frames[i].r=f;
+ }
+
+}
+
+void AudioEffectFilterInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+ filter.set_cutoff(base->cutoff);
+ filter.set_gain(base->gain);
+ filter.set_resonance(base->resonance);
+ filter.set_mode(base->mode);
+ int stages = int(base->db)+1;
+ filter.set_stages(stages);
+ filter.set_sampling_rate(AudioServer::get_singleton()->get_mix_rate());
+
+ for(int i=0;i<2;i++) {
+ for(int j=0;j<4;j++) {
+ filter_process[i][j].update_coeffs();
+ }
+ }
+
+
+ if (stages==1) {
+ _process_filter<1>(p_src_frames,p_dst_frames,p_frame_count);
+ } else if (stages==2) {
+ _process_filter<2>(p_src_frames,p_dst_frames,p_frame_count);
+ } else if (stages==3) {
+ _process_filter<3>(p_src_frames,p_dst_frames,p_frame_count);
+ } else if (stages==4) {
+ _process_filter<4>(p_src_frames,p_dst_frames,p_frame_count);
+ }
+
+}
+
+
+AudioEffectFilterInstance::AudioEffectFilterInstance() {
+
+ for(int i=0;i<2;i++) {
+ for(int j=0;j<4;j++) {
+ filter_process[i][j].set_filter(&filter);
+ }
+ }
+
+}
+
+
+Ref<AudioEffectInstance> AudioEffectFilter::instance() {
+ Ref<AudioEffectFilterInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectFilter>(this);
+
+ return ins;
+}
+
+void AudioEffectFilter::set_cutoff(float p_freq) {
+
+ cutoff=p_freq;
+}
+
+float AudioEffectFilter::get_cutoff() const{
+
+ return cutoff;
+}
+
+void AudioEffectFilter::set_resonance(float p_amount){
+
+ resonance=p_amount;
+}
+float AudioEffectFilter::get_resonance() const{
+
+ return resonance;
+}
+
+void AudioEffectFilter::set_gain(float p_amount){
+
+ gain=p_amount;
+}
+float AudioEffectFilter::get_gain() const {
+
+ return gain;
+}
+
+
+
+void AudioEffectFilter::set_db(FilterDB p_db) {
+ db=p_db;
+}
+
+AudioEffectFilter::FilterDB AudioEffectFilter::get_db() const {
+
+ return db;
+}
+
+void AudioEffectFilter::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_cutoff","freq"),&AudioEffectFilter::set_cutoff);
+ ClassDB::bind_method(_MD("get_cutoff"),&AudioEffectFilter::get_cutoff);
+
+ ClassDB::bind_method(_MD("set_resonance","amount"),&AudioEffectFilter::set_resonance);
+ ClassDB::bind_method(_MD("get_resonance"),&AudioEffectFilter::get_resonance);
+
+ ClassDB::bind_method(_MD("set_gain","amount"),&AudioEffectFilter::set_gain);
+ ClassDB::bind_method(_MD("get_gain"),&AudioEffectFilter::get_gain);
+
+ ClassDB::bind_method(_MD("set_db","amount"),&AudioEffectFilter::set_db);
+ ClassDB::bind_method(_MD("get_db"),&AudioEffectFilter::get_db);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"cutoff_hz",PROPERTY_HINT_RANGE,"1,40000,0.1"),_SCS("set_cutoff"),_SCS("get_cutoff"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"resonance",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_resonance"),_SCS("get_resonance"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"gain",PROPERTY_HINT_RANGE,"0,4,0.01"),_SCS("set_gain"),_SCS("get_gain"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"dB",PROPERTY_HINT_ENUM,"6db,12db,18db,24db"),_SCS("set_db"),_SCS("get_db"));
+}
+
+AudioEffectFilter::AudioEffectFilter(AudioFilterSW::Mode p_mode)
+{
+
+ mode=p_mode;
+ cutoff=2000;
+ resonance=0.5;
+ gain=1.0;
+ db=FILTER_6DB;
+}
diff --git a/servers/audio/effects/audio_effect_filter.h b/servers/audio/effects/audio_effect_filter.h
new file mode 100644
index 0000000000..d0bc7a446a
--- /dev/null
+++ b/servers/audio/effects/audio_effect_filter.h
@@ -0,0 +1,125 @@
+#ifndef AUDIOEFFECTFILTER_H
+#define AUDIOEFFECTFILTER_H
+
+#include "servers/audio/audio_effect.h"
+#include "servers/audio/audio_filter_sw.h"
+
+class AudioEffectFilter;
+
+class AudioEffectFilterInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectFilterInstance,AudioEffectInstance)
+friend class AudioEffectFilter;
+
+ Ref<AudioEffectFilter> base;
+
+ AudioFilterSW filter;
+ AudioFilterSW::Processor filter_process[2][4];
+
+ template<int S>
+ void _process_filter(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+ AudioEffectFilterInstance();
+};
+
+
+class AudioEffectFilter : public AudioEffect {
+ GDCLASS(AudioEffectFilter,AudioEffect)
+public:
+
+ enum FilterDB {
+ FILTER_6DB,
+ FILTER_12DB,
+ FILTER_18DB,
+ FILTER_24DB,
+ };
+ friend class AudioEffectFilterInstance;
+
+ AudioFilterSW::Mode mode;
+ float cutoff;
+ float resonance;
+ float gain;
+ FilterDB db;
+
+
+protected:
+
+
+ static void _bind_methods();
+public:
+
+ void set_cutoff(float p_freq);
+ float get_cutoff() const;
+
+ void set_resonance(float p_amount);
+ float get_resonance() const;
+
+ void set_gain(float p_amount);
+ float get_gain() const;
+
+ void set_db(FilterDB p_db);
+ FilterDB get_db() const;
+
+ Ref<AudioEffectInstance> instance();
+
+ AudioEffectFilter(AudioFilterSW::Mode p_mode=AudioFilterSW::LOWPASS);
+};
+
+VARIANT_ENUM_CAST(AudioEffectFilter::FilterDB)
+
+class AudioEffectLowPassFilter : public AudioEffectFilter {
+ GDCLASS(AudioEffectLowPassFilter,AudioEffectFilter)
+public:
+
+ AudioEffectLowPassFilter() : AudioEffectFilter(AudioFilterSW::LOWPASS) {}
+};
+
+class AudioEffectHighPassFilter : public AudioEffectFilter {
+ GDCLASS(AudioEffectHighPassFilter,AudioEffectFilter)
+public:
+
+ AudioEffectHighPassFilter() : AudioEffectFilter(AudioFilterSW::HIGHPASS) {}
+};
+
+class AudioEffectBandPassFilter : public AudioEffectFilter {
+ GDCLASS(AudioEffectBandPassFilter,AudioEffectFilter)
+public:
+
+ AudioEffectBandPassFilter() : AudioEffectFilter(AudioFilterSW::BANDPASS) {}
+};
+
+class AudioEffectNotchFilter : public AudioEffectFilter {
+ GDCLASS(AudioEffectNotchFilter,AudioEffectFilter)
+public:
+
+ AudioEffectNotchFilter() : AudioEffectFilter(AudioFilterSW::NOTCH) {}
+};
+
+class AudioEffectBandLimitFilter : public AudioEffectFilter {
+ GDCLASS(AudioEffectBandLimitFilter,AudioEffectFilter)
+public:
+
+ AudioEffectBandLimitFilter() : AudioEffectFilter(AudioFilterSW::BANDLIMIT) {}
+};
+
+
+class AudioEffectLowShelfFilter : public AudioEffectFilter {
+ GDCLASS(AudioEffectLowShelfFilter,AudioEffectFilter)
+public:
+
+ AudioEffectLowShelfFilter() : AudioEffectFilter(AudioFilterSW::LOWSHELF) {}
+};
+
+
+class AudioEffectHighShelfFilter : public AudioEffectFilter {
+ GDCLASS(AudioEffectHighShelfFilter,AudioEffectFilter)
+public:
+
+ AudioEffectHighShelfFilter() : AudioEffectFilter(AudioFilterSW::HIGHSHELF) {}
+};
+
+
+
+#endif // AUDIOEFFECTFILTER_H
diff --git a/servers/audio/effects/audio_effect_limiter.cpp b/servers/audio/effects/audio_effect_limiter.cpp
new file mode 100644
index 0000000000..5cd02682ab
--- /dev/null
+++ b/servers/audio/effects/audio_effect_limiter.cpp
@@ -0,0 +1,124 @@
+#include "audio_effect_limiter.h"
+
+void AudioEffectLimiterInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+ float thresh = Math::db2linear(base->treshold);
+ float threshdb = base->treshold;
+ float ceiling = Math::db2linear(base->ceiling);
+ float ceildb = base->ceiling;
+ float makeup = Math::db2linear(ceildb - threshdb);
+ float makeupdb = ceildb - threshdb;
+ float sc = -base->soft_clip;
+ float scv = Math::db2linear(sc);
+ float sccomp = Math::db2linear(-sc);
+ float peakdb = ceildb + 25;
+ float peaklvl = Math::db2linear(peakdb);
+ float scratio = base->soft_clip_ratio;
+ float scmult = Math::abs((ceildb - sc) / (peakdb - sc));
+
+ for(int i=0;i<p_frame_count;i++) {
+
+ float spl0 = p_src_frames[i].l;
+ float spl1 = p_src_frames[i].r;
+ spl0 = spl0 * makeup;
+ spl1 = spl1 * makeup;
+ float sign0 = (spl0 < 0.0 ? -1.0 : 1.0 );
+ float sign1 = (spl1 < 0.0 ? -1.0 : 1.0 );
+ float abs0 = Math::abs(spl0);
+ float abs1 = Math::abs(spl1);
+ float overdb0 = Math::linear2db(abs0) - ceildb;
+ float overdb1 = Math::linear2db(abs1) - ceildb;
+
+ if (abs0 > scv)
+ {
+ spl0 = sign0 * (scv + Math::db2linear(overdb0 * scmult));
+ }
+ if (abs1 > scv)
+ {
+ spl1 = sign1 * (scv + Math::db2linear(overdb1 * scmult));
+ }
+
+ spl0 = MIN(ceiling, Math::abs(spl0)) * (spl0 < 0.0 ? -1.0 : 1.0);
+ spl1 = MIN(ceiling, Math::abs(spl1)) * (spl1 < 0.0 ? -1.0 : 1.0);
+
+ p_dst_frames[i].l = spl0;
+ p_dst_frames[i].r = spl1;
+ }
+
+}
+
+
+Ref<AudioEffectInstance> AudioEffectLimiter::instance() {
+ Ref<AudioEffectLimiterInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectLimiter>(this);
+
+ return ins;
+}
+
+
+void AudioEffectLimiter::set_treshold_db(float p_treshold) {
+
+ treshold=p_treshold;
+}
+
+float AudioEffectLimiter::get_treshold_db() const{
+
+ return treshold;
+}
+
+void AudioEffectLimiter::set_ceiling_db(float p_ceiling){
+
+ ceiling=p_ceiling;
+}
+float AudioEffectLimiter::get_ceiling_db() const{
+
+ return ceiling;
+}
+
+void AudioEffectLimiter::set_soft_clip_db(float p_soft_clip){
+
+ soft_clip=p_soft_clip;
+}
+float AudioEffectLimiter::get_soft_clip_db() const{
+
+ return soft_clip;
+}
+
+void AudioEffectLimiter::set_soft_clip_ratio(float p_soft_clip){
+
+ soft_clip_ratio=p_soft_clip;
+}
+float AudioEffectLimiter::get_soft_clip_ratio() const{
+
+ return soft_clip;
+}
+
+
+void AudioEffectLimiter::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_ceiling_db","ceiling"),&AudioEffectLimiter::set_ceiling_db);
+ ClassDB::bind_method(_MD("get_ceiling_db"),&AudioEffectLimiter::get_ceiling_db);
+
+ ClassDB::bind_method(_MD("set_treshold_db","treshold"),&AudioEffectLimiter::set_treshold_db);
+ ClassDB::bind_method(_MD("get_treshold_db"),&AudioEffectLimiter::get_treshold_db);
+
+ ClassDB::bind_method(_MD("set_soft_clip_db","soft_clip"),&AudioEffectLimiter::set_soft_clip_db);
+ ClassDB::bind_method(_MD("get_soft_clip_db"),&AudioEffectLimiter::get_soft_clip_db);
+
+ ClassDB::bind_method(_MD("set_soft_clip_ratio","soft_clip"),&AudioEffectLimiter::set_soft_clip_ratio);
+ ClassDB::bind_method(_MD("get_soft_clip_ratio"),&AudioEffectLimiter::get_soft_clip_ratio);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"ceiling_db",PROPERTY_HINT_RANGE,"-20,-0.1,0.1"),_SCS("set_ceiling_db"),_SCS("get_ceiling_db"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"treshold_db",PROPERTY_HINT_RANGE,"-30,0,0.1"),_SCS("set_treshold_db"),_SCS("get_treshold_db"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"soft_clip_db",PROPERTY_HINT_RANGE,"0,6,0.1"),_SCS("set_soft_clip_db"),_SCS("get_soft_clip_db"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"soft_clip_ratio",PROPERTY_HINT_RANGE,"3,20,0.1"),_SCS("set_soft_clip_ratio"),_SCS("get_soft_clip_ratio"));
+}
+
+AudioEffectLimiter::AudioEffectLimiter()
+{
+ treshold=0;
+ ceiling=-0.1;
+ soft_clip=2;
+ soft_clip_ratio=10;
+}
diff --git a/servers/audio/effects/audio_effect_limiter.h b/servers/audio/effects/audio_effect_limiter.h
new file mode 100644
index 0000000000..b0d7321205
--- /dev/null
+++ b/servers/audio/effects/audio_effect_limiter.h
@@ -0,0 +1,58 @@
+#ifndef AUDIO_EFFECT_LIMITER_H
+#define AUDIO_EFFECT_LIMITER_H
+
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectLimiter;
+
+class AudioEffectLimiterInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectLimiterInstance,AudioEffectInstance)
+friend class AudioEffectLimiter;
+ Ref<AudioEffectLimiter> base;
+
+ float mix_volume_db;
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectLimiter : public AudioEffect {
+ GDCLASS(AudioEffectLimiter,AudioEffect)
+
+friend class AudioEffectLimiterInstance;
+ float treshold;
+ float ceiling;
+ float soft_clip;
+ float soft_clip_ratio;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+
+ void set_treshold_db(float p_treshold);
+ float get_treshold_db() const;
+
+ void set_ceiling_db(float p_ceiling);
+ float get_ceiling_db() const;
+
+ void set_soft_clip_db(float p_soft_clip);
+ float get_soft_clip_db() const;
+
+ void set_soft_clip_ratio(float p_soft_clip);
+ float get_soft_clip_ratio() const;
+
+
+ Ref<AudioEffectInstance> instance();
+ void set_volume_db(float p_volume);
+ float get_volume_db() const;
+
+ AudioEffectLimiter();
+};
+
+
+#endif // AUDIO_EFFECT_LIMITER_H
diff --git a/servers/audio/effects/audio_effect_panner.cpp b/servers/audio/effects/audio_effect_panner.cpp
new file mode 100644
index 0000000000..e296b0d998
--- /dev/null
+++ b/servers/audio/effects/audio_effect_panner.cpp
@@ -0,0 +1,47 @@
+#include "audio_effect_panner.h"
+
+
+void AudioEffectPannerInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+
+ float lvol = CLAMP( 1.0 - base->pan, 0, 1);
+ float rvol = CLAMP( 1.0 + base->pan, 0, 1);
+
+ for(int i=0;i<p_frame_count;i++) {
+
+ p_dst_frames[i].l = p_src_frames[i].l * lvol + p_src_frames[i].r * (1.0 - rvol);
+ p_dst_frames[i].r = p_src_frames[i].r * rvol + p_src_frames[i].l * (1.0 - lvol);
+
+ }
+
+}
+
+
+Ref<AudioEffectInstance> AudioEffectPanner::instance() {
+ Ref<AudioEffectPannerInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectPanner>(this);
+ return ins;
+}
+
+void AudioEffectPanner::set_pan(float p_cpanume) {
+ pan=p_cpanume;
+}
+
+float AudioEffectPanner::get_pan() const {
+
+ return pan;
+}
+
+void AudioEffectPanner::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_pan","cpanume"),&AudioEffectPanner::set_pan);
+ ClassDB::bind_method(_MD("get_pan"),&AudioEffectPanner::get_pan);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_pan"),_SCS("get_pan"));
+}
+
+AudioEffectPanner::AudioEffectPanner()
+{
+ pan=0;
+}
diff --git a/servers/audio/effects/audio_effect_panner.h b/servers/audio/effects/audio_effect_panner.h
new file mode 100644
index 0000000000..bc1bb00815
--- /dev/null
+++ b/servers/audio/effects/audio_effect_panner.h
@@ -0,0 +1,40 @@
+#ifndef AUDIOEFFECTPANNER_H
+#define AUDIOEFFECTPANNER_H
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectPanner;
+
+class AudioEffectPannerInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectPannerInstance,AudioEffectInstance)
+friend class AudioEffectPanner;
+ Ref<AudioEffectPanner> base;
+
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectPanner : public AudioEffect {
+ GDCLASS(AudioEffectPanner,AudioEffect)
+
+friend class AudioEffectPannerInstance;
+ float pan;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+
+ Ref<AudioEffectInstance> instance();
+ void set_pan(float p_volume);
+ float get_pan() const;
+
+ AudioEffectPanner();
+};
+
+
+#endif // AUDIOEFFECTPANNER_H
diff --git a/servers/audio/effects/audio_effect_phaser.cpp b/servers/audio/effects/audio_effect_phaser.cpp
new file mode 100644
index 0000000000..bfce608603
--- /dev/null
+++ b/servers/audio/effects/audio_effect_phaser.cpp
@@ -0,0 +1,148 @@
+#include "audio_effect_phaser.h"
+#include "servers/audio_server.h"
+#include "math_funcs.h"
+
+void AudioEffectPhaserInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+ float sampling_rate = AudioServer::get_singleton()->get_mix_rate();
+
+ float dmin = base->range_min / (sampling_rate/2.0);
+ float dmax = base->range_max / (sampling_rate/2.0);
+
+ float increment = 2.f * Math_PI * (base->rate / sampling_rate);
+
+ for(int i=0;i<p_frame_count;i++) {
+
+ phase += increment;
+
+ while ( phase >= Math_PI * 2.f ) {
+ phase -= Math_PI * 2.f;
+ }
+
+ float d = dmin + (dmax-dmin) * ((sin( phase ) + 1.f)/2.f);
+
+
+ //update filter coeffs
+ for( int j=0; j<6; j++ ) {
+ allpass[0][j].delay( d );
+ allpass[1][j].delay( d );
+ }
+
+ //calculate output
+ float y = allpass[0][0].update(
+ allpass[0][1].update(
+ allpass[0][2].update(
+ allpass[0][3].update(
+ allpass[0][4].update(
+ allpass[0][5].update( p_src_frames[i].l + h.l * base->feedback ))))));
+ h.l=y;
+
+ p_dst_frames[i].l = p_src_frames[i].l + y * base->depth;
+
+ y = allpass[1][0].update(
+ allpass[1][1].update(
+ allpass[1][2].update(
+ allpass[1][3].update(
+ allpass[1][4].update(
+ allpass[1][5].update( p_src_frames[i].r + h.r * base->feedback ))))));
+ h.r=y;
+
+ p_dst_frames[i].r = p_src_frames[i].r + y * base->depth;
+
+
+ }
+
+}
+
+
+Ref<AudioEffectInstance> AudioEffectPhaser::instance() {
+ Ref<AudioEffectPhaserInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectPhaser>(this);
+ ins->phase=0;
+ ins->h=AudioFrame(0,0);
+
+ return ins;
+}
+
+
+void AudioEffectPhaser::set_range_min_hz(float p_hz) {
+
+ range_min=p_hz;
+}
+
+float AudioEffectPhaser::get_range_min_hz() const{
+
+ return range_min;
+}
+
+void AudioEffectPhaser::set_range_max_hz(float p_hz){
+
+ range_max=p_hz;
+}
+float AudioEffectPhaser::get_range_max_hz() const{
+
+ return range_max;
+}
+
+void AudioEffectPhaser::set_rate_hz(float p_hz){
+
+ rate=p_hz;
+}
+float AudioEffectPhaser::get_rate_hz() const{
+
+ return rate;
+}
+
+void AudioEffectPhaser::set_feedback(float p_fbk){
+
+ feedback=p_fbk;
+}
+float AudioEffectPhaser::get_feedback() const{
+
+ return feedback;
+}
+
+void AudioEffectPhaser::set_depth(float p_depth) {
+
+ depth=p_depth;
+}
+
+float AudioEffectPhaser::get_depth() const {
+
+ return depth;
+}
+
+void AudioEffectPhaser::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_range_min_hz","hz"),&AudioEffectPhaser::set_range_min_hz);
+ ClassDB::bind_method(_MD("get_range_min_hz"),&AudioEffectPhaser::get_range_min_hz);
+
+ ClassDB::bind_method(_MD("set_range_max_hz","hz"),&AudioEffectPhaser::set_range_max_hz);
+ ClassDB::bind_method(_MD("get_range_max_hz"),&AudioEffectPhaser::get_range_max_hz);
+
+ ClassDB::bind_method(_MD("set_rate_hz","hz"),&AudioEffectPhaser::set_rate_hz);
+ ClassDB::bind_method(_MD("get_rate_hz"),&AudioEffectPhaser::get_rate_hz);
+
+ ClassDB::bind_method(_MD("set_feedback","fbk"),&AudioEffectPhaser::set_feedback);
+ ClassDB::bind_method(_MD("get_feedback"),&AudioEffectPhaser::get_feedback);
+
+ ClassDB::bind_method(_MD("set_depth","depth"),&AudioEffectPhaser::set_depth);
+ ClassDB::bind_method(_MD("get_depth"),&AudioEffectPhaser::get_depth);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"range_min_hz",PROPERTY_HINT_RANGE,"10,10000"),_SCS("set_range_min_hz"),_SCS("get_range_min_hz"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"range_max_hz",PROPERTY_HINT_RANGE,"10,10000"),_SCS("set_range_max_hz"),_SCS("get_range_max_hz"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"rate_hz",PROPERTY_HINT_RANGE,"0.01,20"),_SCS("set_rate_hz"),_SCS("get_rate_hz"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"feedback",PROPERTY_HINT_RANGE,"0.1,0.9,0.1"),_SCS("set_feedback"),_SCS("get_feedback"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"depth",PROPERTY_HINT_RANGE,"0.1,4,0.1"),_SCS("set_depth"),_SCS("get_depth"));
+
+}
+
+AudioEffectPhaser::AudioEffectPhaser()
+{
+ range_min=440;
+ range_max=1600;
+ rate=0.5;
+ feedback=0.7;
+ depth=1;
+}
diff --git a/servers/audio/effects/audio_effect_phaser.h b/servers/audio/effects/audio_effect_phaser.h
new file mode 100644
index 0000000000..53a8ab8bd8
--- /dev/null
+++ b/servers/audio/effects/audio_effect_phaser.h
@@ -0,0 +1,81 @@
+#ifndef AUDIO_EFFECT_PHASER_H
+#define AUDIO_EFFECT_PHASER_H
+
+
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectPhaser;
+
+class AudioEffectPhaserInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectPhaserInstance,AudioEffectInstance)
+friend class AudioEffectPhaser;
+ Ref<AudioEffectPhaser> base;
+
+ float phase;
+ AudioFrame h;
+
+ class AllpassDelay{
+ float a, h;
+ public:
+
+ _ALWAYS_INLINE_ void delay( float d ) {
+ a = (1.f - d) / (1.f + d);
+ }
+
+ _ALWAYS_INLINE_ float update( float s ){
+ float y = s * -a + h;
+ h = y * a + s;
+ return y;
+ }
+
+ AllpassDelay() { a =0; h = 0;}
+
+ };
+
+ AllpassDelay allpass[2][6];
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectPhaser : public AudioEffect {
+ GDCLASS(AudioEffectPhaser,AudioEffect)
+
+friend class AudioEffectPhaserInstance;
+ float range_min;
+ float range_max;
+ float rate;
+ float feedback;
+ float depth;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+
+ Ref<AudioEffectInstance> instance();
+
+ void set_range_min_hz(float p_hz);
+ float get_range_min_hz() const;
+
+ void set_range_max_hz(float p_hz);
+ float get_range_max_hz() const;
+
+ void set_rate_hz(float p_hz);
+ float get_rate_hz() const;
+
+ void set_feedback(float p_fbk);
+ float get_feedback() const;
+
+ void set_depth(float p_depth);
+ float get_depth() const;
+
+ AudioEffectPhaser();
+};
+
+
+#endif // AUDIO_EFFECT_PHASER_H
diff --git a/servers/audio/effects/audio_effect_pitch_shift.cpp b/servers/audio/effects/audio_effect_pitch_shift.cpp
new file mode 100644
index 0000000000..49a14cda04
--- /dev/null
+++ b/servers/audio/effects/audio_effect_pitch_shift.cpp
@@ -0,0 +1,298 @@
+#include "audio_effect_pitch_shift.h"
+#include "servers/audio_server.h"
+#include "math_funcs.h"
+/****************************************************************************
+*
+* NAME: smbPitchShift.cpp
+* VERSION: 1.2
+* HOME URL: http://blogs.zynaptiq.com/bernsee
+* KNOWN BUGS: none
+*
+* SYNOPSIS: Routine for doing pitch shifting while maintaining
+* duration using the Short Time Fourier Transform.
+*
+* DESCRIPTION: The routine takes a pitchShift factor value which is between 0.5
+* (one octave down) and 2. (one octave up). A value of exactly 1 does not change
+* the pitch. numSampsToProcess tells the routine how many samples in indata[0...
+* numSampsToProcess-1] should be pitch shifted and moved to outdata[0 ...
+* numSampsToProcess-1]. The two buffers can be identical (ie. it can process the
+* data in-place). fftFrameSize defines the FFT frame size used for the
+* processing. Typical values are 1024, 2048 and 4096. It may be any value <=
+* MAX_FRAME_LENGTH but it MUST be a power of 2. osamp is the STFT
+* oversampling factor which also determines the overlap between adjacent STFT
+* frames. It should at least be 4 for moderate scaling ratios. A value of 32 is
+* recommended for best quality. sampleRate takes the sample rate for the signal
+* in unit Hz, ie. 44100 for 44.1 kHz audio. The data passed to the routine in
+* indata[] should be in the range [-1.0, 1.0), which is also the output range
+* for the data, make sure you scale the data accordingly (for 16bit signed integers
+* you would have to divide (and multiply) by 32768).
+*
+* COPYRIGHT 1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
+*
+* The Wide Open License (WOL)
+*
+* Permission to use, copy, modify, distribute and sell this software and its
+* documentation for any purpose is hereby granted without fee, provided that
+* the above copyright notice and this license appear in all source copies.
+* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
+* ANY KIND. See http://www.dspguru.com/wol.htm for more information.
+*
+*****************************************************************************/
+
+
+void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long fftFrameSize, long osamp, float sampleRate, float *indata, float *outdata,int stride) {
+
+
+ /*
+ Routine smbPitchShift(). See top of file for explanation
+ Purpose: doing pitch shifting while maintaining duration using the Short
+ Time Fourier Transform.
+ Author: (c)1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
+ */
+
+ double magn, phase, tmp, window, real, imag;
+ double freqPerBin, expct;
+ long i,k, qpd, index, inFifoLatency, stepSize, fftFrameSize2;
+
+ /* set up some handy variables */
+ fftFrameSize2 = fftFrameSize/2;
+ stepSize = fftFrameSize/osamp;
+ freqPerBin = sampleRate/(double)fftFrameSize;
+ expct = 2.*Math_PI*(double)stepSize/(double)fftFrameSize;
+ inFifoLatency = fftFrameSize-stepSize;
+ if (gRover == 0) gRover = inFifoLatency;
+
+ /* initialize our static arrays */
+
+ /* main processing loop */
+ for (i = 0; i < numSampsToProcess; i++){
+
+ /* As long as we have not yet collected enough data just read in */
+ gInFIFO[gRover] = indata[i*stride];
+ outdata[i*stride] = gOutFIFO[gRover-inFifoLatency];
+ gRover++;
+
+ /* now we have enough data for processing */
+ if (gRover >= fftFrameSize) {
+ gRover = inFifoLatency;
+
+ /* do windowing and re,im interleave */
+ for (k = 0; k < fftFrameSize;k++) {
+ window = -.5*cos(2.*Math_PI*(double)k/(double)fftFrameSize)+.5;
+ gFFTworksp[2*k] = gInFIFO[k] * window;
+ gFFTworksp[2*k+1] = 0.;
+ }
+
+
+ /* ***************** ANALYSIS ******************* */
+ /* do transform */
+ smbFft(gFFTworksp, fftFrameSize, -1);
+
+ /* this is the analysis step */
+ for (k = 0; k <= fftFrameSize2; k++) {
+
+ /* de-interlace FFT buffer */
+ real = gFFTworksp[2*k];
+ imag = gFFTworksp[2*k+1];
+
+ /* compute magnitude and phase */
+ magn = 2.*sqrt(real*real + imag*imag);
+ phase = atan2(imag,real);
+
+ /* compute phase difference */
+ tmp = phase - gLastPhase[k];
+ gLastPhase[k] = phase;
+
+ /* subtract expected phase difference */
+ tmp -= (double)k*expct;
+
+ /* map delta phase into +/- Pi interval */
+ qpd = tmp/Math_PI;
+ if (qpd >= 0) qpd += qpd&1;
+ else qpd -= qpd&1;
+ tmp -= Math_PI*(double)qpd;
+
+ /* get deviation from bin frequency from the +/- Pi interval */
+ tmp = osamp*tmp/(2.*Math_PI);
+
+ /* compute the k-th partials' true frequency */
+ tmp = (double)k*freqPerBin + tmp*freqPerBin;
+
+ /* store magnitude and true frequency in analysis arrays */
+ gAnaMagn[k] = magn;
+ gAnaFreq[k] = tmp;
+
+ }
+
+ /* ***************** PROCESSING ******************* */
+ /* this does the actual pitch shifting */
+ memset(gSynMagn, 0, fftFrameSize*sizeof(float));
+ memset(gSynFreq, 0, fftFrameSize*sizeof(float));
+ for (k = 0; k <= fftFrameSize2; k++) {
+ index = k*pitchShift;
+ if (index <= fftFrameSize2) {
+ gSynMagn[index] += gAnaMagn[k];
+ gSynFreq[index] = gAnaFreq[k] * pitchShift;
+ }
+ }
+
+ /* ***************** SYNTHESIS ******************* */
+ /* this is the synthesis step */
+ for (k = 0; k <= fftFrameSize2; k++) {
+
+ /* get magnitude and true frequency from synthesis arrays */
+ magn = gSynMagn[k];
+ tmp = gSynFreq[k];
+
+ /* subtract bin mid frequency */
+ tmp -= (double)k*freqPerBin;
+
+ /* get bin deviation from freq deviation */
+ tmp /= freqPerBin;
+
+ /* take osamp into account */
+ tmp = 2.*Math_PI*tmp/osamp;
+
+ /* add the overlap phase advance back in */
+ tmp += (double)k*expct;
+
+ /* accumulate delta phase to get bin phase */
+ gSumPhase[k] += tmp;
+ phase = gSumPhase[k];
+
+ /* get real and imag part and re-interleave */
+ gFFTworksp[2*k] = magn*cos(phase);
+ gFFTworksp[2*k+1] = magn*sin(phase);
+ }
+
+ /* zero negative frequencies */
+ for (k = fftFrameSize+2; k < 2*fftFrameSize; k++) gFFTworksp[k] = 0.;
+
+ /* do inverse transform */
+ smbFft(gFFTworksp, fftFrameSize, 1);
+
+ /* do windowing and add to output accumulator */
+ for(k=0; k < fftFrameSize; k++) {
+ window = -.5*cos(2.*Math_PI*(double)k/(double)fftFrameSize)+.5;
+ gOutputAccum[k] += 2.*window*gFFTworksp[2*k]/(fftFrameSize2*osamp);
+ }
+ for (k = 0; k < stepSize; k++) gOutFIFO[k] = gOutputAccum[k];
+
+ /* shift accumulator */
+ memmove(gOutputAccum, gOutputAccum+stepSize, fftFrameSize*sizeof(float));
+
+ /* move input FIFO */
+ for (k = 0; k < inFifoLatency; k++) gInFIFO[k] = gInFIFO[k+stepSize];
+ }
+ }
+
+
+
+}
+
+
+void SMBPitchShift::smbFft(float *fftBuffer, long fftFrameSize, long sign)
+/*
+ FFT routine, (C)1996 S.M.Bernsee. Sign = -1 is FFT, 1 is iFFT (inverse)
+ Fills fftBuffer[0...2*fftFrameSize-1] with the Fourier transform of the
+ time domain data in fftBuffer[0...2*fftFrameSize-1]. The FFT array takes
+ and returns the cosine and sine parts in an interleaved manner, ie.
+ fftBuffer[0] = cosPart[0], fftBuffer[1] = sinPart[0], asf. fftFrameSize
+ must be a power of 2. It expects a complex input signal (see footnote 2),
+ ie. when working with 'common' audio signals our input signal has to be
+ passed as {in[0],0.,in[1],0.,in[2],0.,...} asf. In that case, the transform
+ of the frequencies of interest is in fftBuffer[0...fftFrameSize].
+*/
+{
+ float wr, wi, arg, *p1, *p2, temp;
+ float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i;
+ long i, bitm, j, le, le2, k;
+
+ for (i = 2; i < 2*fftFrameSize-2; i += 2) {
+ for (bitm = 2, j = 0; bitm < 2*fftFrameSize; bitm <<= 1) {
+ if (i & bitm) j++;
+ j <<= 1;
+ }
+ if (i < j) {
+ p1 = fftBuffer+i; p2 = fftBuffer+j;
+ temp = *p1; *(p1++) = *p2;
+ *(p2++) = temp; temp = *p1;
+ *p1 = *p2; *p2 = temp;
+ }
+ }
+ for (k = 0, le = 2; k < (long)(log(fftFrameSize)/log(2.)+.5); k++) {
+ le <<= 1;
+ le2 = le>>1;
+ ur = 1.0;
+ ui = 0.0;
+ arg = Math_PI / (le2>>1);
+ wr = cos(arg);
+ wi = sign*sin(arg);
+ for (j = 0; j < le2; j += 2) {
+ p1r = fftBuffer+j; p1i = p1r+1;
+ p2r = p1r+le2; p2i = p2r+1;
+ for (i = j; i < 2*fftFrameSize; i += le) {
+ tr = *p2r * ur - *p2i * ui;
+ ti = *p2r * ui + *p2i * ur;
+ *p2r = *p1r - tr; *p2i = *p1i - ti;
+ *p1r += tr; *p1i += ti;
+ p1r += le; p1i += le;
+ p2r += le; p2i += le;
+ }
+ tr = ur*wr - ui*wi;
+ ui = ur*wi + ui*wr;
+ ur = tr;
+ }
+ }
+}
+
+
+void AudioEffectPitchShiftInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+ float sample_rate = AudioServer::get_singleton()->get_mix_rate();
+
+ float *in_l = (float*)p_src_frames;
+ float *in_r = in_l + 1;
+
+ float *out_l = (float*)p_dst_frames;
+ float *out_r = out_l + 1;
+
+ shift_l.PitchShift(base->pitch_scale,p_frame_count,2048,4,sample_rate,in_l,out_l,2);
+ shift_r.PitchShift(base->pitch_scale,p_frame_count,2048,4,sample_rate,in_r,out_r,2);
+
+}
+
+
+Ref<AudioEffectInstance> AudioEffectPitchShift::instance() {
+ Ref<AudioEffectPitchShiftInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectPitchShift>(this);
+
+
+ return ins;
+}
+
+void AudioEffectPitchShift::set_pitch_scale(float p_adjust) {
+
+ pitch_scale=p_adjust;
+}
+
+float AudioEffectPitchShift::get_pitch_scale() const {
+
+ return pitch_scale;
+}
+
+
+void AudioEffectPitchShift::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_pitch_scale","rate"),&AudioEffectPitchShift::set_pitch_scale);
+ ClassDB::bind_method(_MD("get_pitch_scale"),&AudioEffectPitchShift::get_pitch_scale);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"pitch_scale",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_pitch_scale"),_SCS("get_pitch_scale"));
+
+}
+
+AudioEffectPitchShift::AudioEffectPitchShift() {
+ pitch_scale=1.0;
+
+}
diff --git a/servers/audio/effects/audio_effect_pitch_shift.h b/servers/audio/effects/audio_effect_pitch_shift.h
new file mode 100644
index 0000000000..d1343a0745
--- /dev/null
+++ b/servers/audio/effects/audio_effect_pitch_shift.h
@@ -0,0 +1,89 @@
+#ifndef AUDIO_EFFECT_PITCH_SHIFT_H
+#define AUDIO_EFFECT_PITCH_SHIFT_H
+
+
+#include "servers/audio/audio_effect.h"
+
+class SMBPitchShift {
+
+ enum {
+ MAX_FRAME_LENGTH=8192
+ };
+
+ float gInFIFO[MAX_FRAME_LENGTH];
+ float gOutFIFO[MAX_FRAME_LENGTH];
+ float gFFTworksp[2*MAX_FRAME_LENGTH];
+ float gLastPhase[MAX_FRAME_LENGTH/2+1];
+ float gSumPhase[MAX_FRAME_LENGTH/2+1];
+ float gOutputAccum[2*MAX_FRAME_LENGTH];
+ float gAnaFreq[MAX_FRAME_LENGTH];
+ float gAnaMagn[MAX_FRAME_LENGTH];
+ float gSynFreq[MAX_FRAME_LENGTH];
+ float gSynMagn[MAX_FRAME_LENGTH];
+ long gRover;
+
+ void smbFft(float *fftBuffer, long fftFrameSize, long sign);
+public:
+ void PitchShift(float pitchShift, long numSampsToProcess, long fftFrameSize, long osamp, float sampleRate, float *indata, float *outdata, int stride);
+
+ SMBPitchShift() {
+ gRover=0;
+ memset(gInFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));
+ memset(gOutFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));
+ memset(gFFTworksp, 0, 2*MAX_FRAME_LENGTH*sizeof(float));
+ memset(gLastPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));
+ memset(gSumPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));
+ memset(gOutputAccum, 0, 2*MAX_FRAME_LENGTH*sizeof(float));
+ memset(gAnaFreq, 0, MAX_FRAME_LENGTH*sizeof(float));
+ memset(gAnaMagn, 0, MAX_FRAME_LENGTH*sizeof(float));
+ }
+
+
+};
+
+
+class AudioEffectPitchShift;
+
+class AudioEffectPitchShiftInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectPitchShiftInstance,AudioEffectInstance)
+friend class AudioEffectPitchShift;
+ Ref<AudioEffectPitchShift> base;
+
+ SMBPitchShift shift_l;
+ SMBPitchShift shift_r;
+
+
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectPitchShift : public AudioEffect {
+ GDCLASS(AudioEffectPitchShift,AudioEffect)
+
+friend class AudioEffectPitchShiftInstance;
+
+ float pitch_scale;
+ int window_size;
+ float wet;
+ float dry;
+ bool filter;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+
+ Ref<AudioEffectInstance> instance();
+
+ void set_pitch_scale(float p_adjust);
+ float get_pitch_scale() const;
+
+ AudioEffectPitchShift();
+};
+
+
+#endif // AUDIO_EFFECT_PITCH_SHIFT_H
diff --git a/servers/audio/effects/audio_effect_reverb.cpp b/servers/audio/effects/audio_effect_reverb.cpp
new file mode 100644
index 0000000000..749814fd76
--- /dev/null
+++ b/servers/audio/effects/audio_effect_reverb.cpp
@@ -0,0 +1,182 @@
+#include "audio_effect_reverb.h"
+#include "servers/audio_server.h"
+void AudioEffectReverbInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+ for(int i=0;i<2;i++) {
+ Reverb &r=reverb[i];
+
+ r.set_predelay( base->predelay);
+ r.set_predelay_feedback( base->predelay_fb );
+ r.set_highpass( base->hpf );
+ r.set_room_size( base->room_size );
+ r.set_damp( base->damping );
+ r.set_extra_spread( base->spread );
+ r.set_wet( base->wet );
+ r.set_dry( base->dry );
+ }
+
+ int todo = p_frame_count;
+ int offset=0;
+
+ while(todo) {
+
+ int to_mix = MIN(todo,Reverb::INPUT_BUFFER_MAX_SIZE);
+
+ for(int j=0;j<to_mix;j++) {
+ tmp_src[j]=p_src_frames[offset+j].l;
+ }
+
+ reverb[0].process(tmp_src,tmp_dst,to_mix);
+
+ for(int j=0;j<to_mix;j++) {
+ p_dst_frames[offset+j].l=tmp_dst[j];
+ tmp_src[j]=p_src_frames[offset+j].r;
+ }
+
+ reverb[1].process(tmp_src,tmp_dst,to_mix);
+
+ for(int j=0;j<to_mix;j++) {
+ p_dst_frames[offset+j].r=tmp_dst[j];
+ }
+
+ offset+=to_mix;
+ todo-=to_mix;
+ }
+}
+
+AudioEffectReverbInstance::AudioEffectReverbInstance() {
+
+ reverb[0].set_mix_rate( AudioServer::get_singleton()->get_mix_rate() );
+ reverb[0].set_extra_spread_base(0);
+ reverb[1].set_mix_rate( AudioServer::get_singleton()->get_mix_rate() );
+ reverb[1].set_extra_spread_base(0.000521); //for stereo effect
+
+}
+
+Ref<AudioEffectInstance> AudioEffectReverb::instance() {
+ Ref<AudioEffectReverbInstance> ins;
+ ins.instance();
+ ins->base=Ref<AudioEffectReverb>(this);
+ return ins;
+}
+
+void AudioEffectReverb::set_predelay_msec(float p_msec) {
+
+ predelay=p_msec;
+}
+
+void AudioEffectReverb::set_predelay_feedback(float p_feedback){
+
+ predelay_fb=p_feedback;
+}
+void AudioEffectReverb::set_room_size(float p_size){
+
+ room_size=p_size;
+}
+void AudioEffectReverb::set_damping(float p_damping){
+
+ damping=p_damping;
+}
+void AudioEffectReverb::set_spread(float p_spread){
+
+ spread=p_spread;
+}
+
+void AudioEffectReverb::set_dry(float p_dry){
+
+ dry=p_dry;
+}
+void AudioEffectReverb::set_wet(float p_wet){
+
+ wet=p_wet;
+}
+void AudioEffectReverb::set_hpf(float p_hpf) {
+
+ hpf=p_hpf;
+}
+
+float AudioEffectReverb::get_predelay_msec() const {
+
+ return predelay;
+}
+float AudioEffectReverb::get_predelay_feedback() const {
+
+ return predelay_fb;
+}
+float AudioEffectReverb::get_room_size() const {
+
+ return room_size;
+}
+float AudioEffectReverb::get_damping() const {
+
+ return damping;
+}
+float AudioEffectReverb::get_spread() const {
+
+ return spread;
+}
+float AudioEffectReverb::get_dry() const {
+
+ return dry;
+}
+float AudioEffectReverb::get_wet() const {
+
+ return wet;
+}
+float AudioEffectReverb::get_hpf() const {
+
+ return hpf;
+}
+
+
+void AudioEffectReverb::_bind_methods() {
+
+
+ ClassDB::bind_method(_MD("set_predelay_msec","msec"),&AudioEffectReverb::set_predelay_msec);
+ ClassDB::bind_method(_MD("get_predelay_msec"),&AudioEffectReverb::get_predelay_msec);
+
+ ClassDB::bind_method(_MD("set_predelay_feedback","feedback"),&AudioEffectReverb::set_predelay_feedback);
+ ClassDB::bind_method(_MD("get_predelay_feedback"),&AudioEffectReverb::get_predelay_feedback);
+
+ ClassDB::bind_method(_MD("set_room_size","size"),&AudioEffectReverb::set_room_size);
+ ClassDB::bind_method(_MD("get_room_size"),&AudioEffectReverb::get_room_size);
+
+ ClassDB::bind_method(_MD("set_damping","amount"),&AudioEffectReverb::set_damping);
+ ClassDB::bind_method(_MD("get_damping"),&AudioEffectReverb::get_damping);
+
+ ClassDB::bind_method(_MD("set_spread","amount"),&AudioEffectReverb::set_spread);
+ ClassDB::bind_method(_MD("get_spread"),&AudioEffectReverb::get_spread);
+
+ ClassDB::bind_method(_MD("set_dry","amount"),&AudioEffectReverb::set_dry);
+ ClassDB::bind_method(_MD("get_dry"),&AudioEffectReverb::get_dry);
+
+ ClassDB::bind_method(_MD("set_wet","amount"),&AudioEffectReverb::set_wet);
+ ClassDB::bind_method(_MD("get_wet"),&AudioEffectReverb::get_wet);
+
+ ClassDB::bind_method(_MD("set_hpf","amount"),&AudioEffectReverb::set_hpf);
+ ClassDB::bind_method(_MD("get_hpf"),&AudioEffectReverb::get_hpf);
+
+
+ ADD_GROUP("Predelay","predelay_");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"predelay_msec",PROPERTY_HINT_RANGE,"20,500,1"),_SCS("set_predelay_msec"),_SCS("get_predelay_msec"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"predelay_feedback",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_predelay_msec"),_SCS("get_predelay_msec"));
+ ADD_GROUP("","");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"room_size",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_room_size"),_SCS("get_room_size"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"damping",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_damping"),_SCS("get_damping"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"spread",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_spread"),_SCS("get_spread"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"hipass",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_hpf"),_SCS("get_hpf"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"dry",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_dry"),_SCS("get_dry"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"wet",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_wet"),_SCS("get_wet"));
+}
+
+AudioEffectReverb::AudioEffectReverb() {
+ predelay=150;
+ predelay_fb=0.4;
+ hpf=0;
+ room_size=0.8;
+ damping=0.5;
+ spread=1.0;
+ dry=1.0;
+ wet=0.5;
+
+}
diff --git a/servers/audio/effects/audio_effect_reverb.h b/servers/audio/effects/audio_effect_reverb.h
new file mode 100644
index 0000000000..e05ffe422f
--- /dev/null
+++ b/servers/audio/effects/audio_effect_reverb.h
@@ -0,0 +1,76 @@
+#ifndef AUDIOEFFECTREVERB_H
+#define AUDIOEFFECTREVERB_H
+
+
+#include "servers/audio/audio_effect.h"
+#include "servers/audio/effects/reverb.h"
+
+class AudioEffectReverb;
+
+class AudioEffectReverbInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectReverbInstance,AudioEffectInstance)
+
+ Ref<AudioEffectReverb> base;
+
+ float tmp_src[Reverb::INPUT_BUFFER_MAX_SIZE];
+ float tmp_dst[Reverb::INPUT_BUFFER_MAX_SIZE];
+
+friend class AudioEffectReverb;
+
+ Reverb reverb[2];
+
+
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+ AudioEffectReverbInstance();
+};
+
+
+class AudioEffectReverb : public AudioEffect {
+ GDCLASS(AudioEffectReverb,AudioEffect)
+
+friend class AudioEffectReverbInstance;
+
+ float predelay;
+ float predelay_fb;
+ float hpf;
+ float room_size;
+ float damping;
+ float spread;
+ float dry;
+ float wet;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+
+ void set_predelay_msec(float p_msec);
+ void set_predelay_feedback(float p_feedback);
+ void set_room_size(float p_size);
+ void set_damping(float p_damping);
+ void set_spread(float p_spread);
+ void set_dry(float p_dry);
+ void set_wet(float p_wet);
+ void set_hpf(float p_hpf);
+
+ float get_predelay_msec() const;
+ float get_predelay_feedback() const;
+ float get_room_size() const;
+ float get_damping() const;
+ float get_spread() const;
+ float get_dry() const;
+ float get_wet() const;
+ float get_hpf() const;
+
+ Ref<AudioEffectInstance> instance();
+ void set_volume_db(float p_volume);
+ float get_volume_db() const;
+
+ AudioEffectReverb();
+};
+
+
+#endif // AUDIOEFFECTREVERB_H
diff --git a/servers/audio/effects/audio_effect_stereo_enhance.cpp b/servers/audio/effects/audio_effect_stereo_enhance.cpp
new file mode 100644
index 0000000000..c5968aa772
--- /dev/null
+++ b/servers/audio/effects/audio_effect_stereo_enhance.cpp
@@ -0,0 +1,135 @@
+#include "audio_effect_stereo_enhance.h"
+#include "servers/audio_server.h"
+void AudioEffectStereoEnhanceInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+
+ float intensity=base->pan_pullout;
+ bool surround_mode=base->surround>0;
+ float surround_amount=base->surround;
+ unsigned int delay_frames=(base->time_pullout/1000.0)*AudioServer::get_singleton()->get_mix_rate();
+
+ for (int i=0;i<p_frame_count;i++) {
+
+ float l=p_src_frames[i].l;
+ float r=p_src_frames[i].r;
+
+ float center=(l+r)/2.0f;
+
+ l=( center+(l-center)*intensity );
+ r=( center+(r-center)*intensity );
+
+ if (surround_mode) {
+
+ float val=(l+r)/2.0;
+
+ delay_ringbuff[ringbuff_pos&ringbuff_mask]=val;
+
+ float out=delay_ringbuff[(ringbuff_pos-delay_frames)&ringbuff_mask]*surround_amount;
+
+ l+=out;
+ r+=-out;
+ } else {
+
+ float val=r;
+
+ delay_ringbuff[ringbuff_pos&ringbuff_mask]=val;
+
+ //r is delayed
+ r=delay_ringbuff[(ringbuff_pos-delay_frames)&ringbuff_mask];;
+
+
+ }
+
+ p_dst_frames[i].l=l;
+ p_dst_frames[i].r=r;
+ ringbuff_pos++;
+
+ }
+
+}
+
+
+AudioEffectStereoEnhanceInstance::~AudioEffectStereoEnhanceInstance() {
+
+ memdelete_arr(delay_ringbuff);
+}
+
+Ref<AudioEffectInstance> AudioEffectStereoEnhance::instance() {
+ Ref<AudioEffectStereoEnhanceInstance> ins;
+ ins.instance();
+
+ ins->base=Ref<AudioEffectStereoEnhance>(this);
+
+
+ float ring_buffer_max_size=AudioEffectStereoEnhanceInstance::MAX_DELAY_MS+2;
+ ring_buffer_max_size/=1000.0;//convert to seconds
+ ring_buffer_max_size*=AudioServer::get_singleton()->get_mix_rate();
+
+ int ringbuff_size=(int)ring_buffer_max_size;
+
+ int bits=0;
+
+ while(ringbuff_size>0) {
+ bits++;
+ ringbuff_size/=2;
+ }
+
+ ringbuff_size=1<<bits;
+ ins->ringbuff_mask=ringbuff_size-1;
+ ins->ringbuff_pos=0;
+
+ ins->delay_ringbuff = memnew_arr(float,ringbuff_size );
+
+ return ins;
+}
+
+void AudioEffectStereoEnhance::set_pan_pullout(float p_amount) {
+
+ pan_pullout=p_amount;
+}
+
+float AudioEffectStereoEnhance::get_pan_pullout() const {
+
+ return pan_pullout;
+}
+
+void AudioEffectStereoEnhance::set_time_pullout(float p_amount) {
+
+ time_pullout=p_amount;
+}
+float AudioEffectStereoEnhance::get_time_pullout() const {
+
+ return time_pullout;
+}
+
+void AudioEffectStereoEnhance::set_surround(float p_amount) {
+
+ surround=p_amount;
+}
+float AudioEffectStereoEnhance::get_surround() const {
+
+ return surround;
+}
+
+void AudioEffectStereoEnhance::_bind_methods() {
+
+ ClassDB::bind_method(_MD("set_pan_pullout","amount"),&AudioEffectStereoEnhance::set_pan_pullout);
+ ClassDB::bind_method(_MD("get_pan_pullout"),&AudioEffectStereoEnhance::get_pan_pullout);
+
+ ClassDB::bind_method(_MD("set_time_pullout","amount"),&AudioEffectStereoEnhance::set_time_pullout);
+ ClassDB::bind_method(_MD("get_time_pullout"),&AudioEffectStereoEnhance::get_time_pullout);
+
+ ClassDB::bind_method(_MD("set_surround","amount"),&AudioEffectStereoEnhance::set_surround);
+ ClassDB::bind_method(_MD("get_surround"),&AudioEffectStereoEnhance::get_surround);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"pan_pullout",PROPERTY_HINT_RANGE,"0,4,0.01"),_SCS("set_pan_pullout"),_SCS("get_pan_pullout"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"time_pullout_ms",PROPERTY_HINT_RANGE,"0,50,0.01"),_SCS("set_time_pullout"),_SCS("get_time_pullout"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"surround",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_surround"),_SCS("get_surround"));
+}
+
+AudioEffectStereoEnhance::AudioEffectStereoEnhance()
+{
+ pan_pullout=1;
+ time_pullout=0;
+ surround=0;
+}
diff --git a/servers/audio/effects/audio_effect_stereo_enhance.h b/servers/audio/effects/audio_effect_stereo_enhance.h
new file mode 100644
index 0000000000..06762acbf3
--- /dev/null
+++ b/servers/audio/effects/audio_effect_stereo_enhance.h
@@ -0,0 +1,62 @@
+#ifndef AUDIOEFFECTSTEREOENHANCE_H
+#define AUDIOEFFECTSTEREOENHANCE_H
+
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectStereoEnhance;
+
+class AudioEffectStereoEnhanceInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectStereoEnhanceInstance,AudioEffectInstance)
+friend class AudioEffectStereoEnhance;
+ Ref<AudioEffectStereoEnhance> base;
+
+ enum {
+
+ MAX_DELAY_MS=50
+ };
+
+ float *delay_ringbuff;
+ unsigned int ringbuff_pos;
+ unsigned int ringbuff_mask;
+
+
+public:
+
+ virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+ ~AudioEffectStereoEnhanceInstance();
+};
+
+
+class AudioEffectStereoEnhance : public AudioEffect {
+ GDCLASS(AudioEffectStereoEnhance,AudioEffect)
+
+friend class AudioEffectStereoEnhanceInstance;
+ float volume_db;
+
+ float pan_pullout;
+ float time_pullout;
+ float surround;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+
+ Ref<AudioEffectInstance> instance();
+
+ void set_pan_pullout(float p_amount);
+ float get_pan_pullout() const;
+
+ void set_time_pullout(float p_amount);
+ float get_time_pullout() const;
+
+ void set_surround(float p_amount);
+ float get_surround() const;
+
+ AudioEffectStereoEnhance();
+};
+
+#endif // AUDIOEFFECTSTEREOENHANCE_H
diff --git a/servers/audio/effects/eq.cpp b/servers/audio/effects/eq.cpp
new file mode 100644
index 0000000000..a6499a66b4
--- /dev/null
+++ b/servers/audio/effects/eq.cpp
@@ -0,0 +1,219 @@
+//
+// C++ Interface: eq
+//
+// Description:
+//
+//
+// Author: reduzio@gmail.com (C) 2006
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "eq.h"
+#include <math.h>
+#include "error_macros.h"
+#include "math_funcs.h"
+
+#define POW2(v) ((v)*(v))
+
+/* Helper */
+ static int solve_quadratic(double a,double b,double c,double *r1, double *r2) {
+//solves quadractic and returns number of roots
+
+ double base=2*a;
+ if (base == 0.0f)
+ return 0;
+
+ double squared=b*b-4*a*c;
+ if (squared<0.0)
+ return 0;
+
+ squared=sqrt(squared);
+
+ *r1=(-b+squared)/base;
+ *r2=(-b-squared)/base;
+
+ if (*r1==*r2)
+ return 1;
+ else
+ return 2;
+ }
+
+EQ::BandProcess::BandProcess() {
+
+ c1=c2=c3=history.a1=history.a2=history.a3=0;
+ history.b1=history.b2=history.b3=0;
+}
+
+void EQ::recalculate_band_coefficients() {
+
+#define BAND_LOG( m_f ) ( log((m_f)) / log(2) )
+
+ for (int i=0;i<band.size();i++) {
+
+ double octave_size;
+
+ double frq=band[i].freq;
+
+ if (i==0) {
+
+ octave_size=BAND_LOG(band[1].freq)-BAND_LOG(frq);
+ } else if (i==(band.size()-1)) {
+
+ octave_size=BAND_LOG(frq)-BAND_LOG(band[i-1].freq);
+ } else {
+
+ double next=BAND_LOG(band[i+1].freq)-BAND_LOG(frq);
+ double prev=BAND_LOG(frq)-BAND_LOG(band[i-1].freq);
+ octave_size=(next+prev)/2.0;
+ }
+
+
+
+ double frq_l=round(frq/pow(2.0,octave_size/2.0));
+
+
+
+ double side_gain2=POW2(Math_SQRT12);
+ double th=2.0*Math_PI*frq/mix_rate;
+ double th_l=2.0*Math_PI*frq_l/mix_rate;
+
+ double c2a=side_gain2 * POW2(cos(th))
+ - 2.0 * side_gain2 * cos(th_l) * cos(th)
+ + side_gain2
+ - POW2(sin(th_l));
+
+ double c2b=2.0 * side_gain2 * POW2(cos(th_l))
+ + side_gain2 * POW2(cos(th))
+ - 2.0 * side_gain2 * cos(th_l) * cos(th)
+ - side_gain2
+ + POW2(sin(th_l));
+
+ double c2c=0.25 * side_gain2 * POW2(cos(th))
+ - 0.5 * side_gain2 * cos(th_l) * cos(th)
+ + 0.25 * side_gain2
+ - 0.25 * POW2(sin(th_l));
+
+ //printf("band %i, precoefs = %f,%f,%f\n",i,c2a,c2b,c2c);
+
+ double r1,r2; //roots
+ int roots=solve_quadratic(c2a,c2b,c2c,&r1,&r2);
+
+ ERR_CONTINUE( roots==0 );
+
+ band[i].c1=2.0 * ((0.5-r1)/2.0);
+ band[i].c2=2.0 * r1;
+ band[i].c3=2.0 * (0.5+r1) * cos(th);
+ //printf("band %i, coefs = %f,%f,%f\n",i,(float)bands[i].c1,(float)bands[i].c2,(float)bands[i].c3);
+
+ }
+}
+
+void EQ::set_preset_band_mode(Preset p_preset) {
+
+
+ band.clear();
+
+#define PUSH_BANDS(m_bands) \
+ for (int i=0;i<m_bands;i++) { \
+ Band b; \
+ b.freq=bands[i];\
+ band.push_back(b);\
+ }
+
+ switch (p_preset) {
+
+ case PRESET_6_BANDS: {
+
+ static const double bands[] = { 32 , 100 , 320 , 1e3, 3200, 10e3 };
+ PUSH_BANDS(6);
+
+ } break;
+
+ case PRESET_8_BANDS: {
+
+ static const double bands[] = { 32,72,192,512,1200,3000,7500,16e3 };
+
+ PUSH_BANDS(8);
+ } break;
+
+ case PRESET_10_BANDS: {
+ static const double bands[] = { 31.25, 62.5, 125 , 250 , 500 , 1e3, 2e3, 4e3, 8e3, 16e3 };
+
+ PUSH_BANDS(10);
+
+ } break;
+
+ case PRESET_21_BANDS: {
+
+ static const double bands[] = { 22 , 32 , 44 , 63 , 90 , 125 , 175 , 250 , 350 , 500 , 700 , 1e3, 1400 , 2e3, 2800 , 4e3, 5600 , 8e3, 11e3, 16e3, 22e3 };
+ PUSH_BANDS(21);
+
+ } break;
+
+ case PRESET_31_BANDS: {
+
+ static const double bands[] = { 20, 25, 31.5, 40 , 50 , 63 , 80 , 100 , 125 , 160 , 200 , 250 , 315 , 400 , 500 , 630 , 800 , 1e3 , 1250 , 1600 , 2e3, 2500 , 3150 , 4e3, 5e3, 6300 , 8e3, 10e3, 12500 , 16e3, 20e3 };
+ PUSH_BANDS(31);
+ } break;
+
+ };
+
+ recalculate_band_coefficients();
+}
+
+int EQ::get_band_count() const {
+
+ return band.size();
+}
+float EQ::get_band_frequency(int p_band) {
+
+ ERR_FAIL_INDEX_V(p_band,band.size(),0);
+ return band[p_band].freq;
+}
+void EQ::set_bands(const Vector<float>& p_bands) {
+
+ band.resize(p_bands.size());
+ for (int i=0;i<p_bands.size();i++) {
+
+ band[i].freq=p_bands[i];
+ }
+
+ recalculate_band_coefficients();
+
+}
+
+void EQ::set_mix_rate(float p_mix_rate) {
+
+ mix_rate=p_mix_rate;
+ recalculate_band_coefficients();
+}
+
+EQ::BandProcess EQ::get_band_processor(int p_band) const {
+
+
+ EQ::BandProcess band_proc;
+
+ ERR_FAIL_INDEX_V(p_band,band.size(),band_proc);
+
+ band_proc.c1=band[p_band].c1;
+ band_proc.c2=band[p_band].c2;
+ band_proc.c3=band[p_band].c3;
+
+ return band_proc;
+
+
+}
+
+
+EQ::EQ()
+{
+ mix_rate=44100;
+}
+
+
+EQ::~EQ()
+{
+}
+
+
diff --git a/servers/audio/effects/eq.h b/servers/audio/effects/eq.h
new file mode 100644
index 0000000000..2c4668cd0b
--- /dev/null
+++ b/servers/audio/effects/eq.h
@@ -0,0 +1,106 @@
+//
+// C++ Interface: eq
+//
+// Description:
+//
+//
+// Author: reduzio@gmail.com (C) 2006
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef EQ_FILTER_H
+#define EQ_FILTER_H
+
+
+#include "typedefs.h"
+#include "vector.h"
+
+
+/**
+@author Juan Linietsky
+*/
+
+class EQ {
+public:
+
+ enum Preset {
+
+ PRESET_6_BANDS,
+ PRESET_8_BANDS,
+ PRESET_10_BANDS,
+ PRESET_21_BANDS,
+ PRESET_31_BANDS
+ };
+
+
+
+ class BandProcess {
+
+ friend class EQ;
+ float c1,c2,c3;
+ struct History {
+ float a1,a2,a3;
+ float b1,b2,b3;
+
+ } history;
+
+ public:
+
+ inline void process_one(float & p_data);
+
+ BandProcess();
+ };
+
+private:
+ struct Band {
+
+ float freq;
+ float c1,c2,c3;
+ };
+
+ Vector<Band> band;
+
+ float mix_rate;
+
+ void recalculate_band_coefficients();
+
+public:
+
+
+ void set_mix_rate(float p_mix_rate);
+
+ int get_band_count() const;
+ void set_preset_band_mode(Preset p_preset);
+ void set_bands(const Vector<float>& p_bands);
+ BandProcess get_band_processor(int p_band) const;
+ float get_band_frequency(int p_band);
+
+ EQ();
+ ~EQ();
+
+};
+
+
+/* Inline Function */
+
+inline void EQ::BandProcess::process_one(float & p_data) {
+
+
+ history.a1=p_data;
+
+ history.b1= c1 * ( history.a1 - history.a3 )
+ + c3 * history.b2
+ - c2 * history.b3;
+
+ p_data = history.b1;
+
+ history.a3=history.a2;
+ history.a2=history.a1;
+ history.b3=history.b2;
+ history.b2=history.b1;
+
+}
+
+
+#endif
diff --git a/servers/audio/effects/reverb.cpp b/servers/audio/effects/reverb.cpp
new file mode 100644
index 0000000000..43ea0edb3a
--- /dev/null
+++ b/servers/audio/effects/reverb.cpp
@@ -0,0 +1,364 @@
+//
+// C++ Interface: reverb
+//
+// Description:
+//
+//
+// Author: Juan Linietsky <reduzio@gmail.com>, (C) 2006
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#include "reverb.h"
+#include <math.h>
+#include "math_funcs.h"
+
+
+const float Reverb::comb_tunings[MAX_COMBS]={
+ //freeverb comb tunings
+ 0.025306122448979593,
+ 0.026938775510204082,
+ 0.028956916099773241,
+ 0.03074829931972789,
+ 0.032244897959183672,
+ 0.03380952380952381,
+ 0.035306122448979592,
+ 0.036666666666666667
+};
+
+const float Reverb::allpass_tunings[MAX_ALLPASS]={
+ //freeverb allpass tunings
+ 0.0051020408163265302,
+ 0.007732426303854875,
+ 0.01,
+ 0.012607709750566893
+};
+
+
+
+void Reverb::process(float *p_src,float *p_dst,int p_frames) {
+
+ if (p_frames>INPUT_BUFFER_MAX_SIZE)
+ p_frames=INPUT_BUFFER_MAX_SIZE;
+
+ int predelay_frames=lrint((params.predelay/1000.0)*params.mix_rate);
+ if (predelay_frames<10)
+ predelay_frames=10;
+ if (predelay_frames>=echo_buffer_size)
+ predelay_frames=echo_buffer_size-1;
+
+ for (int i=0;i<p_frames;i++) {
+
+ if (echo_buffer_pos>=echo_buffer_size)
+ echo_buffer_pos=0;
+
+ int read_pos=echo_buffer_pos-predelay_frames;
+ while (read_pos<0)
+ read_pos+=echo_buffer_size;
+
+ float in=undenormalise(echo_buffer[read_pos]*params.predelay_fb+p_src[i]);
+
+ echo_buffer[echo_buffer_pos]=in;
+
+ input_buffer[i]=in;
+
+ p_dst[i]=0; //take the chance and clear this
+
+ echo_buffer_pos++;
+ }
+
+ if (params.hpf>0) {
+ float hpaux=expf(-2.0*Math_PI*params.hpf*6000/params.mix_rate);
+ float hp_a1=(1.0+hpaux)/2.0;
+ float hp_a2=-(1.0+hpaux)/2.0;
+ float hp_b1=hpaux;
+
+ for (int i=0;i<p_frames;i++) {
+
+ float in=input_buffer[i];
+ input_buffer[i]=in*hp_a1+hpf_h1*hp_a2+hpf_h2*hp_b1;
+ hpf_h2=input_buffer[i];
+ hpf_h1=in;
+ }
+ }
+
+ for (int i=0;i<MAX_COMBS;i++) {
+
+ Comb &c=comb[i];
+
+ int size_limit=c.size-lrintf((float)c.extra_spread_frames*(1.0-params.extra_spread));
+ for (int j=0;j<p_frames;j++) {
+
+ if (c.pos>=size_limit) //reset this now just in case
+ c.pos=0;
+
+ float out=undenormalise(c.buffer[c.pos]*c.feedback);
+ out=out*(1.0-c.damp)+c.damp_h*c.damp; //lowpass
+ c.damp_h=out;
+ c.buffer[c.pos]=input_buffer[j]+out;
+ p_dst[j]+=out;
+ c.pos++;
+ }
+
+ }
+
+
+ static const float allpass_feedback=0.7;
+ /* this one works, but the other version is just nicer....
+ int ap_size_limit[MAX_ALLPASS];
+
+ for (int i=0;i<MAX_ALLPASS;i++) {
+
+ AllPass &a=allpass[i];
+ ap_size_limit[i]=a.size-lrintf((float)a.extra_spread_frames*(1.0-params.extra_spread));
+ }
+
+ for (int i=0;i<p_frames;i++) {
+
+ float sample=p_dst[i];
+ float aux,in;
+ float AllPass*ap;
+
+#define PROCESS_ALLPASS(m_ap) \
+ ap=&allpass[m_ap]; \
+ if (ap->pos>=ap_size_limit[m_ap]) \
+ ap->pos=0; \
+ aux=undenormalise(ap->buffer[ap->pos]); \
+ in=sample; \
+ sample=-in+aux; \
+ ap->pos++;
+
+
+ PROCESS_ALLPASS(0);
+ PROCESS_ALLPASS(1);
+ PROCESS_ALLPASS(2);
+ PROCESS_ALLPASS(3);
+
+ p_dst[i]=sample;
+ }
+ */
+
+ for (int i=0;i<MAX_ALLPASS;i++) {
+
+ AllPass &a=allpass[i];
+ int size_limit=a.size-lrintf((float)a.extra_spread_frames*(1.0-params.extra_spread));
+
+ for (int j=0;j<p_frames;j++) {
+
+ if (a.pos>=size_limit)
+ a.pos=0;
+
+ float aux=a.buffer[a.pos];
+ a.buffer[a.pos]=undenormalise(allpass_feedback*aux+p_dst[j]);
+ p_dst[j]=aux-allpass_feedback*a.buffer[a.pos];
+ a.pos++;
+
+ }
+ }
+
+ static const float wet_scale=0.6;
+
+ for (int i=0;i<p_frames;i++) {
+
+
+ p_dst[i]=p_dst[i]*params.wet*wet_scale+p_src[i]*params.dry;
+ }
+
+}
+
+
+void Reverb::set_room_size(float p_size) {
+
+ params.room_size=p_size;
+ update_parameters();
+
+}
+void Reverb::set_damp(float p_damp) {
+
+ params.damp=p_damp;
+ update_parameters();
+
+}
+void Reverb::set_wet(float p_wet) {
+
+ params.wet=p_wet;
+
+}
+
+void Reverb::set_dry(float p_dry) {
+
+ params.dry=p_dry;
+
+}
+
+void Reverb::set_predelay(float p_predelay) {
+
+ params.predelay=p_predelay;
+}
+void Reverb::set_predelay_feedback(float p_predelay_fb) {
+
+ params.predelay_fb=p_predelay_fb;
+
+}
+
+void Reverb::set_highpass(float p_frq) {
+
+ if (p_frq>1)
+ p_frq=1;
+ if (p_frq<0)
+ p_frq=0;
+ params.hpf=p_frq;
+}
+
+void Reverb::set_extra_spread(float p_spread) {
+
+ params.extra_spread=p_spread;
+
+}
+
+
+void Reverb::set_mix_rate(float p_mix_rate) {
+
+ params.mix_rate=p_mix_rate;
+ configure_buffers();
+}
+
+void Reverb::set_extra_spread_base(float p_sec) {
+
+ params.extra_spread_base=p_sec;
+ configure_buffers();
+}
+
+
+void Reverb::configure_buffers() {
+
+ clear_buffers(); //clear if necesary
+
+ for (int i=0;i<MAX_COMBS;i++) {
+
+ Comb &c=comb[i];
+
+
+ c.extra_spread_frames=lrint(params.extra_spread_base*params.mix_rate);
+
+ int len=lrint(comb_tunings[i]*params.mix_rate)+c.extra_spread_frames;
+ if (len<5)
+ len=5; //may this happen?
+
+ c.buffer = memnew_arr(float,len);
+ c.pos=0;
+ for (int j=0;j<len;j++)
+ c.buffer[j]=0;
+ c.size=len;
+
+ }
+
+ for (int i=0;i<MAX_ALLPASS;i++) {
+
+ AllPass &a=allpass[i];
+
+ a.extra_spread_frames=lrint(params.extra_spread_base*params.mix_rate);
+
+ int len=lrint(allpass_tunings[i]*params.mix_rate)+a.extra_spread_frames;
+ if (len<5)
+ len=5; //may this happen?
+
+ a.buffer = memnew_arr(float,len);
+ a.pos=0;
+ for (int j=0;j<len;j++)
+ a.buffer[j]=0;
+ a.size=len;
+ }
+
+ echo_buffer_size=(int)(((float)MAX_ECHO_MS/1000.0)*params.mix_rate+1.0);
+ echo_buffer = memnew_arr(float,echo_buffer_size);
+ for (int i=0;i<echo_buffer_size;i++) {
+
+ echo_buffer[i]=0;
+ }
+
+ echo_buffer_pos=0;
+}
+
+
+void Reverb::update_parameters() {
+
+ //more freeverb derived constants
+ static const float room_scale = 0.28f;
+ static const float room_offset = 0.7f;
+
+ for (int i=0;i<MAX_COMBS;i++) {
+
+ Comb &c=comb[i];
+ c.feedback=room_offset+params.room_size*room_scale;
+ if (c.feedback<room_offset)
+ c.feedback=room_offset;
+ else if (c.feedback>(room_offset+room_scale))
+ c.feedback=(room_offset+room_scale);
+
+ float auxdmp=params.damp/2.0+0.5; //only half the range (0.5 .. 1.0 is enough)
+ auxdmp*=auxdmp;
+
+ c.damp=expf(-2.0*Math_PI*auxdmp*10000/params.mix_rate); // 0 .. 10khz
+ }
+
+}
+
+void Reverb::clear_buffers() {
+
+ if (echo_buffer)
+ memdelete_arr(echo_buffer);
+
+ for (int i=0;i<MAX_COMBS;i++) {
+
+ if (comb[i].buffer)
+ memdelete_arr(comb[i].buffer);
+
+ comb[i].buffer=0;
+
+ }
+
+ for (int i=0;i<MAX_ALLPASS;i++) {
+
+ if (allpass[i].buffer)
+ memdelete_arr(allpass[i].buffer);
+
+ allpass[i].buffer=0;
+ }
+
+}
+
+Reverb::Reverb() {
+
+ params.room_size=0.8;
+ params.damp=0.5;
+ params.dry=1.0;
+ params.wet=0.0;
+ params.mix_rate=44100;
+ params.extra_spread_base=0;
+ params.extra_spread=1.0;
+ params.predelay=150;
+ params.predelay_fb=0.4;
+ params.hpf=0;
+ hpf_h1=0;
+ hpf_h2=0;
+
+
+ input_buffer=memnew_arr(float,INPUT_BUFFER_MAX_SIZE);
+ echo_buffer=0;
+
+ configure_buffers();
+ update_parameters();
+
+
+}
+
+
+Reverb::~Reverb() {
+
+ memdelete_arr(input_buffer);
+ clear_buffers();
+}
+
+
diff --git a/servers/audio/effects/reverb.h b/servers/audio/effects/reverb.h
new file mode 100644
index 0000000000..2c82be9156
--- /dev/null
+++ b/servers/audio/effects/reverb.h
@@ -0,0 +1,111 @@
+//
+// C++ Interface: reverb
+//
+// Description:
+//
+//
+// Author: Juan Linietsky <reduzio@gmail.com>, (C) 2006
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef REVERB_H
+#define REVERB_H
+
+#include "typedefs.h"
+#include "os/memory.h"
+#include "audio_frame.h"
+
+class Reverb {
+public:
+ enum {
+ INPUT_BUFFER_MAX_SIZE=1024,
+
+ };
+private:
+ enum {
+
+ MAX_COMBS=8,
+ MAX_ALLPASS=4,
+ MAX_ECHO_MS=500
+
+ };
+
+
+
+ static const float comb_tunings[MAX_COMBS];
+ static const float allpass_tunings[MAX_ALLPASS];
+
+ struct Comb {
+
+ int size;
+ float *buffer;
+ float feedback;
+ float damp; //lowpass
+ float damp_h; //history
+ int pos;
+ int extra_spread_frames;
+
+ Comb() { size=0; buffer=0; feedback=0; damp_h=0; pos=0; }
+ };
+
+ struct AllPass {
+
+ int size;
+ float *buffer;
+ int pos;
+ int extra_spread_frames;
+ AllPass() { size=0; buffer=0; pos=0; }
+ };
+
+ Comb comb[MAX_COMBS];
+ AllPass allpass[MAX_ALLPASS];
+ float *input_buffer;
+ float *echo_buffer;
+ int echo_buffer_size;
+ int echo_buffer_pos;
+
+ float hpf_h1,hpf_h2;
+
+
+ struct Parameters {
+
+ float room_size;
+ float damp;
+ float wet;
+ float dry;
+ float mix_rate;
+ float extra_spread_base;
+ float extra_spread;
+ float predelay;
+ float predelay_fb;
+ float hpf;
+ } params;
+
+ void configure_buffers();
+ void update_parameters();
+ void clear_buffers();
+public:
+
+ void set_room_size(float p_size);
+ void set_damp(float p_damp);
+ void set_wet(float p_wet);
+ void set_dry(float p_dry);
+ void set_predelay(float p_predelay); // in ms
+ void set_predelay_feedback(float p_predelay_fb); // in ms
+ void set_highpass(float p_frq);
+ void set_mix_rate(float p_mix_rate);
+ void set_extra_spread(float p_spread);
+ void set_extra_spread_base(float p_sec);
+
+ void process(float *p_src,float *p_dst,int p_frames);
+
+ Reverb();
+
+ ~Reverb();
+
+};
+
+
+
+#endif
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 9b938a7f86..8a8b9ebf76 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -29,6 +29,19 @@
#include "audio_server.h"
#include "globals.h"
#include "os/os.h"
+#include "servers/audio/effects/audio_effect_compressor.h"
+#include "io/resource_loader.h"
+#include "os/file_access.h"
+#ifdef TOOLS_ENABLED
+
+#define MARK_EDITED set_edited(true);
+
+#else
+
+#define MARK_EDITED
+
+#endif
+
AudioDriver *AudioDriver::singleton=NULL;
AudioDriver *AudioDriver::get_singleton() {
@@ -42,12 +55,16 @@ void AudioDriver::set_singleton() {
void AudioDriver::audio_server_process(int p_frames,int32_t *p_buffer,bool p_update_mix_time) {
- AudioServer * audio_server = static_cast<AudioServer*>(AudioServer::get_singleton());
+
if (p_update_mix_time)
update_mix_time(p_frames);
-// audio_server->driver_process(p_frames,p_buffer);
+
+ if (AudioServer::get_singleton())
+ AudioServer::get_singleton()->_driver_process(p_frames,p_buffer);
}
+
+
void AudioDriver::update_mix_time(int p_frames) {
_mix_amount+=p_frames;
@@ -74,7 +91,6 @@ AudioDriver *AudioDriverManager::drivers[MAX_DRIVERS];
int AudioDriverManager::driver_count=0;
-
void AudioDriverManager::add_driver(AudioDriver *p_driver) {
ERR_FAIL_COND(driver_count>=MAX_DRIVERS);
@@ -97,62 +113,548 @@ AudioDriver *AudioDriverManager::get_driver(int p_driver) {
//////////////////////////////////////////////
//////////////////////////////////////////////
+void AudioServer::_driver_process(int p_frames,int32_t* p_buffer) {
+
+ int todo=p_frames;
+
+ while(todo) {
+
+ if (to_mix==0) {
+ _mix_step();
+ }
+
+ int to_copy = MIN(to_mix,todo);
+
+ Bus *master = buses[0];
+
+ int from = buffer_size-to_mix;
+ int from_buf=p_frames-todo;
+
+ //master master, send to output
+ int cs = master->channels.size();
+ for(int k=0;k<cs;k++) {
+
+ if (master->channels[k].active) {
+
+ AudioFrame *buf = master->channels[k].buffer.ptr();
+
+ for(int j=0;j<to_copy;j++) {
+
+ float l = CLAMP(buf[from+j].l,-1.0,1.0);
+ int32_t vl = l*((1<<20)-1);
+ p_buffer[(from_buf+j)*(cs*2)+k*2+0]=vl<<11;
+
+ float r = CLAMP(buf[from+j].r,-1.0,1.0);
+ int32_t vr = r*((1<<20)-1);
+ p_buffer[(from_buf+j)*(cs*2)+k*2+1]=vr<<11;
+ }
+
+ } else {
+ for(int j=0;j<to_copy;j++) {
+
+ p_buffer[(from_buf+j)*(cs*2)+k*2+0]=0;
+ p_buffer[(from_buf+j)*(cs*2)+k*2+1]=0;
+ }
+ }
+
+ }
+
+ todo-=to_copy;
+ to_mix-=to_copy;
+
+ }
+
+}
+
+void AudioServer::_mix_step() {
+
+ for(int i=0;i<buses.size();i++) {
+ Bus *bus = buses[i];
+ bus->index_cache=i; //might be moved around by editor, so..
+ for(int k=0;k<bus->channels.size();k++) {
+
+ bus->channels[k].used=false;
+ }
+ }
+
+ //make callbacks for mixing the audio
+ for (Set<CallbackItem>::Element *E=callbacks.front();E;E=E->next()) {
+
+ E->get().callback(E->get().userdata);
+ }
+
+ for(int i=buses.size()-1;i>=0;i--) {
+ //go bus by bus
+ Bus *bus = buses[i];
+
+
+ for(int k=0;k<bus->channels.size();k++) {
+
+ if (bus->channels[k].active && !bus->channels[k].used) {
+ //buffer was not used, but it's still active, so it must be cleaned
+ AudioFrame *buf = bus->channels[k].buffer.ptr();
+
+ for(uint32_t j=0;j<buffer_size;j++) {
+
+ buf[j]=AudioFrame(0,0);
+ }
+ }
+
+ }
+
+
+ //process effects
+ for(int j=0;j<bus->effects.size();j++) {
+
+ if (!bus->effects[j].enabled)
+ continue;
+
+ for(int k=0;k<bus->channels.size();k++) {
+
+ if (!bus->channels[k].active)
+ continue;
+ bus->channels[k].effect_instances[j]->process(bus->channels[k].buffer.ptr(),temp_buffer[k].ptr(),buffer_size);
+ }
+
+ //swap buffers, so internal buffer always has the right data
+ for(int k=0;k<bus->channels.size();k++) {
+
+ if (!buses[i]->channels[k].active)
+ continue;
+ SWAP(bus->channels[k].buffer,temp_buffer[k]);
+ }
+ }
+
+ //process send
+
+ Bus *send=NULL;
+
+ if (i>0) {
+ //everything has a send save for master bus
+ if (!bus_map.has(bus->send)) {
+ send=buses[0];
+ } else {
+ send=bus_map[bus->send];
+ if (send->index_cache>=bus->index_cache) { //invalid, send to master
+ send=buses[0];
+ }
+ }
+ }
+
+
+ for(int k=0;k<bus->channels.size();k++) {
+
+ if (!bus->channels[k].active)
+ continue;
+
+ AudioFrame *buf = bus->channels[k].buffer.ptr();
+
+
+ AudioFrame peak = AudioFrame(0,0);
+ for(uint32_t j=0;j<buffer_size;j++) {
+ float l = ABS(buf[j].l);
+ if (l>peak.l) {
+ peak.l=l;
+ }
+ float r = ABS(buf[j].r);
+ if (r>peak.r) {
+ peak.r=r;
+ }
+ }
+
+ bus->channels[k].peak_volume=AudioFrame(Math::linear2db(peak.l+0.0000000001),Math::linear2db(peak.r+0.0000000001));
+
+
+ if (!bus->channels[k].used) {
+ //see if any audio is contained, because channel was not used
+
+
+ if (MAX(peak.r,peak.l) > Math::db2linear(channel_disable_treshold_db)) {
+ bus->channels[k].last_mix_with_audio=mix_frames;
+ } else if (mix_frames-bus->channels[k].last_mix_with_audio > channel_disable_frames ) {
+ bus->channels[k].active=false;
+ continue; //went inactive, dont mix.
+ }
+ }
+
+ if (send) {
+ //if not master bus, send
+ AudioFrame *target_buf = thread_get_channel_mix_buffer(send->index_cache,k);
+
+ for(uint32_t j=0;j<buffer_size;j++) {
+ target_buf[j]+=buf[j];
+ }
+ }
+
+ }
+
+ }
+
+
+ mix_frames+=buffer_size;
+ to_mix=buffer_size;
+
+}
+
+AudioFrame *AudioServer::thread_get_channel_mix_buffer(int p_bus,int p_buffer) {
+
+ ERR_FAIL_INDEX_V(p_bus,buses.size(),NULL);
+ ERR_FAIL_INDEX_V(p_buffer,buses[p_bus]->channels.size(),NULL);
+
+ AudioFrame *data = buses[p_bus]->channels[p_buffer].buffer.ptr();
+
+
+ if (!buses[p_bus]->channels[p_buffer].used) {
+ buses[p_bus]->channels[p_buffer].used=true;
+ buses[p_bus]->channels[p_buffer].active=true;
+ buses[p_bus]->channels[p_buffer].last_mix_with_audio=mix_frames;
+ for(uint32_t i=0;i<buffer_size;i++) {
+ data[i]=AudioFrame(0,0);
+ }
+ }
+
+ return data;
+}
+
+int AudioServer::thread_get_mix_buffer_size() const {
+
+ return buffer_size;
+}
+
+int AudioServer::thread_find_bus_index(const StringName& p_name) {
+
+ if (bus_map.has(p_name)) {
+ return bus_map[p_name]->index_cache;
+ } else {
+ return 0;
+ }
+
+}
+
void AudioServer::set_bus_count(int p_count) {
ERR_FAIL_COND(p_count<1);
ERR_FAIL_INDEX(p_count,256);
+
+ MARK_EDITED
+
lock();
+ int cb = buses.size();
+
+ if (p_count<buses.size()) {
+ for(int i=p_count;i<buses.size();i++) {
+ bus_map.erase(buses[i]->name);
+ memdelete(buses[i]);
+ }
+ }
+
buses.resize(p_count);
+
+ for(int i=cb;i<buses.size();i++) {
+
+ String attempt="New Bus";
+ int attempts=1;
+ while(true) {
+
+ bool name_free=true;
+ for(int j=0;j<i;j++) {
+
+ if (buses[j]->name==attempt) {
+ name_free=false;
+ break;
+ }
+ }
+
+ if (!name_free) {
+ attempts++;
+ attempt="New Bus " +itos(attempts);
+ } else {
+ break;
+ }
+
+ }
+
+
+ buses[i]=memnew(Bus);
+ buses[i]->channels.resize(_get_channel_count());
+ for(int j=0;j<_get_channel_count();j++) {
+ buses[i]->channels[j].buffer.resize(buffer_size);
+ }
+ buses[i]->name=attempt;
+ buses[i]->solo=false;
+ buses[i]->mute=false;
+ buses[i]->bypass=false;
+ buses[i]->volume_db=0;
+ if (i>0) {
+ buses[i]->send="Master";
+ }
+
+ bus_map[attempt]=buses[i];
+
+ }
+
unlock();
+
+ emit_signal("bus_layout_changed");
}
-int AudioServer::get_bus_count() const {
- return buses.size();
+void AudioServer::remove_bus(int p_index) {
+
+ ERR_FAIL_INDEX(p_index,buses.size());
+ ERR_FAIL_COND(p_index==0);
+
+ MARK_EDITED
+
+ lock();
+ bus_map.erase(buses[p_index]->name);
+ memdelete(buses[p_index]);
+ buses.remove(p_index);
+ unlock();
}
-void AudioServer::set_bus_mode(int p_bus,BusMode p_mode) {
+void AudioServer::add_bus(int p_at_pos) {
- ERR_FAIL_INDEX(p_bus,buses.size());
+ MARK_EDITED
+
+ if (p_at_pos>=buses.size()) {
+ p_at_pos=-1;
+ } else if (p_at_pos==0) {
+ if (buses.size()>1)
+ p_at_pos=1;
+ else
+ p_at_pos=-1;
+ }
+
+ String attempt="New Bus";
+ int attempts=1;
+ while(true) {
+
+ bool name_free=true;
+ for(int j=0;j<buses.size();j++) {
+
+ if (buses[j]->name==attempt) {
+ name_free=false;
+ break;
+ }
+ }
+
+ if (!name_free) {
+ attempts++;
+ attempt="New Bus " +itos(attempts);
+ } else {
+ break;
+ }
+
+ }
+
+ Bus* bus =memnew(Bus);
+ bus->channels.resize(_get_channel_count());
+ for(int j=0;j<_get_channel_count();j++) {
+ bus->channels[j].buffer.resize(buffer_size);
+ }
+ bus->name=attempt;
+ bus->solo=false;
+ bus->mute=false;
+ bus->bypass=false;
+ bus->volume_db=0;
+
+ bus_map[attempt]=bus;
+
+ if (p_at_pos==-1)
+ buses.push_back(bus);
+ else
+ buses.insert(p_at_pos,bus);
}
-AudioServer::BusMode AudioServer::get_bus_mode(int p_bus) const {
- ERR_FAIL_INDEX_V(p_bus,buses.size(),BUS_MODE_STEREO);
+void AudioServer::move_bus(int p_bus,int p_to_pos) {
+
+ ERR_FAIL_COND(p_bus<1 || p_bus>=buses.size());
+ ERR_FAIL_COND(p_to_pos!=-1 && (p_to_pos<1 || p_to_pos>buses.size()));
+
+ MARK_EDITED
+
+ if (p_bus==p_to_pos)
+ return;
- return buses[p_bus].mode;
+ Bus *bus = buses[p_bus];
+ buses.remove(p_bus);
+
+ if (p_to_pos==-1) {
+ buses.push_back(bus);
+ } else if (p_to_pos<p_bus) {
+ buses.insert(p_to_pos,bus);
+ } else {
+ buses.insert(p_to_pos-1,bus);
+ }
}
+int AudioServer::get_bus_count() const {
+
+ return buses.size();
+}
+
+
void AudioServer::set_bus_name(int p_bus,const String& p_name) {
ERR_FAIL_INDEX(p_bus,buses.size());
- buses[p_bus].name=p_name;
+ if (p_bus==0 && p_name!="Master")
+ return; //bus 0 is always master
+
+ MARK_EDITED
+
+ lock();
+
+ if (buses[p_bus]->name==p_name) {
+ unlock();
+ return;
+ }
+
+ String attempt=p_name;
+ int attempts=1;
+
+ while(true) {
+
+ bool name_free=true;
+ for(int i=0;i<buses.size();i++) {
+
+ if (buses[i]->name==attempt) {
+ name_free=false;
+ break;
+ }
+ }
+
+ if (name_free) {
+ break;
+ }
+
+ attempts++;
+ attempt=p_name+" "+itos(attempts);
+ }
+ bus_map.erase(buses[p_bus]->name);
+ buses[p_bus]->name=attempt;
+ bus_map[attempt]=buses[p_bus];
+ unlock();
+
+ emit_signal("bus_layout_changed");
}
String AudioServer::get_bus_name(int p_bus) const {
ERR_FAIL_INDEX_V(p_bus,buses.size(),String());
- return buses[p_bus].name;
+ return buses[p_bus]->name;
}
void AudioServer::set_bus_volume_db(int p_bus,float p_volume_db) {
ERR_FAIL_INDEX(p_bus,buses.size());
- buses[p_bus].volume_db=p_volume_db;
+
+ MARK_EDITED
+
+ buses[p_bus]->volume_db=p_volume_db;
}
float AudioServer::get_bus_volume_db(int p_bus) const {
ERR_FAIL_INDEX_V(p_bus,buses.size(),0);
- return buses[p_bus].volume_db;
+ return buses[p_bus]->volume_db;
+
+}
+
+void AudioServer::set_bus_send(int p_bus,const StringName& p_send) {
+
+ ERR_FAIL_INDEX(p_bus,buses.size());
+
+ MARK_EDITED
+
+ buses[p_bus]->send=p_send;
+
+}
+
+StringName AudioServer::get_bus_send(int p_bus) const {
+
+ ERR_FAIL_INDEX_V(p_bus,buses.size(),StringName());
+ return buses[p_bus]->send;
}
+
+void AudioServer::set_bus_solo(int p_bus,bool p_enable) {
+
+ ERR_FAIL_INDEX(p_bus,buses.size());
+
+ MARK_EDITED
+
+ buses[p_bus]->solo=p_enable;
+
+}
+
+bool AudioServer::is_bus_solo(int p_bus) const{
+
+ ERR_FAIL_INDEX_V(p_bus,buses.size(),false);
+
+ return buses[p_bus]->solo;
+
+}
+
+void AudioServer::set_bus_mute(int p_bus,bool p_enable){
+
+ ERR_FAIL_INDEX(p_bus,buses.size());
+
+ MARK_EDITED
+
+ buses[p_bus]->mute=p_enable;
+}
+bool AudioServer::is_bus_mute(int p_bus) const{
+
+ ERR_FAIL_INDEX_V(p_bus,buses.size(),false);
+
+ return buses[p_bus]->mute;
+
+}
+
+void AudioServer::set_bus_bypass_effects(int p_bus,bool p_enable){
+
+ ERR_FAIL_INDEX(p_bus,buses.size());
+
+ MARK_EDITED
+
+ buses[p_bus]->bypass=p_enable;
+}
+bool AudioServer::is_bus_bypassing_effects(int p_bus) const{
+
+ ERR_FAIL_INDEX_V(p_bus,buses.size(),false);
+
+ return buses[p_bus]->bypass;
+
+}
+
+
+void AudioServer::_update_bus_effects(int p_bus) {
+
+ for(int i=0;i<buses[p_bus]->channels.size();i++) {
+ buses[p_bus]->channels[i].effect_instances.resize(buses[p_bus]->effects.size());
+ for(int j=0;j<buses[p_bus]->effects.size();j++) {
+ Ref<AudioEffectInstance> fx = buses[p_bus]->effects[j].effect->instance();
+ if (fx->cast_to<AudioEffectCompressorInstance>()) {
+ fx->cast_to<AudioEffectCompressorInstance>()->set_current_channel(i);
+ }
+ buses[p_bus]->channels[i].effect_instances[j]=fx;
+
+ }
+ }
+}
+
+
void AudioServer::add_bus_effect(int p_bus,const Ref<AudioEffect>& p_effect,int p_at_pos) {
ERR_FAIL_COND(p_effect.is_null());
ERR_FAIL_INDEX(p_bus,buses.size());
+ MARK_EDITED
+
+
lock();
Bus::Effect fx;
@@ -160,12 +662,14 @@ void AudioServer::add_bus_effect(int p_bus,const Ref<AudioEffect>& p_effect,int
//fx.instance=p_effect->instance();
fx.enabled=true;
- if (p_at_pos>=buses[p_bus].effects.size() || p_at_pos<0) {
- buses[p_bus].effects.push_back(fx);
+ if (p_at_pos>=buses[p_bus]->effects.size() || p_at_pos<0) {
+ buses[p_bus]->effects.push_back(fx);
} else {
- buses[p_bus].effects.insert(p_at_pos,fx);
+ buses[p_bus]->effects.insert(p_at_pos,fx);
}
+ _update_bus_effects(p_bus);
+
unlock();
}
@@ -174,9 +678,13 @@ void AudioServer::remove_bus_effect(int p_bus,int p_effect) {
ERR_FAIL_INDEX(p_bus,buses.size());
+ MARK_EDITED
+
+
lock();
- buses[p_bus].effects.remove(p_effect);
+ buses[p_bus]->effects.remove(p_effect);
+ _update_bus_effects(p_bus);
unlock();
}
@@ -185,52 +693,131 @@ int AudioServer::get_bus_effect_count(int p_bus) {
ERR_FAIL_INDEX_V(p_bus,buses.size(),0);
- return buses[p_bus].effects.size();
+ return buses[p_bus]->effects.size();
}
Ref<AudioEffect> AudioServer::get_bus_effect(int p_bus,int p_effect) {
ERR_FAIL_INDEX_V(p_bus,buses.size(),Ref<AudioEffect>());
- ERR_FAIL_INDEX_V(p_effect,buses[p_bus].effects.size(),Ref<AudioEffect>());
+ ERR_FAIL_INDEX_V(p_effect,buses[p_bus]->effects.size(),Ref<AudioEffect>());
- return buses[p_bus].effects[p_effect].effect;
+ return buses[p_bus]->effects[p_effect].effect;
}
void AudioServer::swap_bus_effects(int p_bus,int p_effect,int p_by_effect) {
ERR_FAIL_INDEX(p_bus,buses.size());
- ERR_FAIL_INDEX(p_effect,buses[p_bus].effects.size());
- ERR_FAIL_INDEX(p_by_effect,buses[p_bus].effects.size());
+ ERR_FAIL_INDEX(p_effect,buses[p_bus]->effects.size());
+ ERR_FAIL_INDEX(p_by_effect,buses[p_bus]->effects.size());
+
+ MARK_EDITED
+
lock();
- SWAP( buses[p_bus].effects[p_effect], buses[p_bus].effects[p_by_effect] );
+ SWAP( buses[p_bus]->effects[p_effect], buses[p_bus]->effects[p_by_effect] );
+ _update_bus_effects(p_bus);
unlock();
}
void AudioServer::set_bus_effect_enabled(int p_bus,int p_effect,bool p_enabled) {
ERR_FAIL_INDEX(p_bus,buses.size());
- ERR_FAIL_INDEX(p_effect,buses[p_bus].effects.size());
- buses[p_bus].effects[p_effect].enabled=p_enabled;
+ ERR_FAIL_INDEX(p_effect,buses[p_bus]->effects.size());
+
+ MARK_EDITED
+
+
+ buses[p_bus]->effects[p_effect].enabled=p_enabled;
}
bool AudioServer::is_bus_effect_enabled(int p_bus,int p_effect) const {
ERR_FAIL_INDEX_V(p_bus,buses.size(),false);
- ERR_FAIL_INDEX_V(p_effect,buses[p_bus].effects.size(),false);
- return buses[p_bus].effects[p_effect].enabled;
+ ERR_FAIL_INDEX_V(p_effect,buses[p_bus]->effects.size(),false);
+ return buses[p_bus]->effects[p_effect].enabled;
+
+}
+
+
+float AudioServer::get_bus_peak_volume_left_db(int p_bus,int p_channel) const {
+
+ ERR_FAIL_INDEX_V(p_bus,buses.size(),0);
+ ERR_FAIL_INDEX_V(p_channel,buses[p_bus]->channels.size(),0);
+
+ return buses[p_bus]->channels[p_channel].peak_volume.l;
+
+}
+float AudioServer::get_bus_peak_volume_right_db(int p_bus,int p_channel) const {
+
+ ERR_FAIL_INDEX_V(p_bus,buses.size(),0);
+ ERR_FAIL_INDEX_V(p_channel,buses[p_bus]->channels.size(),0);
+
+ return buses[p_bus]->channels[p_channel].peak_volume.r;
+
+}
+
+bool AudioServer::is_bus_channel_active(int p_bus,int p_channel) const {
+
+ ERR_FAIL_INDEX_V(p_bus,buses.size(),false);
+ ERR_FAIL_INDEX_V(p_channel,buses[p_bus]->channels.size(),false);
+
+ return buses[p_bus]->channels[p_channel].active;
}
void AudioServer::init() {
+ channel_disable_treshold_db=GLOBAL_DEF("audio/channel_disable_treshold_db",-60.0);
+ channel_disable_frames=float(GLOBAL_DEF("audio/channel_disable_time",2.0))*get_mix_rate();
+ buffer_size=1024; //harcoded for now
+ switch( get_speaker_mode() ) {
+ case SPEAKER_MODE_STEREO: {
+ temp_buffer.resize(1);
+ } break;
+ case SPEAKER_SURROUND_51: {
+ temp_buffer.resize(3);
+ } break;
+ case SPEAKER_SURROUND_71: {
+ temp_buffer.resize(4);
+ } break;
+ }
+
+ for(int i=0;i<temp_buffer.size();i++) {
+ temp_buffer[i].resize(buffer_size);
+ }
+
+ mix_count=0;
set_bus_count(1);;
set_bus_name(0,"Master");
+
+
+ if (AudioDriver::get_singleton())
+ AudioDriver::get_singleton()->start();
+#ifdef TOOLS_ENABLED
+ set_edited(false); //avoid editors from thinking this was edited
+#endif
+
+}
+
+void AudioServer::load_default_bus_layout() {
+
+ if (FileAccess::exists("res://default_bus_layout.tres")) {
+ Ref<AudioBusLayout> default_layout = ResourceLoader::load("res://default_bus_layout.tres");
+ if (default_layout.is_valid()) {
+ set_bus_layout(default_layout);
+ }
+ }
+
}
+
void AudioServer::finish() {
+ for(int i=0;i<buses.size();i++) {
+ memdelete(buses[i]);
+ }
+
buses.clear();
}
void AudioServer::update() {
@@ -282,18 +869,353 @@ double AudioServer::get_output_delay() const {
AudioServer* AudioServer::singleton=NULL;
-void AudioServer::_bind_methods() {
+
+void* AudioServer::audio_data_alloc(uint32_t p_data_len,const uint8_t *p_from_data) {
+
+ void * ad = memalloc( p_data_len );
+ ERR_FAIL_COND_V(!ad,NULL);
+ if (p_from_data) {
+ copymem(ad,p_from_data,p_data_len);
+ }
+
+ audio_data_lock->lock();
+ audio_data[ad]=p_data_len;
+ audio_data_total_mem+=p_data_len;
+ audio_data_max_mem=MAX(audio_data_total_mem,audio_data_max_mem);
+ audio_data_lock->unlock();
+
+ return ad;
+}
+
+void AudioServer::audio_data_free(void* p_data) {
+
+ audio_data_lock->lock();
+ if (!audio_data.has(p_data)) {
+ audio_data_lock->unlock();
+ ERR_FAIL();
+ }
+
+ audio_data_total_mem-=audio_data[p_data];
+ audio_data.erase(p_data);
+ memfree(p_data);
+ audio_data_lock->unlock();
+
+
+}
+
+size_t AudioServer::audio_data_get_total_memory_usage() const{
+
+ return audio_data_total_mem;
+}
+size_t AudioServer::audio_data_get_max_memory_usage() const{
+
+ return audio_data_max_mem;
+
+}
+
+void AudioServer::add_callback(AudioCallback p_callback,void *p_userdata) {
+ lock();
+ CallbackItem ci;
+ ci.callback=p_callback;
+ ci.userdata=p_userdata;
+ callbacks.insert(ci);
+ unlock();
+}
+
+void AudioServer::remove_callback(AudioCallback p_callback,void *p_userdata) {
+
+ lock();
+ CallbackItem ci;
+ ci.callback=p_callback;
+ ci.userdata=p_userdata;
+ callbacks.erase(ci);
+ unlock();
+
+}
+
+void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_state) {
+
+ ERR_FAIL_COND(p_state.is_null() || p_state->buses.size()==0);
+
+ lock();
+ for(int i=0;i<buses.size();i++) {
+ memdelete(buses[i]);
+ }
+ buses.resize(p_state->buses.size());
+ bus_map.clear();
+ for(int i=0;i<p_state->buses.size();i++) {
+ Bus * bus = memnew(Bus);
+ if (i==0) {
+ bus->name="Master";
+ } else {
+ bus->name=p_state->buses[i].name;
+ bus->send=p_state->buses[i].send;
+ }
+
+ bus->solo=p_state->buses[i].solo;
+ bus->mute=p_state->buses[i].mute;
+ bus->bypass=p_state->buses[i].bypass;
+ bus->volume_db=p_state->buses[i].volume_db;
+
+ for(int j=0;j<p_state->buses[i].effects.size();j++) {
+
+ Ref<AudioEffect> fx = p_state->buses[i].effects[j].effect;
+
+ if (fx.is_valid()) {
+
+ Bus::Effect bfx;
+ bfx.effect=fx;
+ bfx.enabled=p_state->buses[i].effects[j].enabled;
+ bus->effects.push_back(bfx);
+ }
+ }
+
+ bus_map[bus->name]=bus;
+ buses[i]=bus;
+
+ buses[i]->channels.resize(_get_channel_count());
+ for(int j=0;j<_get_channel_count();j++) {
+ buses[i]->channels[j].buffer.resize(buffer_size);
+ }
+ _update_bus_effects(i);
+ }
+#ifdef TOOLS_ENABLED
+ set_edited(false);
+#endif
+ unlock();
+
+}
+
+
+Ref<AudioBusLayout> AudioServer::generate_bus_layout() const {
+
+ Ref<AudioBusLayout> state;
+ state.instance();
+
+ state->buses.resize( buses.size() );
+
+ for(int i=0;i<buses.size();i++) {
+
+ state->buses[i].name=buses[i]->name;
+ state->buses[i].send=buses[i]->send;
+ state->buses[i].mute=buses[i]->mute;
+ state->buses[i].solo=buses[i]->solo;
+ state->buses[i].bypass=buses[i]->bypass;
+ state->buses[i].volume_db=buses[i]->volume_db;
+ for(int j=0;j<buses[i]->effects.size();j++) {
+ AudioBusLayout::Bus::Effect fx;
+ fx.effect=buses[i]->effects[j].effect;
+ fx.enabled=buses[i]->effects[j].enabled;
+ state->buses[i].effects.push_back(fx);
+
+ }
+ }
+
+ return state;
}
+void AudioServer::_bind_methods() {
+
+
+ ClassDB::bind_method(_MD("set_bus_count","amount"),&AudioServer::set_bus_count);
+ ClassDB::bind_method(_MD("get_bus_count"),&AudioServer::get_bus_count);
+
+ ClassDB::bind_method(_MD("remove_bus","index"),&AudioServer::remove_bus);
+ ClassDB::bind_method(_MD("add_bus","at_pos"),&AudioServer::add_bus,DEFVAL(-1));
+ ClassDB::bind_method(_MD("move_bus","index","to_index"),&AudioServer::move_bus);
+
+ ClassDB::bind_method(_MD("set_bus_name","bus_idx","name"),&AudioServer::set_bus_name);
+ ClassDB::bind_method(_MD("get_bus_name","bus_idx"),&AudioServer::get_bus_name);
+
+ ClassDB::bind_method(_MD("set_bus_volume_db","bus_idx","volume_db"),&AudioServer::set_bus_volume_db);
+ ClassDB::bind_method(_MD("get_bus_volume_db","bus_idx"),&AudioServer::get_bus_volume_db);
+
+ ClassDB::bind_method(_MD("set_bus_send","bus_idx","send"),&AudioServer::set_bus_send);
+ ClassDB::bind_method(_MD("get_bus_send","bus_idx"),&AudioServer::get_bus_send);
+
+ ClassDB::bind_method(_MD("set_bus_solo","bus_idx","enable"),&AudioServer::set_bus_solo);
+ ClassDB::bind_method(_MD("is_bus_solo","bus_idx"),&AudioServer::is_bus_solo);
+
+ ClassDB::bind_method(_MD("set_bus_mute","bus_idx","enable"),&AudioServer::set_bus_mute);
+ ClassDB::bind_method(_MD("is_bus_mute","bus_idx"),&AudioServer::is_bus_mute);
+
+ ClassDB::bind_method(_MD("set_bus_bypass_effects","bus_idx","enable"),&AudioServer::set_bus_bypass_effects);
+ ClassDB::bind_method(_MD("is_bus_bypassing_effects","bus_idx"),&AudioServer::is_bus_bypassing_effects);
+
+ ClassDB::bind_method(_MD("add_bus_effect","bus_idx","effect:AudioEffect"),&AudioServer::add_bus_effect,DEFVAL(-1));
+ ClassDB::bind_method(_MD("remove_bus_effect","bus_idx","effect_idx"),&AudioServer::remove_bus_effect);
+
+ ClassDB::bind_method(_MD("get_bus_effect_count","bus_idx"),&AudioServer::add_bus_effect);
+ ClassDB::bind_method(_MD("get_bus_effect:AudioEffect","bus_idx","effect_idx"),&AudioServer::get_bus_effect);
+ ClassDB::bind_method(_MD("swap_bus_effects","bus_idx","effect_idx","by_effect_idx"),&AudioServer::swap_bus_effects);
+
+ ClassDB::bind_method(_MD("set_bus_effect_enabled","bus_idx","effect_idx","enabled"),&AudioServer::set_bus_effect_enabled);
+ ClassDB::bind_method(_MD("is_bus_effect_enabled","bus_idx","effect_idx"),&AudioServer::is_bus_effect_enabled);
+
+ ClassDB::bind_method(_MD("get_bus_peak_volume_left_db","bus_idx","channel"),&AudioServer::get_bus_peak_volume_left_db);
+ ClassDB::bind_method(_MD("get_bus_peak_volume_right_db","bus_idx","channel"),&AudioServer::get_bus_peak_volume_right_db);
+
+ ClassDB::bind_method(_MD("lock"),&AudioServer::lock);
+ ClassDB::bind_method(_MD("unlock"),&AudioServer::unlock);
+
+ ClassDB::bind_method(_MD("get_speaker_mode"),&AudioServer::get_speaker_mode);
+ ClassDB::bind_method(_MD("get_mix_rate"),&AudioServer::get_mix_rate);
+
+ ClassDB::bind_method(_MD("set_state","state:AudioServerState"),&AudioServer::set_bus_layout);
+ ClassDB::bind_method(_MD("generate_state:AudioServerState"),&AudioServer::generate_bus_layout);
+
+ ADD_SIGNAL(MethodInfo("bus_layout_changed") );
+}
+
AudioServer::AudioServer() {
singleton=this;
+ audio_data_total_mem=0;
+ audio_data_max_mem=0;
+ audio_data_lock=Mutex::create();
+ mix_frames=0;
+ to_mix=0;
+
}
AudioServer::~AudioServer() {
+ memdelete(audio_data_lock);
+}
+
+/////////////////////////////////
+
+
+
+bool AudioBusLayout::_set(const StringName& p_name, const Variant& p_value) {
+
+ String s = p_name;
+ if (s.begins_with("bus/")) {
+ int index = s.get_slice("/",1).to_int();
+ if (buses.size()<=index) {
+ buses.resize(index+1);
+ }
+
+ Bus &bus = buses[index];
+
+ String what = s.get_slice("/",2);
+
+ if (what=="name") {
+ bus.name=p_value;
+ } else if (what=="solo") {
+ bus.solo=p_value;
+ } else if (what=="mute") {
+ bus.mute=p_value;
+ } else if (what=="bypass_fx") {
+ bus.bypass=p_value;
+ } else if (what=="volume_db") {
+ bus.volume_db=p_value;
+ } else if (what=="send") {
+ bus.send=p_value;
+ } else if (what=="effect") {
+ int which = s.get_slice("/",3).to_int();
+ if (bus.effects.size()<=which) {
+ bus.effects.resize(which+1);
+ }
+
+ Bus::Effect &fx = bus.effects[which];
+
+ String fxwhat = s.get_slice("/",4);
+ if (fxwhat=="effect") {
+ fx.effect=p_value;
+ } else if (fxwhat=="enabled") {
+ fx.enabled=p_value;
+ } else {
+ return false;
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
}
+bool AudioBusLayout::_get(const StringName& p_name,Variant &r_ret) const{
+
+ String s = p_name;
+ if (s.begins_with("bus/")) {
+
+ int index = s.get_slice("/",1).to_int();
+ if (index<0 || index>=buses.size())
+ return false;
+
+ const Bus &bus = buses[index];
+
+ String what = s.get_slice("/",2);
+
+ if (what=="name") {
+ r_ret=bus.name;
+ } else if (what=="solo") {
+ r_ret=bus.solo;
+ } else if (what=="mute") {
+ r_ret=bus.mute;
+ } else if (what=="bypass_fx") {
+ r_ret=bus.bypass;
+ } else if (what=="volume_db") {
+ r_ret=bus.volume_db;
+ } else if (what=="send") {
+ r_ret=bus.send;
+ } else if (what=="effect") {
+ int which = s.get_slice("/",3).to_int();
+ if (which<0 || which>=bus.effects.size()) {
+ return false;
+ }
+
+ const Bus::Effect &fx = bus.effects[which];
+
+ String fxwhat = s.get_slice("/",4);
+ if (fxwhat=="effect") {
+ r_ret=fx.effect;
+ } else if (fxwhat=="enabled") {
+ r_ret=fx.enabled;
+ } else {
+ return false;
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+
+}
+void AudioBusLayout::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ for(int i=0;i<buses.size();i++) {
+ p_list->push_back(PropertyInfo(Variant::STRING,"bus/"+itos(i)+"/name",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::BOOL,"bus/"+itos(i)+"/solo",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::BOOL,"bus/"+itos(i)+"/mute",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::BOOL,"bus/"+itos(i)+"/bypass_fx",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::REAL,"bus/"+itos(i)+"/volume_db",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::REAL,"bus/"+itos(i)+"/send",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR));
+
+ for(int j=0;j<buses[i].effects.size();j++) {
+ p_list->push_back(PropertyInfo(Variant::OBJECT,"bus/"+itos(i)+"/effect/"+itos(j)+"/effect",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::BOOL,"bus/"+itos(i)+"/effect/"+itos(j)+"/enabled",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR));
+ }
+ }
+}
+
+
+AudioBusLayout::AudioBusLayout() {
+
+ buses.resize(1);
+ buses[0].name="Master";
+}
diff --git a/servers/audio_server.h b/servers/audio_server.h
index 77aca39760..88849bb591 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -100,56 +100,131 @@ public:
};
+class AudioBusLayout;
+
class AudioServer : public Object {
GDCLASS( AudioServer, Object )
public:
- enum BusMode {
- BUS_MODE_STEREO,
- BUS_MODE_SURROUND
- };
-
//re-expose this her, as AudioDriver is not exposed to script
enum SpeakerMode {
SPEAKER_MODE_STEREO,
SPEAKER_SURROUND_51,
SPEAKER_SURROUND_71,
};
+
+ enum {
+ AUDIO_DATA_INVALID_ID=-1
+ };
+
+ typedef void (*AudioCallback)(void* p_userdata);
+
private:
uint32_t buffer_size;
+ uint64_t mix_count;
+ uint64_t mix_frames;
+
+ float channel_disable_treshold_db;
+ uint32_t channel_disable_frames;
+
+ int to_mix;
struct Bus {
- String name;
- BusMode mode;
- Vector<AudioFrame> buffer;
+ StringName name;
+ bool solo;
+ bool mute;
+ bool bypass;
+
+ //Each channel is a stereo pair.
+ struct Channel {
+ bool used;
+ bool active;
+ AudioFrame peak_volume;
+ Vector<AudioFrame> buffer;
+ Vector<Ref<AudioEffectInstance> > effect_instances;
+ uint64_t last_mix_with_audio;
+ Channel() { last_mix_with_audio=0; used=false; active=false; peak_volume=AudioFrame(0,0); }
+ };
+
+ Vector<Channel> channels;
+
struct Effect {
Ref<AudioEffect> effect;
- Ref<AudioEffectInstance> instance;
bool enabled;
};
Vector<Effect> effects;
-
float volume_db;
+ StringName send;
+ int index_cache;
};
- Vector<Bus> buses;
+ Vector< Vector<AudioFrame> >temp_buffer; //temp_buffer for each level
+ Vector<Bus*> buses;
+ Map<StringName,Bus*> bus_map;
+ _FORCE_INLINE_ int _get_channel_count() const {
+ switch (AudioDriver::get_singleton()->get_speaker_mode()) {
+ case AudioDriver::SPEAKER_MODE_STEREO: return 1;
+ case AudioDriver::SPEAKER_SURROUND_51: return 3;
+ case AudioDriver::SPEAKER_SURROUND_71: return 4;
+
+ }
+ ERR_FAIL_V(1);
+ }
+
+
+ void _update_bus_effects(int p_bus);
- static void _bind_methods();
static AudioServer* singleton;
+
+ // TODO create an audiodata pool to optimize memory
+
+
+ Map<void*,uint32_t> audio_data;
+ size_t audio_data_total_mem;
+ size_t audio_data_max_mem;
+
+ Mutex *audio_data_lock;
+
+ void _mix_step();
+
+ struct CallbackItem {
+
+ AudioCallback callback;
+ void *userdata;
+
+ bool operator<(const CallbackItem& p_item) const {
+ return (callback==p_item.callback ? userdata < p_item.userdata : callback < p_item.callback);
+ }
+ };
+
+ Set<CallbackItem> callbacks;
+
+friend class AudioDriver;
+ void _driver_process(int p_frames, int32_t *p_buffer);
+protected:
+
+ static void _bind_methods();
public:
+ //do not use from outside audio thread
+ AudioFrame *thread_get_channel_mix_buffer(int p_bus,int p_buffer);
+ int thread_get_mix_buffer_size() const;
+ int thread_find_bus_index(const StringName& p_name);
+
void set_bus_count(int p_count);
int get_bus_count() const;
- void set_bus_mode(int p_bus,BusMode p_mode);
- BusMode get_bus_mode(int p_bus) const;
+ void remove_bus(int p_index);
+ void add_bus(int p_at_pos=-1);
+
+ void move_bus(int p_bus,int p_to_pos);
void set_bus_name(int p_bus,const String& p_name);
String get_bus_name(int p_bus) const;
@@ -157,6 +232,19 @@ public:
void set_bus_volume_db(int p_bus,float p_volume_db);
float get_bus_volume_db(int p_bus) const;
+
+ void set_bus_send(int p_bus,const StringName& p_send);
+ StringName get_bus_send(int p_bus) const;
+
+ void set_bus_solo(int p_bus,bool p_enable);
+ bool is_bus_solo(int p_bus) const;
+
+ void set_bus_mute(int p_bus,bool p_enable);
+ bool is_bus_mute(int p_bus) const;
+
+ void set_bus_bypass_effects(int p_bus,bool p_enable);
+ bool is_bus_bypassing_effects(int p_bus) const;
+
void add_bus_effect(int p_bus,const Ref<AudioEffect>& p_effect,int p_at_pos=-1);
void remove_bus_effect(int p_bus,int p_effect);
@@ -168,9 +256,15 @@ public:
void set_bus_effect_enabled(int p_bus,int p_effect,bool p_enabled);
bool is_bus_effect_enabled(int p_bus,int p_effect) const;
+ float get_bus_peak_volume_left_db(int p_bus,int p_channel) const;
+ float get_bus_peak_volume_right_db(int p_bus,int p_channel) const;
+
+ bool is_bus_channel_active(int p_bus,int p_channel) const;
+
virtual void init();
virtual void finish();
virtual void update();
+ virtual void load_default_bus_layout();
/* MISC config */
@@ -188,13 +282,74 @@ public:
virtual double get_mix_time() const; //useful for video -> audio sync
virtual double get_output_delay() const;
+ void* audio_data_alloc(uint32_t p_data_len, const uint8_t *p_from_data=NULL);
+ void audio_data_free(void* p_data);
+
+ size_t audio_data_get_total_memory_usage() const;
+ size_t audio_data_get_max_memory_usage() const;
+
+
+ void add_callback(AudioCallback p_callback,void *p_userdata);
+ void remove_callback(AudioCallback p_callback,void *p_userdata);
+
+ void set_bus_layout(const Ref<AudioBusLayout>& p_state);
+ Ref<AudioBusLayout> generate_bus_layout() const;
+
AudioServer();
virtual ~AudioServer();
};
-VARIANT_ENUM_CAST( AudioServer::BusMode )
VARIANT_ENUM_CAST( AudioServer::SpeakerMode )
+class AudioBusLayout : public Resource {
+
+ GDCLASS(AudioBusLayout,Resource)
+
+friend class AudioServer;
+
+ struct Bus {
+
+ StringName name;
+ bool solo;
+ bool mute;
+ bool bypass;
+
+ struct Effect {
+ Ref<AudioEffect> effect;
+ bool enabled;
+ };
+
+ Vector<Effect> effects;
+
+ float volume_db;
+ StringName send;
+
+ Bus() {
+ solo=false;
+ mute=false;
+ bypass=false;
+ volume_db=0;
+ }
+ };
+
+ Vector<Bus> buses;
+
+protected:
+
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+ AudioBusLayout();
+};
+
+
+
+
+
+
typedef AudioServer AS;
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
index d2b37319ad..8b7a410b3d 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
@@ -539,14 +539,14 @@ int BroadPhase2DHashGrid::cull_segment(const Vector2& p_from, const Vector2& p_t
Vector2 max;
if (dir.x<0)
- max.x= (Math::floor(pos.x)*cell_size - p_from.x) / dir.x;
+ max.x= (Math::floor((double)pos.x)*cell_size - p_from.x) / dir.x;
else
- max.x= (Math::floor(pos.x + 1)*cell_size - p_from.x) / dir.x;
+ max.x= (Math::floor((double)pos.x + 1)*cell_size - p_from.x) / dir.x;
if (dir.y<0)
- max.y= (Math::floor(pos.y)*cell_size - p_from.y) / dir.y;
+ max.y= (Math::floor((double)pos.y)*cell_size - p_from.y) / dir.y;
else
- max.y= (Math::floor(pos.y + 1)*cell_size - p_from.y) / dir.y;
+ max.y= (Math::floor((double)pos.y + 1)*cell_size - p_from.y) / dir.y;
int cullcount=0;
_cull<false,true>(pos,Rect2(),p_from,p_to,p_results,p_max_results,p_result_indices,cullcount);
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index 8b831f4ff6..01f8ffa504 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -35,6 +35,21 @@
#include "physics_2d_server.h"
#include "script_debugger_remote.h"
#include "visual/shader_types.h"
+#include "audio/audio_stream.h"
+#include "audio/audio_effect.h"
+#include "audio/effects/audio_effect_amplify.h"
+#include "audio/effects/audio_effect_reverb.h"
+#include "audio/effects/audio_effect_filter.h"
+#include "audio/effects/audio_effect_eq.h"
+#include "audio/effects/audio_effect_distortion.h"
+#include "audio/effects/audio_effect_stereo_enhance.h"
+#include "audio/effects/audio_effect_panner.h"
+#include "audio/effects/audio_effect_chorus.h"
+#include "audio/effects/audio_effect_delay.h"
+#include "audio/effects/audio_effect_compressor.h"
+#include "audio/effects/audio_effect_limiter.h"
+#include "audio/effects/audio_effect_pitch_shift.h"
+#include "audio/effects/audio_effect_phaser.h"
static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsage>* r_usage) {
@@ -67,6 +82,42 @@ void register_server_types() {
shader_types = memnew( ShaderTypes );
+ ClassDB::register_virtual_class<AudioStream>();
+ ClassDB::register_virtual_class<AudioStreamPlayback>();
+ ClassDB::register_virtual_class<AudioEffect>();
+ ClassDB::register_class<AudioBusLayout>();
+
+ {
+ //audio effects
+ ClassDB::register_class<AudioEffectAmplify>();
+
+ ClassDB::register_class<AudioEffectReverb>();
+
+ ClassDB::register_class<AudioEffectLowPassFilter>();
+ ClassDB::register_class<AudioEffectHighPassFilter>();
+ ClassDB::register_class<AudioEffectBandPassFilter>();
+ ClassDB::register_class<AudioEffectNotchFilter>();
+ ClassDB::register_class<AudioEffectBandLimitFilter>();
+ ClassDB::register_class<AudioEffectLowShelfFilter>();
+ ClassDB::register_class<AudioEffectHighShelfFilter>();
+
+ ClassDB::register_class<AudioEffectEQ6>();
+ ClassDB::register_class<AudioEffectEQ10>();
+ ClassDB::register_class<AudioEffectEQ21>();
+
+ ClassDB::register_class<AudioEffectDistortion>();
+
+ ClassDB::register_class<AudioEffectStereoEnhance>();
+
+ ClassDB::register_class<AudioEffectPanner>();
+ ClassDB::register_class<AudioEffectChorus>();
+ ClassDB::register_class<AudioEffectDelay>();
+ ClassDB::register_class<AudioEffectCompressor>();
+ ClassDB::register_class<AudioEffectLimiter>();
+ ClassDB::register_class<AudioEffectPitchShift>();
+ ClassDB::register_class<AudioEffectPhaser>();
+ }
+
ClassDB::register_virtual_class<Physics2DDirectBodyState>();
ClassDB::register_virtual_class<Physics2DDirectSpaceState>();
diff --git a/thirdparty/stb_vorbis/stb_vorbis.c b/thirdparty/stb_vorbis/stb_vorbis.c
new file mode 100644
index 0000000000..c4f24d5898
--- /dev/null
+++ b/thirdparty/stb_vorbis/stb_vorbis.c
@@ -0,0 +1,5399 @@
+// Ogg Vorbis audio decoder - v1.09 - public domain
+// http://nothings.org/stb_vorbis/
+//
+// Original version written by Sean Barrett in 2007.
+//
+// Originally sponsored by RAD Game Tools. Seeking sponsored
+// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software,
+// Aras Pranckevicius, and Sean Barrett.
+//
+// LICENSE
+//
+// This software is dual-licensed to the public domain and under the following
+// license: you are granted a perpetual, irrevocable license to copy, modify,
+// publish, and distribute this file as you see fit.
+//
+// No warranty for any purpose is expressed or implied by the author (nor
+// by RAD Game Tools). Report bugs and send enhancements to the author.
+//
+// Limitations:
+//
+// - floor 0 not supported (used in old ogg vorbis files pre-2004)
+// - lossless sample-truncation at beginning ignored
+// - cannot concatenate multiple vorbis streams
+// - sample positions are 32-bit, limiting seekable 192Khz
+// files to around 6 hours (Ogg supports 64-bit)
+//
+// Feature contributors:
+// Dougall Johnson (sample-exact seeking)
+//
+// Bugfix/warning contributors:
+// Terje Mathisen Niklas Frykholm Andy Hill
+// Casey Muratori John Bolton Gargaj
+// Laurent Gomila Marc LeBlanc Ronny Chevalier
+// Bernhard Wodo Evan Balster alxprd@github
+// Tom Beaumont Ingo Leitgeb Nicolas Guillemot
+// Phillip Bennefall Rohit Thiago Goulart
+// manxorist@github saga musix
+//
+// Partial history:
+// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version
+// 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame
+// 1.07 - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const
+// 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson)
+// some crash fixes when out of memory or with corrupt files
+// fix some inappropriately signed shifts
+// 1.05 - 2015/04/19 - don't define __forceinline if it's redundant
+// 1.04 - 2014/08/27 - fix missing const-correct case in API
+// 1.03 - 2014/08/07 - warning fixes
+// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows
+// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct)
+// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
+// (API change) report sample rate for decode-full-file funcs
+//
+// See end of file for full version history.
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// HEADER BEGINS HERE
+//
+
+#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
+#define STB_VORBIS_INCLUDE_STB_VORBIS_H
+
+#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
+#define STB_VORBIS_NO_STDIO 1
+#endif
+
+#ifndef STB_VORBIS_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/////////// THREAD SAFETY
+
+// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
+// them from multiple threads at the same time. However, you can have multiple
+// stb_vorbis* handles and decode from them independently in multiple thrads.
+
+
+/////////// MEMORY ALLOCATION
+
+// normally stb_vorbis uses malloc() to allocate memory at startup,
+// and alloca() to allocate temporary memory during a frame on the
+// stack. (Memory consumption will depend on the amount of setup
+// data in the file and how you set the compile flags for speed
+// vs. size. In my test files the maximal-size usage is ~150KB.)
+//
+// You can modify the wrapper functions in the source (setup_malloc,
+// setup_temp_malloc, temp_malloc) to change this behavior, or you
+// can use a simpler allocation model: you pass in a buffer from
+// which stb_vorbis will allocate _all_ its memory (including the
+// temp memory). "open" may fail with a VORBIS_outofmem if you
+// do not pass in enough data; there is no way to determine how
+// much you do need except to succeed (at which point you can
+// query get_info to find the exact amount required. yes I know
+// this is lame).
+//
+// If you pass in a non-NULL buffer of the type below, allocation
+// will occur from it as described above. Otherwise just pass NULL
+// to use malloc()/alloca()
+
+typedef struct
+{
+ char *alloc_buffer;
+ int alloc_buffer_length_in_bytes;
+} stb_vorbis_alloc;
+
+
+/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
+
+typedef struct stb_vorbis stb_vorbis;
+
+typedef struct
+{
+ unsigned int sample_rate;
+ int channels;
+
+ unsigned int setup_memory_required;
+ unsigned int setup_temp_memory_required;
+ unsigned int temp_memory_required;
+
+ int max_frame_size;
+} stb_vorbis_info;
+
+// get general information about the file
+extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
+
+// get the last error detected (clears it, too)
+extern int stb_vorbis_get_error(stb_vorbis *f);
+
+// close an ogg vorbis file and free all memory in use
+extern void stb_vorbis_close(stb_vorbis *f);
+
+// this function returns the offset (in samples) from the beginning of the
+// file that will be returned by the next decode, if it is known, or -1
+// otherwise. after a flush_pushdata() call, this may take a while before
+// it becomes valid again.
+// NOT WORKING YET after a seek with PULLDATA API
+extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
+
+// returns the current seek point within the file, or offset from the beginning
+// of the memory buffer. In pushdata mode it returns 0.
+extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
+
+/////////// PUSHDATA API
+
+#ifndef STB_VORBIS_NO_PUSHDATA_API
+
+// this API allows you to get blocks of data from any source and hand
+// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
+// you how much it used, and you have to give it the rest next time;
+// and stb_vorbis may not have enough data to work with and you will
+// need to give it the same data again PLUS more. Note that the Vorbis
+// specification does not bound the size of an individual frame.
+
+extern stb_vorbis *stb_vorbis_open_pushdata(
+ const unsigned char * datablock, int datablock_length_in_bytes,
+ int *datablock_memory_consumed_in_bytes,
+ int *error,
+ const stb_vorbis_alloc *alloc_buffer);
+// create a vorbis decoder by passing in the initial data block containing
+// the ogg&vorbis headers (you don't need to do parse them, just provide
+// the first N bytes of the file--you're told if it's not enough, see below)
+// on success, returns an stb_vorbis *, does not set error, returns the amount of
+// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
+// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
+// if returns NULL and *error is VORBIS_need_more_data, then the input block was
+// incomplete and you need to pass in a larger block from the start of the file
+
+extern int stb_vorbis_decode_frame_pushdata(
+ stb_vorbis *f,
+ const unsigned char *datablock, int datablock_length_in_bytes,
+ int *channels, // place to write number of float * buffers
+ float ***output, // place to write float ** array of float * buffers
+ int *samples // place to write number of output samples
+ );
+// decode a frame of audio sample data if possible from the passed-in data block
+//
+// return value: number of bytes we used from datablock
+//
+// possible cases:
+// 0 bytes used, 0 samples output (need more data)
+// N bytes used, 0 samples output (resynching the stream, keep going)
+// N bytes used, M samples output (one frame of data)
+// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
+// frame, because Vorbis always "discards" the first frame.
+//
+// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
+// instead only datablock_length_in_bytes-3 or less. This is because it wants
+// to avoid missing parts of a page header if they cross a datablock boundary,
+// without writing state-machiney code to record a partial detection.
+//
+// The number of channels returned are stored in *channels (which can be
+// NULL--it is always the same as the number of channels reported by
+// get_info). *output will contain an array of float* buffers, one per
+// channel. In other words, (*output)[0][0] contains the first sample from
+// the first channel, and (*output)[1][0] contains the first sample from
+// the second channel.
+
+extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
+// inform stb_vorbis that your next datablock will not be contiguous with
+// previous ones (e.g. you've seeked in the data); future attempts to decode
+// frames will cause stb_vorbis to resynchronize (as noted above), and
+// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
+// will begin decoding the _next_ frame.
+//
+// if you want to seek using pushdata, you need to seek in your file, then
+// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
+// decoding is returning you data, call stb_vorbis_get_sample_offset, and
+// if you don't like the result, seek your file again and repeat.
+#endif
+
+
+////////// PULLING INPUT API
+
+#ifndef STB_VORBIS_NO_PULLDATA_API
+// This API assumes stb_vorbis is allowed to pull data from a source--
+// either a block of memory containing the _entire_ vorbis stream, or a
+// FILE * that you or it create, or possibly some other reading mechanism
+// if you go modify the source to replace the FILE * case with some kind
+// of callback to your code. (But if you don't support seeking, you may
+// just want to go ahead and use pushdata.)
+
+#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
+extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);
+#endif
+#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
+extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);
+#endif
+// decode an entire file and output the data interleaved into a malloc()ed
+// buffer stored in *output. The return value is the number of samples
+// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
+// When you're done with it, just free() the pointer returned in *output.
+
+extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
+ int *error, const stb_vorbis_alloc *alloc_buffer);
+// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
+// this must be the entire stream!). on failure, returns NULL and sets *error
+
+#ifndef STB_VORBIS_NO_STDIO
+extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
+ int *error, const stb_vorbis_alloc *alloc_buffer);
+// create an ogg vorbis decoder from a filename via fopen(). on failure,
+// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
+
+extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
+ int *error, const stb_vorbis_alloc *alloc_buffer);
+// create an ogg vorbis decoder from an open FILE *, looking for a stream at
+// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
+// note that stb_vorbis must "own" this stream; if you seek it in between
+// calls to stb_vorbis, it will become confused. Morever, if you attempt to
+// perform stb_vorbis_seek_*() operations on this file, it will assume it
+// owns the _entire_ rest of the file after the start point. Use the next
+// function, stb_vorbis_open_file_section(), to limit it.
+
+extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
+ int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len);
+// create an ogg vorbis decoder from an open FILE *, looking for a stream at
+// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
+// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
+// this stream; if you seek it in between calls to stb_vorbis, it will become
+// confused.
+#endif
+
+extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
+extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
+// these functions seek in the Vorbis file to (approximately) 'sample_number'.
+// after calling seek_frame(), the next call to get_frame_*() will include
+// the specified sample. after calling stb_vorbis_seek(), the next call to
+// stb_vorbis_get_samples_* will start with the specified sample. If you
+// do not need to seek to EXACTLY the target sample when using get_samples_*,
+// you can also use seek_frame().
+
+extern void stb_vorbis_seek_start(stb_vorbis *f);
+// this function is equivalent to stb_vorbis_seek(f,0)
+
+extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
+extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
+// these functions return the total length of the vorbis stream
+
+extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
+// decode the next frame and return the number of samples. the number of
+// channels returned are stored in *channels (which can be NULL--it is always
+// the same as the number of channels reported by get_info). *output will
+// contain an array of float* buffers, one per channel. These outputs will
+// be overwritten on the next call to stb_vorbis_get_frame_*.
+//
+// You generally should not intermix calls to stb_vorbis_get_frame_*()
+// and stb_vorbis_get_samples_*(), since the latter calls the former.
+
+#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
+extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
+extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
+#endif
+// decode the next frame and return the number of *samples* per channel.
+// Note that for interleaved data, you pass in the number of shorts (the
+// size of your array), but the return value is the number of samples per
+// channel, not the total number of samples.
+//
+// The data is coerced to the number of channels you request according to the
+// channel coercion rules (see below). You must pass in the size of your
+// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
+// The maximum buffer size needed can be gotten from get_info(); however,
+// the Vorbis I specification implies an absolute maximum of 4096 samples
+// per channel.
+
+// Channel coercion rules:
+// Let M be the number of channels requested, and N the number of channels present,
+// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
+// and stereo R be the sum of all R and center channels (channel assignment from the
+// vorbis spec).
+// M N output
+// 1 k sum(Ck) for all k
+// 2 * stereo L, stereo R
+// k l k > l, the first l channels, then 0s
+// k l k <= l, the first k channels
+// Note that this is not _good_ surround etc. mixing at all! It's just so
+// you get something useful.
+
+extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
+extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
+// gets num_samples samples, not necessarily on a frame boundary--this requires
+// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
+// Returns the number of samples stored per channel; it may be less than requested
+// at the end of the file. If there are no more samples in the file, returns 0.
+
+#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
+extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
+extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
+#endif
+// gets num_samples samples, not necessarily on a frame boundary--this requires
+// buffering so you have to supply the buffers. Applies the coercion rules above
+// to produce 'channels' channels. Returns the number of samples stored per channel;
+// it may be less than requested at the end of the file. If there are no more
+// samples in the file, returns 0.
+
+#endif
+
+//////// ERROR CODES
+
+enum STBVorbisError
+{
+ VORBIS__no_error,
+
+ VORBIS_need_more_data=1, // not a real error
+
+ VORBIS_invalid_api_mixing, // can't mix API modes
+ VORBIS_outofmem, // not enough memory
+ VORBIS_feature_not_supported, // uses floor 0
+ VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small
+ VORBIS_file_open_failure, // fopen() failed
+ VORBIS_seek_without_length, // can't seek in unknown-length file
+
+ VORBIS_unexpected_eof=10, // file is truncated?
+ VORBIS_seek_invalid, // seek past EOF
+
+ // decoding errors (corrupt/invalid stream) -- you probably
+ // don't care about the exact details of these
+
+ // vorbis errors:
+ VORBIS_invalid_setup=20,
+ VORBIS_invalid_stream,
+
+ // ogg errors:
+ VORBIS_missing_capture_pattern=30,
+ VORBIS_invalid_stream_structure_version,
+ VORBIS_continued_packet_flag_invalid,
+ VORBIS_incorrect_stream_serial_number,
+ VORBIS_invalid_first_page,
+ VORBIS_bad_packet_type,
+ VORBIS_cant_find_last_page,
+ VORBIS_seek_failed
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H
+//
+// HEADER ENDS HERE
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef STB_VORBIS_HEADER_ONLY
+
+// global configuration settings (e.g. set these in the project/makefile),
+// or just set them in this file at the top (although ideally the first few
+// should be visible when the header file is compiled too, although it's not
+// crucial)
+
+// STB_VORBIS_NO_PUSHDATA_API
+// does not compile the code for the various stb_vorbis_*_pushdata()
+// functions
+// #define STB_VORBIS_NO_PUSHDATA_API
+
+// STB_VORBIS_NO_PULLDATA_API
+// does not compile the code for the non-pushdata APIs
+// #define STB_VORBIS_NO_PULLDATA_API
+
+// STB_VORBIS_NO_STDIO
+// does not compile the code for the APIs that use FILE *s internally
+// or externally (implied by STB_VORBIS_NO_PULLDATA_API)
+// #define STB_VORBIS_NO_STDIO
+
+// STB_VORBIS_NO_INTEGER_CONVERSION
+// does not compile the code for converting audio sample data from
+// float to integer (implied by STB_VORBIS_NO_PULLDATA_API)
+// #define STB_VORBIS_NO_INTEGER_CONVERSION
+
+// STB_VORBIS_NO_FAST_SCALED_FLOAT
+// does not use a fast float-to-int trick to accelerate float-to-int on
+// most platforms which requires endianness be defined correctly.
+//#define STB_VORBIS_NO_FAST_SCALED_FLOAT
+
+
+// STB_VORBIS_MAX_CHANNELS [number]
+// globally define this to the maximum number of channels you need.
+// The spec does not put a restriction on channels except that
+// the count is stored in a byte, so 255 is the hard limit.
+// Reducing this saves about 16 bytes per value, so using 16 saves
+// (255-16)*16 or around 4KB. Plus anything other memory usage
+// I forgot to account for. Can probably go as low as 8 (7.1 audio),
+// 6 (5.1 audio), or 2 (stereo only).
+#ifndef STB_VORBIS_MAX_CHANNELS
+#define STB_VORBIS_MAX_CHANNELS 16 // enough for anyone?
+#endif
+
+// STB_VORBIS_PUSHDATA_CRC_COUNT [number]
+// after a flush_pushdata(), stb_vorbis begins scanning for the
+// next valid page, without backtracking. when it finds something
+// that looks like a page, it streams through it and verifies its
+// CRC32. Should that validation fail, it keeps scanning. But it's
+// possible that _while_ streaming through to check the CRC32 of
+// one candidate page, it sees another candidate page. This #define
+// determines how many "overlapping" candidate pages it can search
+// at once. Note that "real" pages are typically ~4KB to ~8KB, whereas
+// garbage pages could be as big as 64KB, but probably average ~16KB.
+// So don't hose ourselves by scanning an apparent 64KB page and
+// missing a ton of real ones in the interim; so minimum of 2
+#ifndef STB_VORBIS_PUSHDATA_CRC_COUNT
+#define STB_VORBIS_PUSHDATA_CRC_COUNT 4
+#endif
+
+// STB_VORBIS_FAST_HUFFMAN_LENGTH [number]
+// sets the log size of the huffman-acceleration table. Maximum
+// supported value is 24. with larger numbers, more decodings are O(1),
+// but the table size is larger so worse cache missing, so you'll have
+// to probe (and try multiple ogg vorbis files) to find the sweet spot.
+#ifndef STB_VORBIS_FAST_HUFFMAN_LENGTH
+#define STB_VORBIS_FAST_HUFFMAN_LENGTH 10
+#endif
+
+// STB_VORBIS_FAST_BINARY_LENGTH [number]
+// sets the log size of the binary-search acceleration table. this
+// is used in similar fashion to the fast-huffman size to set initial
+// parameters for the binary search
+
+// STB_VORBIS_FAST_HUFFMAN_INT
+// The fast huffman tables are much more efficient if they can be
+// stored as 16-bit results instead of 32-bit results. This restricts
+// the codebooks to having only 65535 possible outcomes, though.
+// (At least, accelerated by the huffman table.)
+#ifndef STB_VORBIS_FAST_HUFFMAN_INT
+#define STB_VORBIS_FAST_HUFFMAN_SHORT
+#endif
+
+// STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH
+// If the 'fast huffman' search doesn't succeed, then stb_vorbis falls
+// back on binary searching for the correct one. This requires storing
+// extra tables with the huffman codes in sorted order. Defining this
+// symbol trades off space for speed by forcing a linear search in the
+// non-fast case, except for "sparse" codebooks.
+// #define STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH
+
+// STB_VORBIS_DIVIDES_IN_RESIDUE
+// stb_vorbis precomputes the result of the scalar residue decoding
+// that would otherwise require a divide per chunk. you can trade off
+// space for time by defining this symbol.
+// #define STB_VORBIS_DIVIDES_IN_RESIDUE
+
+// STB_VORBIS_DIVIDES_IN_CODEBOOK
+// vorbis VQ codebooks can be encoded two ways: with every case explicitly
+// stored, or with all elements being chosen from a small range of values,
+// and all values possible in all elements. By default, stb_vorbis expands
+// this latter kind out to look like the former kind for ease of decoding,
+// because otherwise an integer divide-per-vector-element is required to
+// unpack the index. If you define STB_VORBIS_DIVIDES_IN_CODEBOOK, you can
+// trade off storage for speed.
+//#define STB_VORBIS_DIVIDES_IN_CODEBOOK
+
+#ifdef STB_VORBIS_CODEBOOK_SHORTS
+#error "STB_VORBIS_CODEBOOK_SHORTS is no longer supported as it produced incorrect results for some input formats"
+#endif
+
+// STB_VORBIS_DIVIDE_TABLE
+// this replaces small integer divides in the floor decode loop with
+// table lookups. made less than 1% difference, so disabled by default.
+
+// STB_VORBIS_NO_INLINE_DECODE
+// disables the inlining of the scalar codebook fast-huffman decode.
+// might save a little codespace; useful for debugging
+// #define STB_VORBIS_NO_INLINE_DECODE
+
+// STB_VORBIS_NO_DEFER_FLOOR
+// Normally we only decode the floor without synthesizing the actual
+// full curve. We can instead synthesize the curve immediately. This
+// requires more memory and is very likely slower, so I don't think
+// you'd ever want to do it except for debugging.
+// #define STB_VORBIS_NO_DEFER_FLOOR
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+#ifdef STB_VORBIS_NO_PULLDATA_API
+ #define STB_VORBIS_NO_INTEGER_CONVERSION
+ #define STB_VORBIS_NO_STDIO
+#endif
+
+#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
+ #define STB_VORBIS_NO_STDIO 1
+#endif
+
+#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
+#ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT
+
+ // only need endianness for fast-float-to-int, which we don't
+ // use for pushdata
+
+ #ifndef STB_VORBIS_BIG_ENDIAN
+ #define STB_VORBIS_ENDIAN 0
+ #else
+ #define STB_VORBIS_ENDIAN 1
+ #endif
+
+#endif
+#endif
+
+
+#ifndef STB_VORBIS_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifndef STB_VORBIS_NO_CRT
+ #include <stdlib.h>
+ #include <string.h>
+ #include <assert.h>
+ #include <math.h>
+
+ // find definition of alloca if it's not in stdlib.h:
+ #ifdef _MSC_VER
+ #include <malloc.h>
+ #endif
+ #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__)
+ #include <alloca.h>
+ #endif
+#else // STB_VORBIS_NO_CRT
+ #define NULL 0
+ #define malloc(s) 0
+ #define free(s) ((void) 0)
+ #define realloc(s) 0
+#endif // STB_VORBIS_NO_CRT
+
+#include <limits.h>
+
+#ifdef __MINGW32__
+ // eff you mingw:
+ // "fixed":
+ // http://sourceforge.net/p/mingw-w64/mailman/message/32882927/
+ // "no that broke the build, reverted, who cares about C":
+ // http://sourceforge.net/p/mingw-w64/mailman/message/32890381/
+ #ifdef __forceinline
+ #undef __forceinline
+ #endif
+ #define __forceinline
+#elif !defined(_MSC_VER)
+ #if __GNUC__
+ #define __forceinline inline
+ #else
+ #define __forceinline
+ #endif
+#endif
+
+#if STB_VORBIS_MAX_CHANNELS > 256
+#error "Value of STB_VORBIS_MAX_CHANNELS outside of allowed range"
+#endif
+
+#if STB_VORBIS_FAST_HUFFMAN_LENGTH > 24
+#error "Value of STB_VORBIS_FAST_HUFFMAN_LENGTH outside of allowed range"
+#endif
+
+
+#if 0
+#include <crtdbg.h>
+#define CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1])
+#else
+#define CHECK(f) ((void) 0)
+#endif
+
+#define MAX_BLOCKSIZE_LOG 13 // from specification
+#define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG)
+
+
+typedef unsigned char uint8;
+typedef signed char int8;
+typedef unsigned short uint16;
+typedef signed short int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+typedef float codetype;
+
+// @NOTE
+//
+// Some arrays below are tagged "//varies", which means it's actually
+// a variable-sized piece of data, but rather than malloc I assume it's
+// small enough it's better to just allocate it all together with the
+// main thing
+//
+// Most of the variables are specified with the smallest size I could pack
+// them into. It might give better performance to make them all full-sized
+// integers. It should be safe to freely rearrange the structures or change
+// the sizes larger--nothing relies on silently truncating etc., nor the
+// order of variables.
+
+#define FAST_HUFFMAN_TABLE_SIZE (1 << STB_VORBIS_FAST_HUFFMAN_LENGTH)
+#define FAST_HUFFMAN_TABLE_MASK (FAST_HUFFMAN_TABLE_SIZE - 1)
+
+typedef struct
+{
+ int dimensions, entries;
+ uint8 *codeword_lengths;
+ float minimum_value;
+ float delta_value;
+ uint8 value_bits;
+ uint8 lookup_type;
+ uint8 sequence_p;
+ uint8 sparse;
+ uint32 lookup_values;
+ codetype *multiplicands;
+ uint32 *codewords;
+ #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT
+ int16 fast_huffman[FAST_HUFFMAN_TABLE_SIZE];
+ #else
+ int32 fast_huffman[FAST_HUFFMAN_TABLE_SIZE];
+ #endif
+ uint32 *sorted_codewords;
+ int *sorted_values;
+ int sorted_entries;
+} Codebook;
+
+typedef struct
+{
+ uint8 order;
+ uint16 rate;
+ uint16 bark_map_size;
+ uint8 amplitude_bits;
+ uint8 amplitude_offset;
+ uint8 number_of_books;
+ uint8 book_list[16]; // varies
+} Floor0;
+
+typedef struct
+{
+ uint8 partitions;
+ uint8 partition_class_list[32]; // varies
+ uint8 class_dimensions[16]; // varies
+ uint8 class_subclasses[16]; // varies
+ uint8 class_masterbooks[16]; // varies
+ int16 subclass_books[16][8]; // varies
+ uint16 Xlist[31*8+2]; // varies
+ uint8 sorted_order[31*8+2];
+ uint8 neighbors[31*8+2][2];
+ uint8 floor1_multiplier;
+ uint8 rangebits;
+ int values;
+} Floor1;
+
+typedef union
+{
+ Floor0 floor0;
+ Floor1 floor1;
+} Floor;
+
+typedef struct
+{
+ uint32 begin, end;
+ uint32 part_size;
+ uint8 classifications;
+ uint8 classbook;
+ uint8 **classdata;
+ int16 (*residue_books)[8];
+} Residue;
+
+typedef struct
+{
+ uint8 magnitude;
+ uint8 angle;
+ uint8 mux;
+} MappingChannel;
+
+typedef struct
+{
+ uint16 coupling_steps;
+ MappingChannel *chan;
+ uint8 submaps;
+ uint8 submap_floor[15]; // varies
+ uint8 submap_residue[15]; // varies
+} Mapping;
+
+typedef struct
+{
+ uint8 blockflag;
+ uint8 mapping;
+ uint16 windowtype;
+ uint16 transformtype;
+} Mode;
+
+typedef struct
+{
+ uint32 goal_crc; // expected crc if match
+ int bytes_left; // bytes left in packet
+ uint32 crc_so_far; // running crc
+ int bytes_done; // bytes processed in _current_ chunk
+ uint32 sample_loc; // granule pos encoded in page
+} CRCscan;
+
+typedef struct
+{
+ uint32 page_start, page_end;
+ uint32 last_decoded_sample;
+} ProbedPage;
+
+struct stb_vorbis
+{
+ // user-accessible info
+ unsigned int sample_rate;
+ int channels;
+
+ unsigned int setup_memory_required;
+ unsigned int temp_memory_required;
+ unsigned int setup_temp_memory_required;
+
+ // input config
+#ifndef STB_VORBIS_NO_STDIO
+ FILE *f;
+ uint32 f_start;
+ int close_on_free;
+#endif
+
+ uint8 *stream;
+ uint8 *stream_start;
+ uint8 *stream_end;
+
+ uint32 stream_len;
+
+ uint8 push_mode;
+
+ uint32 first_audio_page_offset;
+
+ ProbedPage p_first, p_last;
+
+ // memory management
+ stb_vorbis_alloc alloc;
+ int setup_offset;
+ int temp_offset;
+
+ // run-time results
+ int eof;
+ enum STBVorbisError error;
+
+ // user-useful data
+
+ // header info
+ int blocksize[2];
+ int blocksize_0, blocksize_1;
+ int codebook_count;
+ Codebook *codebooks;
+ int floor_count;
+ uint16 floor_types[64]; // varies
+ Floor *floor_config;
+ int residue_count;
+ uint16 residue_types[64]; // varies
+ Residue *residue_config;
+ int mapping_count;
+ Mapping *mapping;
+ int mode_count;
+ Mode mode_config[64]; // varies
+
+ uint32 total_samples;
+
+ // decode buffer
+ float *channel_buffers[STB_VORBIS_MAX_CHANNELS];
+ float *outputs [STB_VORBIS_MAX_CHANNELS];
+
+ float *previous_window[STB_VORBIS_MAX_CHANNELS];
+ int previous_length;
+
+ #ifndef STB_VORBIS_NO_DEFER_FLOOR
+ int16 *finalY[STB_VORBIS_MAX_CHANNELS];
+ #else
+ float *floor_buffers[STB_VORBIS_MAX_CHANNELS];
+ #endif
+
+ uint32 current_loc; // sample location of next frame to decode
+ int current_loc_valid;
+
+ // per-blocksize precomputed data
+
+ // twiddle factors
+ float *A[2],*B[2],*C[2];
+ float *window[2];
+ uint16 *bit_reverse[2];
+
+ // current page/packet/segment streaming info
+ uint32 serial; // stream serial number for verification
+ int last_page;
+ int segment_count;
+ uint8 segments[255];
+ uint8 page_flag;
+ uint8 bytes_in_seg;
+ uint8 first_decode;
+ int next_seg;
+ int last_seg; // flag that we're on the last segment
+ int last_seg_which; // what was the segment number of the last seg?
+ uint32 acc;
+ int valid_bits;
+ int packet_bytes;
+ int end_seg_with_known_loc;
+ uint32 known_loc_for_packet;
+ int discard_samples_deferred;
+ uint32 samples_output;
+
+ // push mode scanning
+ int page_crc_tests; // only in push_mode: number of tests active; -1 if not searching
+#ifndef STB_VORBIS_NO_PUSHDATA_API
+ CRCscan scan[STB_VORBIS_PUSHDATA_CRC_COUNT];
+#endif
+
+ // sample-access
+ int channel_buffer_start;
+ int channel_buffer_end;
+};
+
+#if defined(STB_VORBIS_NO_PUSHDATA_API)
+ #define IS_PUSH_MODE(f) FALSE
+#elif defined(STB_VORBIS_NO_PULLDATA_API)
+ #define IS_PUSH_MODE(f) TRUE
+#else
+ #define IS_PUSH_MODE(f) ((f)->push_mode)
+#endif
+
+typedef struct stb_vorbis vorb;
+
+static int error(vorb *f, enum STBVorbisError e)
+{
+ f->error = e;
+ if (!f->eof && e != VORBIS_need_more_data) {
+ f->error=e; // breakpoint for debugging
+ }
+ return 0;
+}
+
+
+// these functions are used for allocating temporary memory
+// while decoding. if you can afford the stack space, use
+// alloca(); otherwise, provide a temp buffer and it will
+// allocate out of those.
+
+#define array_size_required(count,size) (count*(sizeof(void *)+(size)))
+
+#define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size))
+#ifdef dealloca
+#define temp_free(f,p) (f->alloc.alloc_buffer ? 0 : dealloca(size))
+#else
+#define temp_free(f,p) 0
+#endif
+#define temp_alloc_save(f) ((f)->temp_offset)
+#define temp_alloc_restore(f,p) ((f)->temp_offset = (p))
+
+#define temp_block_array(f,count,size) make_block_array(temp_alloc(f,array_size_required(count,size)), count, size)
+
+// given a sufficiently large block of memory, make an array of pointers to subblocks of it
+static void *make_block_array(void *mem, int count, int size)
+{
+ int i;
+ void ** p = (void **) mem;
+ char *q = (char *) (p + count);
+ for (i=0; i < count; ++i) {
+ p[i] = q;
+ q += size;
+ }
+ return p;
+}
+
+static void *setup_malloc(vorb *f, int sz)
+{
+ sz = (sz+3) & ~3;
+ f->setup_memory_required += sz;
+ if (f->alloc.alloc_buffer) {
+ void *p = (char *) f->alloc.alloc_buffer + f->setup_offset;
+ if (f->setup_offset + sz > f->temp_offset) return NULL;
+ f->setup_offset += sz;
+ return p;
+ }
+ return sz ? malloc(sz) : NULL;
+}
+
+static void setup_free(vorb *f, void *p)
+{
+ if (f->alloc.alloc_buffer) return; // do nothing; setup mem is a stack
+ free(p);
+}
+
+static void *setup_temp_malloc(vorb *f, int sz)
+{
+ sz = (sz+3) & ~3;
+ if (f->alloc.alloc_buffer) {
+ if (f->temp_offset - sz < f->setup_offset) return NULL;
+ f->temp_offset -= sz;
+ return (char *) f->alloc.alloc_buffer + f->temp_offset;
+ }
+ return malloc(sz);
+}
+
+static void setup_temp_free(vorb *f, void *p, int sz)
+{
+ if (f->alloc.alloc_buffer) {
+ f->temp_offset += (sz+3)&~3;
+ return;
+ }
+ free(p);
+}
+
+#define CRC32_POLY 0x04c11db7 // from spec
+
+static uint32 crc_table[256];
+static void crc32_init(void)
+{
+ int i,j;
+ uint32 s;
+ for(i=0; i < 256; i++) {
+ for (s=(uint32) i << 24, j=0; j < 8; ++j)
+ s = (s << 1) ^ (s >= (1U<<31) ? CRC32_POLY : 0);
+ crc_table[i] = s;
+ }
+}
+
+static __forceinline uint32 crc32_update(uint32 crc, uint8 byte)
+{
+ return (crc << 8) ^ crc_table[byte ^ (crc >> 24)];
+}
+
+
+// used in setup, and for huffman that doesn't go fast path
+static unsigned int bit_reverse(unsigned int n)
+{
+ n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1);
+ n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2);
+ n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4);
+ n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8);
+ return (n >> 16) | (n << 16);
+}
+
+static float square(float x)
+{
+ return x*x;
+}
+
+// this is a weird definition of log2() for which log2(1) = 1, log2(2) = 2, log2(4) = 3
+// as required by the specification. fast(?) implementation from stb.h
+// @OPTIMIZE: called multiple times per-packet with "constants"; move to setup
+static int ilog(int32 n)
+{
+ static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 };
+
+ // 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29)
+ if (n < (1 << 14))
+ if (n < (1 << 4)) return 0 + log2_4[n ];
+ else if (n < (1 << 9)) return 5 + log2_4[n >> 5];
+ else return 10 + log2_4[n >> 10];
+ else if (n < (1 << 24))
+ if (n < (1 << 19)) return 15 + log2_4[n >> 15];
+ else return 20 + log2_4[n >> 20];
+ else if (n < (1 << 29)) return 25 + log2_4[n >> 25];
+ else if (n < (1 << 31)) return 30 + log2_4[n >> 30];
+ else return 0; // signed n returns 0
+}
+
+#ifndef M_PI
+ #define M_PI 3.14159265358979323846264f // from CRC
+#endif
+
+// code length assigned to a value with no huffman encoding
+#define NO_CODE 255
+
+/////////////////////// LEAF SETUP FUNCTIONS //////////////////////////
+//
+// these functions are only called at setup, and only a few times
+// per file
+
+static float float32_unpack(uint32 x)
+{
+ // from the specification
+ uint32 mantissa = x & 0x1fffff;
+ uint32 sign = x & 0x80000000;
+ uint32 exp = (x & 0x7fe00000) >> 21;
+ double res = sign ? -(double)mantissa : (double)mantissa;
+ return (float) ldexp((float)res, exp-788);
+}
+
+
+// zlib & jpeg huffman tables assume that the output symbols
+// can either be arbitrarily arranged, or have monotonically
+// increasing frequencies--they rely on the lengths being sorted;
+// this makes for a very simple generation algorithm.
+// vorbis allows a huffman table with non-sorted lengths. This
+// requires a more sophisticated construction, since symbols in
+// order do not map to huffman codes "in order".
+static void add_entry(Codebook *c, uint32 huff_code, int symbol, int count, int len, uint32 *values)
+{
+ if (!c->sparse) {
+ c->codewords [symbol] = huff_code;
+ } else {
+ c->codewords [count] = huff_code;
+ c->codeword_lengths[count] = len;
+ values [count] = symbol;
+ }
+}
+
+static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
+{
+ int i,k,m=0;
+ uint32 available[32];
+
+ memset(available, 0, sizeof(available));
+ // find the first entry
+ for (k=0; k < n; ++k) if (len[k] < NO_CODE) break;
+ if (k == n) { assert(c->sorted_entries == 0); return TRUE; }
+ // add to the list
+ add_entry(c, 0, k, m++, len[k], values);
+ // add all available leaves
+ for (i=1; i <= len[k]; ++i)
+ available[i] = 1U << (32-i);
+ // note that the above code treats the first case specially,
+ // but it's really the same as the following code, so they
+ // could probably be combined (except the initial code is 0,
+ // and I use 0 in available[] to mean 'empty')
+ for (i=k+1; i < n; ++i) {
+ uint32 res;
+ int z = len[i], y;
+ if (z == NO_CODE) continue;
+ // find lowest available leaf (should always be earliest,
+ // which is what the specification calls for)
+ // note that this property, and the fact we can never have
+ // more than one free leaf at a given level, isn't totally
+ // trivial to prove, but it seems true and the assert never
+ // fires, so!
+ while (z > 0 && !available[z]) --z;
+ if (z == 0) { return FALSE; }
+ res = available[z];
+ assert(z >= 0 && z < 32);
+ available[z] = 0;
+ add_entry(c, bit_reverse(res), i, m++, len[i], values);
+ // propogate availability up the tree
+ if (z != len[i]) {
+ assert(len[i] >= 0 && len[i] < 32);
+ for (y=len[i]; y > z; --y) {
+ assert(available[y] == 0);
+ available[y] = res + (1 << (32-y));
+ }
+ }
+ }
+ return TRUE;
+}
+
+// accelerated huffman table allows fast O(1) match of all symbols
+// of length <= STB_VORBIS_FAST_HUFFMAN_LENGTH
+static void compute_accelerated_huffman(Codebook *c)
+{
+ int i, len;
+ for (i=0; i < FAST_HUFFMAN_TABLE_SIZE; ++i)
+ c->fast_huffman[i] = -1;
+
+ len = c->sparse ? c->sorted_entries : c->entries;
+ #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT
+ if (len > 32767) len = 32767; // largest possible value we can encode!
+ #endif
+ for (i=0; i < len; ++i) {
+ if (c->codeword_lengths[i] <= STB_VORBIS_FAST_HUFFMAN_LENGTH) {
+ uint32 z = c->sparse ? bit_reverse(c->sorted_codewords[i]) : c->codewords[i];
+ // set table entries for all bit combinations in the higher bits
+ while (z < FAST_HUFFMAN_TABLE_SIZE) {
+ c->fast_huffman[z] = i;
+ z += 1 << c->codeword_lengths[i];
+ }
+ }
+ }
+}
+
+#ifdef _MSC_VER
+#define STBV_CDECL __cdecl
+#else
+#define STBV_CDECL
+#endif
+
+static int STBV_CDECL uint32_compare(const void *p, const void *q)
+{
+ uint32 x = * (uint32 *) p;
+ uint32 y = * (uint32 *) q;
+ return x < y ? -1 : x > y;
+}
+
+static int include_in_sort(Codebook *c, uint8 len)
+{
+ if (c->sparse) { assert(len != NO_CODE); return TRUE; }
+ if (len == NO_CODE) return FALSE;
+ if (len > STB_VORBIS_FAST_HUFFMAN_LENGTH) return TRUE;
+ return FALSE;
+}
+
+// if the fast table above doesn't work, we want to binary
+// search them... need to reverse the bits
+static void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values)
+{
+ int i, len;
+ // build a list of all the entries
+ // OPTIMIZATION: don't include the short ones, since they'll be caught by FAST_HUFFMAN.
+ // this is kind of a frivolous optimization--I don't see any performance improvement,
+ // but it's like 4 extra lines of code, so.
+ if (!c->sparse) {
+ int k = 0;
+ for (i=0; i < c->entries; ++i)
+ if (include_in_sort(c, lengths[i]))
+ c->sorted_codewords[k++] = bit_reverse(c->codewords[i]);
+ assert(k == c->sorted_entries);
+ } else {
+ for (i=0; i < c->sorted_entries; ++i)
+ c->sorted_codewords[i] = bit_reverse(c->codewords[i]);
+ }
+
+ qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), uint32_compare);
+ c->sorted_codewords[c->sorted_entries] = 0xffffffff;
+
+ len = c->sparse ? c->sorted_entries : c->entries;
+ // now we need to indicate how they correspond; we could either
+ // #1: sort a different data structure that says who they correspond to
+ // #2: for each sorted entry, search the original list to find who corresponds
+ // #3: for each original entry, find the sorted entry
+ // #1 requires extra storage, #2 is slow, #3 can use binary search!
+ for (i=0; i < len; ++i) {
+ int huff_len = c->sparse ? lengths[values[i]] : lengths[i];
+ if (include_in_sort(c,huff_len)) {
+ uint32 code = bit_reverse(c->codewords[i]);
+ int x=0, n=c->sorted_entries;
+ while (n > 1) {
+ // invariant: sc[x] <= code < sc[x+n]
+ int m = x + (n >> 1);
+ if (c->sorted_codewords[m] <= code) {
+ x = m;
+ n -= (n>>1);
+ } else {
+ n >>= 1;
+ }
+ }
+ assert(c->sorted_codewords[x] == code);
+ if (c->sparse) {
+ c->sorted_values[x] = values[i];
+ c->codeword_lengths[x] = huff_len;
+ } else {
+ c->sorted_values[x] = i;
+ }
+ }
+ }
+}
+
+// only run while parsing the header (3 times)
+static int vorbis_validate(uint8 *data)
+{
+ static uint8 vorbis[6] = { 'v', 'o', 'r', 'b', 'i', 's' };
+ return memcmp(data, vorbis, 6) == 0;
+}
+
+// called from setup only, once per code book
+// (formula implied by specification)
+static int lookup1_values(int entries, int dim)
+{
+ int r = (int) floor(exp((float) log((float) entries) / dim));
+ if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning;
+ ++r; // floor() to avoid _ftol() when non-CRT
+ assert(pow((float) r+1, dim) > entries);
+ assert((int) floor(pow((float) r, dim)) <= entries); // (int),floor() as above
+ return r;
+}
+
+// called twice per file
+static void compute_twiddle_factors(int n, float *A, float *B, float *C)
+{
+ int n4 = n >> 2, n8 = n >> 3;
+ int k,k2;
+
+ for (k=k2=0; k < n4; ++k,k2+=2) {
+ A[k2 ] = (float) cos(4*k*M_PI/n);
+ A[k2+1] = (float) -sin(4*k*M_PI/n);
+ B[k2 ] = (float) cos((k2+1)*M_PI/n/2) * 0.5f;
+ B[k2+1] = (float) sin((k2+1)*M_PI/n/2) * 0.5f;
+ }
+ for (k=k2=0; k < n8; ++k,k2+=2) {
+ C[k2 ] = (float) cos(2*(k2+1)*M_PI/n);
+ C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n);
+ }
+}
+
+static void compute_window(int n, float *window)
+{
+ int n2 = n >> 1, i;
+ for (i=0; i < n2; ++i)
+ window[i] = (float) sin(0.5 * M_PI * square((float) sin((i - 0 + 0.5) / n2 * 0.5 * M_PI)));
+}
+
+static void compute_bitreverse(int n, uint16 *rev)
+{
+ int ld = ilog(n) - 1; // ilog is off-by-one from normal definitions
+ int i, n8 = n >> 3;
+ for (i=0; i < n8; ++i)
+ rev[i] = (bit_reverse(i) >> (32-ld+3)) << 2;
+}
+
+static int init_blocksize(vorb *f, int b, int n)
+{
+ int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3;
+ f->A[b] = (float *) setup_malloc(f, sizeof(float) * n2);
+ f->B[b] = (float *) setup_malloc(f, sizeof(float) * n2);
+ f->C[b] = (float *) setup_malloc(f, sizeof(float) * n4);
+ if (!f->A[b] || !f->B[b] || !f->C[b]) return error(f, VORBIS_outofmem);
+ compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]);
+ f->window[b] = (float *) setup_malloc(f, sizeof(float) * n2);
+ if (!f->window[b]) return error(f, VORBIS_outofmem);
+ compute_window(n, f->window[b]);
+ f->bit_reverse[b] = (uint16 *) setup_malloc(f, sizeof(uint16) * n8);
+ if (!f->bit_reverse[b]) return error(f, VORBIS_outofmem);
+ compute_bitreverse(n, f->bit_reverse[b]);
+ return TRUE;
+}
+
+static void neighbors(uint16 *x, int n, int *plow, int *phigh)
+{
+ int low = -1;
+ int high = 65536;
+ int i;
+ for (i=0; i < n; ++i) {
+ if (x[i] > low && x[i] < x[n]) { *plow = i; low = x[i]; }
+ if (x[i] < high && x[i] > x[n]) { *phigh = i; high = x[i]; }
+ }
+}
+
+// this has been repurposed so y is now the original index instead of y
+typedef struct
+{
+ uint16 x,y;
+} Point;
+
+static int STBV_CDECL point_compare(const void *p, const void *q)
+{
+ Point *a = (Point *) p;
+ Point *b = (Point *) q;
+ return a->x < b->x ? -1 : a->x > b->x;
+}
+
+//
+/////////////////////// END LEAF SETUP FUNCTIONS //////////////////////////
+
+
+#if defined(STB_VORBIS_NO_STDIO)
+ #define USE_MEMORY(z) TRUE
+#else
+ #define USE_MEMORY(z) ((z)->stream)
+#endif
+
+static uint8 get8(vorb *z)
+{
+ if (USE_MEMORY(z)) {
+ if (z->stream >= z->stream_end) { z->eof = TRUE; return 0; }
+ return *z->stream++;
+ }
+
+ #ifndef STB_VORBIS_NO_STDIO
+ {
+ int c = fgetc(z->f);
+ if (c == EOF) { z->eof = TRUE; return 0; }
+ return c;
+ }
+ #endif
+}
+
+static uint32 get32(vorb *f)
+{
+ uint32 x;
+ x = get8(f);
+ x += get8(f) << 8;
+ x += get8(f) << 16;
+ x += (uint32) get8(f) << 24;
+ return x;
+}
+
+static int getn(vorb *z, uint8 *data, int n)
+{
+ if (USE_MEMORY(z)) {
+ if (z->stream+n > z->stream_end) { z->eof = 1; return 0; }
+ memcpy(data, z->stream, n);
+ z->stream += n;
+ return 1;
+ }
+
+ #ifndef STB_VORBIS_NO_STDIO
+ if (fread(data, n, 1, z->f) == 1)
+ return 1;
+ else {
+ z->eof = 1;
+ return 0;
+ }
+ #endif
+}
+
+static void skip(vorb *z, int n)
+{
+ if (USE_MEMORY(z)) {
+ z->stream += n;
+ if (z->stream >= z->stream_end) z->eof = 1;
+ return;
+ }
+ #ifndef STB_VORBIS_NO_STDIO
+ {
+ long x = ftell(z->f);
+ fseek(z->f, x+n, SEEK_SET);
+ }
+ #endif
+}
+
+static int set_file_offset(stb_vorbis *f, unsigned int loc)
+{
+ #ifndef STB_VORBIS_NO_PUSHDATA_API
+ if (f->push_mode) return 0;
+ #endif
+ f->eof = 0;
+ if (USE_MEMORY(f)) {
+ if (f->stream_start + loc >= f->stream_end || f->stream_start + loc < f->stream_start) {
+ f->stream = f->stream_end;
+ f->eof = 1;
+ return 0;
+ } else {
+ f->stream = f->stream_start + loc;
+ return 1;
+ }
+ }
+ #ifndef STB_VORBIS_NO_STDIO
+ if (loc + f->f_start < loc || loc >= 0x80000000) {
+ loc = 0x7fffffff;
+ f->eof = 1;
+ } else {
+ loc += f->f_start;
+ }
+ if (!fseek(f->f, loc, SEEK_SET))
+ return 1;
+ f->eof = 1;
+ fseek(f->f, f->f_start, SEEK_END);
+ return 0;
+ #endif
+}
+
+
+static uint8 ogg_page_header[4] = { 0x4f, 0x67, 0x67, 0x53 };
+
+static int capture_pattern(vorb *f)
+{
+ if (0x4f != get8(f)) return FALSE;
+ if (0x67 != get8(f)) return FALSE;
+ if (0x67 != get8(f)) return FALSE;
+ if (0x53 != get8(f)) return FALSE;
+ return TRUE;
+}
+
+#define PAGEFLAG_continued_packet 1
+#define PAGEFLAG_first_page 2
+#define PAGEFLAG_last_page 4
+
+static int start_page_no_capturepattern(vorb *f)
+{
+ uint32 loc0,loc1,n;
+ // stream structure version
+ if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version);
+ // header flag
+ f->page_flag = get8(f);
+ // absolute granule position
+ loc0 = get32(f);
+ loc1 = get32(f);
+ // @TODO: validate loc0,loc1 as valid positions?
+ // stream serial number -- vorbis doesn't interleave, so discard
+ get32(f);
+ //if (f->serial != get32(f)) return error(f, VORBIS_incorrect_stream_serial_number);
+ // page sequence number
+ n = get32(f);
+ f->last_page = n;
+ // CRC32
+ get32(f);
+ // page_segments
+ f->segment_count = get8(f);
+ if (!getn(f, f->segments, f->segment_count))
+ return error(f, VORBIS_unexpected_eof);
+ // assume we _don't_ know any the sample position of any segments
+ f->end_seg_with_known_loc = -2;
+ if (loc0 != ~0U || loc1 != ~0U) {
+ int i;
+ // determine which packet is the last one that will complete
+ for (i=f->segment_count-1; i >= 0; --i)
+ if (f->segments[i] < 255)
+ break;
+ // 'i' is now the index of the _last_ segment of a packet that ends
+ if (i >= 0) {
+ f->end_seg_with_known_loc = i;
+ f->known_loc_for_packet = loc0;
+ }
+ }
+ if (f->first_decode) {
+ int i,len;
+ ProbedPage p;
+ len = 0;
+ for (i=0; i < f->segment_count; ++i)
+ len += f->segments[i];
+ len += 27 + f->segment_count;
+ p.page_start = f->first_audio_page_offset;
+ p.page_end = p.page_start + len;
+ p.last_decoded_sample = loc0;
+ f->p_first = p;
+ }
+ f->next_seg = 0;
+ return TRUE;
+}
+
+static int start_page(vorb *f)
+{
+ if (!capture_pattern(f)) return error(f, VORBIS_missing_capture_pattern);
+ return start_page_no_capturepattern(f);
+}
+
+static int start_packet(vorb *f)
+{
+ while (f->next_seg == -1) {
+ if (!start_page(f)) return FALSE;
+ if (f->page_flag & PAGEFLAG_continued_packet)
+ return error(f, VORBIS_continued_packet_flag_invalid);
+ }
+ f->last_seg = FALSE;
+ f->valid_bits = 0;
+ f->packet_bytes = 0;
+ f->bytes_in_seg = 0;
+ // f->next_seg is now valid
+ return TRUE;
+}
+
+static int maybe_start_packet(vorb *f)
+{
+ if (f->next_seg == -1) {
+ int x = get8(f);
+ if (f->eof) return FALSE; // EOF at page boundary is not an error!
+ if (0x4f != x ) return error(f, VORBIS_missing_capture_pattern);
+ if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern);
+ if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern);
+ if (0x53 != get8(f)) return error(f, VORBIS_missing_capture_pattern);
+ if (!start_page_no_capturepattern(f)) return FALSE;
+ if (f->page_flag & PAGEFLAG_continued_packet) {
+ // set up enough state that we can read this packet if we want,
+ // e.g. during recovery
+ f->last_seg = FALSE;
+ f->bytes_in_seg = 0;
+ return error(f, VORBIS_continued_packet_flag_invalid);
+ }
+ }
+ return start_packet(f);
+}
+
+static int next_segment(vorb *f)
+{
+ int len;
+ if (f->last_seg) return 0;
+ if (f->next_seg == -1) {
+ f->last_seg_which = f->segment_count-1; // in case start_page fails
+ if (!start_page(f)) { f->last_seg = 1; return 0; }
+ if (!(f->page_flag & PAGEFLAG_continued_packet)) return error(f, VORBIS_continued_packet_flag_invalid);
+ }
+ len = f->segments[f->next_seg++];
+ if (len < 255) {
+ f->last_seg = TRUE;
+ f->last_seg_which = f->next_seg-1;
+ }
+ if (f->next_seg >= f->segment_count)
+ f->next_seg = -1;
+ assert(f->bytes_in_seg == 0);
+ f->bytes_in_seg = len;
+ return len;
+}
+
+#define EOP (-1)
+#define INVALID_BITS (-1)
+
+static int get8_packet_raw(vorb *f)
+{
+ if (!f->bytes_in_seg) { // CLANG!
+ if (f->last_seg) return EOP;
+ else if (!next_segment(f)) return EOP;
+ }
+ assert(f->bytes_in_seg > 0);
+ --f->bytes_in_seg;
+ ++f->packet_bytes;
+ return get8(f);
+}
+
+static int get8_packet(vorb *f)
+{
+ int x = get8_packet_raw(f);
+ f->valid_bits = 0;
+ return x;
+}
+
+static void flush_packet(vorb *f)
+{
+ while (get8_packet_raw(f) != EOP);
+}
+
+// @OPTIMIZE: this is the secondary bit decoder, so it's probably not as important
+// as the huffman decoder?
+static uint32 get_bits(vorb *f, int n)
+{
+ uint32 z;
+
+ if (f->valid_bits < 0) return 0;
+ if (f->valid_bits < n) {
+ if (n > 24) {
+ // the accumulator technique below would not work correctly in this case
+ z = get_bits(f, 24);
+ z += get_bits(f, n-24) << 24;
+ return z;
+ }
+ if (f->valid_bits == 0) f->acc = 0;
+ while (f->valid_bits < n) {
+ int z = get8_packet_raw(f);
+ if (z == EOP) {
+ f->valid_bits = INVALID_BITS;
+ return 0;
+ }
+ f->acc += z << f->valid_bits;
+ f->valid_bits += 8;
+ }
+ }
+ if (f->valid_bits < 0) return 0;
+ z = f->acc & ((1 << n)-1);
+ f->acc >>= n;
+ f->valid_bits -= n;
+ return z;
+}
+
+// @OPTIMIZE: primary accumulator for huffman
+// expand the buffer to as many bits as possible without reading off end of packet
+// it might be nice to allow f->valid_bits and f->acc to be stored in registers,
+// e.g. cache them locally and decode locally
+static __forceinline void prep_huffman(vorb *f)
+{
+ if (f->valid_bits <= 24) {
+ if (f->valid_bits == 0) f->acc = 0;
+ do {
+ int z;
+ if (f->last_seg && !f->bytes_in_seg) return;
+ z = get8_packet_raw(f);
+ if (z == EOP) return;
+ f->acc += (unsigned) z << f->valid_bits;
+ f->valid_bits += 8;
+ } while (f->valid_bits <= 24);
+ }
+}
+
+enum
+{
+ VORBIS_packet_id = 1,
+ VORBIS_packet_comment = 3,
+ VORBIS_packet_setup = 5
+};
+
+static int codebook_decode_scalar_raw(vorb *f, Codebook *c)
+{
+ int i;
+ prep_huffman(f);
+
+ if (c->codewords == NULL && c->sorted_codewords == NULL)
+ return -1;
+
+ // cases to use binary search: sorted_codewords && !c->codewords
+ // sorted_codewords && c->entries > 8
+ if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) {
+ // binary search
+ uint32 code = bit_reverse(f->acc);
+ int x=0, n=c->sorted_entries, len;
+
+ while (n > 1) {
+ // invariant: sc[x] <= code < sc[x+n]
+ int m = x + (n >> 1);
+ if (c->sorted_codewords[m] <= code) {
+ x = m;
+ n -= (n>>1);
+ } else {
+ n >>= 1;
+ }
+ }
+ // x is now the sorted index
+ if (!c->sparse) x = c->sorted_values[x];
+ // x is now sorted index if sparse, or symbol otherwise
+ len = c->codeword_lengths[x];
+ if (f->valid_bits >= len) {
+ f->acc >>= len;
+ f->valid_bits -= len;
+ return x;
+ }
+
+ f->valid_bits = 0;
+ return -1;
+ }
+
+ // if small, linear search
+ assert(!c->sparse);
+ for (i=0; i < c->entries; ++i) {
+ if (c->codeword_lengths[i] == NO_CODE) continue;
+ if (c->codewords[i] == (f->acc & ((1 << c->codeword_lengths[i])-1))) {
+ if (f->valid_bits >= c->codeword_lengths[i]) {
+ f->acc >>= c->codeword_lengths[i];
+ f->valid_bits -= c->codeword_lengths[i];
+ return i;
+ }
+ f->valid_bits = 0;
+ return -1;
+ }
+ }
+
+ error(f, VORBIS_invalid_stream);
+ f->valid_bits = 0;
+ return -1;
+}
+
+#ifndef STB_VORBIS_NO_INLINE_DECODE
+
+#define DECODE_RAW(var, f,c) \
+ if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH) \
+ prep_huffman(f); \
+ var = f->acc & FAST_HUFFMAN_TABLE_MASK; \
+ var = c->fast_huffman[var]; \
+ if (var >= 0) { \
+ int n = c->codeword_lengths[var]; \
+ f->acc >>= n; \
+ f->valid_bits -= n; \
+ if (f->valid_bits < 0) { f->valid_bits = 0; var = -1; } \
+ } else { \
+ var = codebook_decode_scalar_raw(f,c); \
+ }
+
+#else
+
+static int codebook_decode_scalar(vorb *f, Codebook *c)
+{
+ int i;
+ if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH)
+ prep_huffman(f);
+ // fast huffman table lookup
+ i = f->acc & FAST_HUFFMAN_TABLE_MASK;
+ i = c->fast_huffman[i];
+ if (i >= 0) {
+ f->acc >>= c->codeword_lengths[i];
+ f->valid_bits -= c->codeword_lengths[i];
+ if (f->valid_bits < 0) { f->valid_bits = 0; return -1; }
+ return i;
+ }
+ return codebook_decode_scalar_raw(f,c);
+}
+
+#define DECODE_RAW(var,f,c) var = codebook_decode_scalar(f,c);
+
+#endif
+
+#define DECODE(var,f,c) \
+ DECODE_RAW(var,f,c) \
+ if (c->sparse) var = c->sorted_values[var];
+
+#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ #define DECODE_VQ(var,f,c) DECODE_RAW(var,f,c)
+#else
+ #define DECODE_VQ(var,f,c) DECODE(var,f,c)
+#endif
+
+
+
+
+
+
+// CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case
+// where we avoid one addition
+#define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off])
+#define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off])
+#define CODEBOOK_ELEMENT_BASE(c) (0)
+
+static int codebook_decode_start(vorb *f, Codebook *c)
+{
+ int z = -1;
+
+ // type 0 is only legal in a scalar context
+ if (c->lookup_type == 0)
+ error(f, VORBIS_invalid_stream);
+ else {
+ DECODE_VQ(z,f,c);
+ if (c->sparse) assert(z < c->sorted_entries);
+ if (z < 0) { // check for EOP
+ if (!f->bytes_in_seg)
+ if (f->last_seg)
+ return z;
+ error(f, VORBIS_invalid_stream);
+ }
+ }
+ return z;
+}
+
+static int codebook_decode(vorb *f, Codebook *c, float *output, int len)
+{
+ int i,z = codebook_decode_start(f,c);
+ if (z < 0) return FALSE;
+ if (len > c->dimensions) len = c->dimensions;
+
+#ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ if (c->lookup_type == 1) {
+ float last = CODEBOOK_ELEMENT_BASE(c);
+ int div = 1;
+ for (i=0; i < len; ++i) {
+ int off = (z / div) % c->lookup_values;
+ float val = CODEBOOK_ELEMENT_FAST(c,off) + last;
+ output[i] += val;
+ if (c->sequence_p) last = val + c->minimum_value;
+ div *= c->lookup_values;
+ }
+ return TRUE;
+ }
+#endif
+
+ z *= c->dimensions;
+ if (c->sequence_p) {
+ float last = CODEBOOK_ELEMENT_BASE(c);
+ for (i=0; i < len; ++i) {
+ float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
+ output[i] += val;
+ last = val + c->minimum_value;
+ }
+ } else {
+ float last = CODEBOOK_ELEMENT_BASE(c);
+ for (i=0; i < len; ++i) {
+ output[i] += CODEBOOK_ELEMENT_FAST(c,z+i) + last;
+ }
+ }
+
+ return TRUE;
+}
+
+static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, int step)
+{
+ int i,z = codebook_decode_start(f,c);
+ float last = CODEBOOK_ELEMENT_BASE(c);
+ if (z < 0) return FALSE;
+ if (len > c->dimensions) len = c->dimensions;
+
+#ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ if (c->lookup_type == 1) {
+ int div = 1;
+ for (i=0; i < len; ++i) {
+ int off = (z / div) % c->lookup_values;
+ float val = CODEBOOK_ELEMENT_FAST(c,off) + last;
+ output[i*step] += val;
+ if (c->sequence_p) last = val;
+ div *= c->lookup_values;
+ }
+ return TRUE;
+ }
+#endif
+
+ z *= c->dimensions;
+ for (i=0; i < len; ++i) {
+ float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
+ output[i*step] += val;
+ if (c->sequence_p) last = val;
+ }
+
+ return TRUE;
+}
+
+static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **outputs, int ch, int *c_inter_p, int *p_inter_p, int len, int total_decode)
+{
+ int c_inter = *c_inter_p;
+ int p_inter = *p_inter_p;
+ int i,z, effective = c->dimensions;
+
+ // type 0 is only legal in a scalar context
+ if (c->lookup_type == 0) return error(f, VORBIS_invalid_stream);
+
+ while (total_decode > 0) {
+ float last = CODEBOOK_ELEMENT_BASE(c);
+ DECODE_VQ(z,f,c);
+ #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ assert(!c->sparse || z < c->sorted_entries);
+ #endif
+ if (z < 0) {
+ if (!f->bytes_in_seg)
+ if (f->last_seg) return FALSE;
+ return error(f, VORBIS_invalid_stream);
+ }
+
+ // if this will take us off the end of the buffers, stop short!
+ // we check by computing the length of the virtual interleaved
+ // buffer (len*ch), our current offset within it (p_inter*ch)+(c_inter),
+ // and the length we'll be using (effective)
+ if (c_inter + p_inter*ch + effective > len * ch) {
+ effective = len*ch - (p_inter*ch - c_inter);
+ }
+
+ #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ if (c->lookup_type == 1) {
+ int div = 1;
+ for (i=0; i < effective; ++i) {
+ int off = (z / div) % c->lookup_values;
+ float val = CODEBOOK_ELEMENT_FAST(c,off) + last;
+ if (outputs[c_inter])
+ outputs[c_inter][p_inter] += val;
+ if (++c_inter == ch) { c_inter = 0; ++p_inter; }
+ if (c->sequence_p) last = val;
+ div *= c->lookup_values;
+ }
+ } else
+ #endif
+ {
+ z *= c->dimensions;
+ if (c->sequence_p) {
+ for (i=0; i < effective; ++i) {
+ float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
+ if (outputs[c_inter])
+ outputs[c_inter][p_inter] += val;
+ if (++c_inter == ch) { c_inter = 0; ++p_inter; }
+ last = val;
+ }
+ } else {
+ for (i=0; i < effective; ++i) {
+ float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
+ if (outputs[c_inter])
+ outputs[c_inter][p_inter] += val;
+ if (++c_inter == ch) { c_inter = 0; ++p_inter; }
+ }
+ }
+ }
+
+ total_decode -= effective;
+ }
+ *c_inter_p = c_inter;
+ *p_inter_p = p_inter;
+ return TRUE;
+}
+
+static int predict_point(int x, int x0, int x1, int y0, int y1)
+{
+ int dy = y1 - y0;
+ int adx = x1 - x0;
+ // @OPTIMIZE: force int division to round in the right direction... is this necessary on x86?
+ int err = abs(dy) * (x - x0);
+ int off = err / adx;
+ return dy < 0 ? y0 - off : y0 + off;
+}
+
+// the following table is block-copied from the specification
+static float inverse_db_table[256] =
+{
+ 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f,
+ 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f,
+ 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.1287530e-07f,
+ 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f,
+ 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f,
+ 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f,
+ 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f,
+ 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f,
+ 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f,
+ 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f,
+ 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f,
+ 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f,
+ 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f,
+ 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f,
+ 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f,
+ 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f,
+ 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f,
+ 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f,
+ 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f,
+ 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f,
+ 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f,
+ 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f,
+ 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f,
+ 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f,
+ 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f,
+ 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f,
+ 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f,
+ 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f,
+ 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f,
+ 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f,
+ 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f,
+ 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f,
+ 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f,
+ 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f,
+ 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f,
+ 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f,
+ 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f,
+ 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f,
+ 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f,
+ 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f,
+ 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f,
+ 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f,
+ 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f,
+ 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f,
+ 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f,
+ 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f,
+ 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f,
+ 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f,
+ 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f,
+ 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f,
+ 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f,
+ 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f,
+ 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f,
+ 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f,
+ 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f,
+ 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f,
+ 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f,
+ 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f,
+ 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f,
+ 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f,
+ 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f,
+ 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f,
+ 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f,
+ 0.82788260f, 0.88168307f, 0.9389798f, 1.0f
+};
+
+
+// @OPTIMIZE: if you want to replace this bresenham line-drawing routine,
+// note that you must produce bit-identical output to decode correctly;
+// this specific sequence of operations is specified in the spec (it's
+// drawing integer-quantized frequency-space lines that the encoder
+// expects to be exactly the same)
+// ... also, isn't the whole point of Bresenham's algorithm to NOT
+// have to divide in the setup? sigh.
+#ifndef STB_VORBIS_NO_DEFER_FLOOR
+#define LINE_OP(a,b) a *= b
+#else
+#define LINE_OP(a,b) a = b
+#endif
+
+#ifdef STB_VORBIS_DIVIDE_TABLE
+#define DIVTAB_NUMER 32
+#define DIVTAB_DENOM 64
+int8 integer_divide_table[DIVTAB_NUMER][DIVTAB_DENOM]; // 2KB
+#endif
+
+static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y1, int n)
+{
+ int dy = y1 - y0;
+ int adx = x1 - x0;
+ int ady = abs(dy);
+ int base;
+ int x=x0,y=y0;
+ int err = 0;
+ int sy;
+
+#ifdef STB_VORBIS_DIVIDE_TABLE
+ if (adx < DIVTAB_DENOM && ady < DIVTAB_NUMER) {
+ if (dy < 0) {
+ base = -integer_divide_table[ady][adx];
+ sy = base-1;
+ } else {
+ base = integer_divide_table[ady][adx];
+ sy = base+1;
+ }
+ } else {
+ base = dy / adx;
+ if (dy < 0)
+ sy = base - 1;
+ else
+ sy = base+1;
+ }
+#else
+ base = dy / adx;
+ if (dy < 0)
+ sy = base - 1;
+ else
+ sy = base+1;
+#endif
+ ady -= abs(base) * adx;
+ if (x1 > n) x1 = n;
+ if (x < x1) {
+ LINE_OP(output[x], inverse_db_table[y]);
+ for (++x; x < x1; ++x) {
+ err += ady;
+ if (err >= adx) {
+ err -= adx;
+ y += sy;
+ } else
+ y += base;
+ LINE_OP(output[x], inverse_db_table[y]);
+ }
+ }
+}
+
+static int residue_decode(vorb *f, Codebook *book, float *target, int offset, int n, int rtype)
+{
+ int k;
+ if (rtype == 0) {
+ int step = n / book->dimensions;
+ for (k=0; k < step; ++k)
+ if (!codebook_decode_step(f, book, target+offset+k, n-offset-k, step))
+ return FALSE;
+ } else {
+ for (k=0; k < n; ) {
+ if (!codebook_decode(f, book, target+offset, n-k))
+ return FALSE;
+ k += book->dimensions;
+ offset += book->dimensions;
+ }
+ }
+ return TRUE;
+}
+
+static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode)
+{
+ int i,j,pass;
+ Residue *r = f->residue_config + rn;
+ int rtype = f->residue_types[rn];
+ int c = r->classbook;
+ int classwords = f->codebooks[c].dimensions;
+ int n_read = r->end - r->begin;
+ int part_read = n_read / r->part_size;
+ int temp_alloc_point = temp_alloc_save(f);
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ uint8 ***part_classdata = (uint8 ***) temp_block_array(f,f->channels, part_read * sizeof(**part_classdata));
+ #else
+ int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications));
+ #endif
+
+ CHECK(f);
+
+ for (i=0; i < ch; ++i)
+ if (!do_not_decode[i])
+ memset(residue_buffers[i], 0, sizeof(float) * n);
+
+ if (rtype == 2 && ch != 1) {
+ for (j=0; j < ch; ++j)
+ if (!do_not_decode[j])
+ break;
+ if (j == ch)
+ goto done;
+
+ for (pass=0; pass < 8; ++pass) {
+ int pcount = 0, class_set = 0;
+ if (ch == 2) {
+ while (pcount < part_read) {
+ int z = r->begin + pcount*r->part_size;
+ int c_inter = (z & 1), p_inter = z>>1;
+ if (pass == 0) {
+ Codebook *c = f->codebooks+r->classbook;
+ int q;
+ DECODE(q,f,c);
+ if (q == EOP) goto done;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ part_classdata[0][class_set] = r->classdata[q];
+ #else
+ for (i=classwords-1; i >= 0; --i) {
+ classifications[0][i+pcount] = q % r->classifications;
+ q /= r->classifications;
+ }
+ #endif
+ }
+ for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
+ int z = r->begin + pcount*r->part_size;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ int c = part_classdata[0][class_set][i];
+ #else
+ int c = classifications[0][pcount];
+ #endif
+ int b = r->residue_books[c][pass];
+ if (b >= 0) {
+ Codebook *book = f->codebooks + b;
+ #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
+ goto done;
+ #else
+ // saves 1%
+ if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
+ goto done;
+ #endif
+ } else {
+ z += r->part_size;
+ c_inter = z & 1;
+ p_inter = z >> 1;
+ }
+ }
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ ++class_set;
+ #endif
+ }
+ } else if (ch == 1) {
+ while (pcount < part_read) {
+ int z = r->begin + pcount*r->part_size;
+ int c_inter = 0, p_inter = z;
+ if (pass == 0) {
+ Codebook *c = f->codebooks+r->classbook;
+ int q;
+ DECODE(q,f,c);
+ if (q == EOP) goto done;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ part_classdata[0][class_set] = r->classdata[q];
+ #else
+ for (i=classwords-1; i >= 0; --i) {
+ classifications[0][i+pcount] = q % r->classifications;
+ q /= r->classifications;
+ }
+ #endif
+ }
+ for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
+ int z = r->begin + pcount*r->part_size;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ int c = part_classdata[0][class_set][i];
+ #else
+ int c = classifications[0][pcount];
+ #endif
+ int b = r->residue_books[c][pass];
+ if (b >= 0) {
+ Codebook *book = f->codebooks + b;
+ if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
+ goto done;
+ } else {
+ z += r->part_size;
+ c_inter = 0;
+ p_inter = z;
+ }
+ }
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ ++class_set;
+ #endif
+ }
+ } else {
+ while (pcount < part_read) {
+ int z = r->begin + pcount*r->part_size;
+ int c_inter = z % ch, p_inter = z/ch;
+ if (pass == 0) {
+ Codebook *c = f->codebooks+r->classbook;
+ int q;
+ DECODE(q,f,c);
+ if (q == EOP) goto done;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ part_classdata[0][class_set] = r->classdata[q];
+ #else
+ for (i=classwords-1; i >= 0; --i) {
+ classifications[0][i+pcount] = q % r->classifications;
+ q /= r->classifications;
+ }
+ #endif
+ }
+ for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
+ int z = r->begin + pcount*r->part_size;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ int c = part_classdata[0][class_set][i];
+ #else
+ int c = classifications[0][pcount];
+ #endif
+ int b = r->residue_books[c][pass];
+ if (b >= 0) {
+ Codebook *book = f->codebooks + b;
+ if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
+ goto done;
+ } else {
+ z += r->part_size;
+ c_inter = z % ch;
+ p_inter = z / ch;
+ }
+ }
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ ++class_set;
+ #endif
+ }
+ }
+ }
+ goto done;
+ }
+ CHECK(f);
+
+ for (pass=0; pass < 8; ++pass) {
+ int pcount = 0, class_set=0;
+ while (pcount < part_read) {
+ if (pass == 0) {
+ for (j=0; j < ch; ++j) {
+ if (!do_not_decode[j]) {
+ Codebook *c = f->codebooks+r->classbook;
+ int temp;
+ DECODE(temp,f,c);
+ if (temp == EOP) goto done;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ part_classdata[j][class_set] = r->classdata[temp];
+ #else
+ for (i=classwords-1; i >= 0; --i) {
+ classifications[j][i+pcount] = temp % r->classifications;
+ temp /= r->classifications;
+ }
+ #endif
+ }
+ }
+ }
+ for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
+ for (j=0; j < ch; ++j) {
+ if (!do_not_decode[j]) {
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ int c = part_classdata[j][class_set][i];
+ #else
+ int c = classifications[j][pcount];
+ #endif
+ int b = r->residue_books[c][pass];
+ if (b >= 0) {
+ float *target = residue_buffers[j];
+ int offset = r->begin + pcount * r->part_size;
+ int n = r->part_size;
+ Codebook *book = f->codebooks + b;
+ if (!residue_decode(f, book, target, offset, n, rtype))
+ goto done;
+ }
+ }
+ }
+ }
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ ++class_set;
+ #endif
+ }
+ }
+ done:
+ CHECK(f);
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ temp_free(f,part_classdata);
+ #else
+ temp_free(f,classifications);
+ #endif
+ temp_alloc_restore(f,temp_alloc_point);
+}
+
+
+#if 0
+// slow way for debugging
+void inverse_mdct_slow(float *buffer, int n)
+{
+ int i,j;
+ int n2 = n >> 1;
+ float *x = (float *) malloc(sizeof(*x) * n2);
+ memcpy(x, buffer, sizeof(*x) * n2);
+ for (i=0; i < n; ++i) {
+ float acc = 0;
+ for (j=0; j < n2; ++j)
+ // formula from paper:
+ //acc += n/4.0f * x[j] * (float) cos(M_PI / 2 / n * (2 * i + 1 + n/2.0)*(2*j+1));
+ // formula from wikipedia
+ //acc += 2.0f / n2 * x[j] * (float) cos(M_PI/n2 * (i + 0.5 + n2/2)*(j + 0.5));
+ // these are equivalent, except the formula from the paper inverts the multiplier!
+ // however, what actually works is NO MULTIPLIER!?!
+ //acc += 64 * 2.0f / n2 * x[j] * (float) cos(M_PI/n2 * (i + 0.5 + n2/2)*(j + 0.5));
+ acc += x[j] * (float) cos(M_PI / 2 / n * (2 * i + 1 + n/2.0)*(2*j+1));
+ buffer[i] = acc;
+ }
+ free(x);
+}
+#elif 0
+// same as above, but just barely able to run in real time on modern machines
+void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype)
+{
+ float mcos[16384];
+ int i,j;
+ int n2 = n >> 1, nmask = (n << 2) -1;
+ float *x = (float *) malloc(sizeof(*x) * n2);
+ memcpy(x, buffer, sizeof(*x) * n2);
+ for (i=0; i < 4*n; ++i)
+ mcos[i] = (float) cos(M_PI / 2 * i / n);
+
+ for (i=0; i < n; ++i) {
+ float acc = 0;
+ for (j=0; j < n2; ++j)
+ acc += x[j] * mcos[(2 * i + 1 + n2)*(2*j+1) & nmask];
+ buffer[i] = acc;
+ }
+ free(x);
+}
+#elif 0
+// transform to use a slow dct-iv; this is STILL basically trivial,
+// but only requires half as many ops
+void dct_iv_slow(float *buffer, int n)
+{
+ float mcos[16384];
+ float x[2048];
+ int i,j;
+ int n2 = n >> 1, nmask = (n << 3) - 1;
+ memcpy(x, buffer, sizeof(*x) * n);
+ for (i=0; i < 8*n; ++i)
+ mcos[i] = (float) cos(M_PI / 4 * i / n);
+ for (i=0; i < n; ++i) {
+ float acc = 0;
+ for (j=0; j < n; ++j)
+ acc += x[j] * mcos[((2 * i + 1)*(2*j+1)) & nmask];
+ buffer[i] = acc;
+ }
+}
+
+void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype)
+{
+ int i, n4 = n >> 2, n2 = n >> 1, n3_4 = n - n4;
+ float temp[4096];
+
+ memcpy(temp, buffer, n2 * sizeof(float));
+ dct_iv_slow(temp, n2); // returns -c'-d, a-b'
+
+ for (i=0; i < n4 ; ++i) buffer[i] = temp[i+n4]; // a-b'
+ for ( ; i < n3_4; ++i) buffer[i] = -temp[n3_4 - i - 1]; // b-a', c+d'
+ for ( ; i < n ; ++i) buffer[i] = -temp[i - n3_4]; // c'+d
+}
+#endif
+
+#ifndef LIBVORBIS_MDCT
+#define LIBVORBIS_MDCT 0
+#endif
+
+#if LIBVORBIS_MDCT
+// directly call the vorbis MDCT using an interface documented
+// by Jeff Roberts... useful for performance comparison
+typedef struct
+{
+ int n;
+ int log2n;
+
+ float *trig;
+ int *bitrev;
+
+ float scale;
+} mdct_lookup;
+
+extern void mdct_init(mdct_lookup *lookup, int n);
+extern void mdct_clear(mdct_lookup *l);
+extern void mdct_backward(mdct_lookup *init, float *in, float *out);
+
+mdct_lookup M1,M2;
+
+void inverse_mdct(float *buffer, int n, vorb *f, int blocktype)
+{
+ mdct_lookup *M;
+ if (M1.n == n) M = &M1;
+ else if (M2.n == n) M = &M2;
+ else if (M1.n == 0) { mdct_init(&M1, n); M = &M1; }
+ else {
+ if (M2.n) __asm int 3;
+ mdct_init(&M2, n);
+ M = &M2;
+ }
+
+ mdct_backward(M, buffer, buffer);
+}
+#endif
+
+
+// the following were split out into separate functions while optimizing;
+// they could be pushed back up but eh. __forceinline showed no change;
+// they're probably already being inlined.
+static void imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, float *A)
+{
+ float *ee0 = e + i_off;
+ float *ee2 = ee0 + k_off;
+ int i;
+
+ assert((n & 3) == 0);
+ for (i=(n>>2); i > 0; --i) {
+ float k00_20, k01_21;
+ k00_20 = ee0[ 0] - ee2[ 0];
+ k01_21 = ee0[-1] - ee2[-1];
+ ee0[ 0] += ee2[ 0];//ee0[ 0] = ee0[ 0] + ee2[ 0];
+ ee0[-1] += ee2[-1];//ee0[-1] = ee0[-1] + ee2[-1];
+ ee2[ 0] = k00_20 * A[0] - k01_21 * A[1];
+ ee2[-1] = k01_21 * A[0] + k00_20 * A[1];
+ A += 8;
+
+ k00_20 = ee0[-2] - ee2[-2];
+ k01_21 = ee0[-3] - ee2[-3];
+ ee0[-2] += ee2[-2];//ee0[-2] = ee0[-2] + ee2[-2];
+ ee0[-3] += ee2[-3];//ee0[-3] = ee0[-3] + ee2[-3];
+ ee2[-2] = k00_20 * A[0] - k01_21 * A[1];
+ ee2[-3] = k01_21 * A[0] + k00_20 * A[1];
+ A += 8;
+
+ k00_20 = ee0[-4] - ee2[-4];
+ k01_21 = ee0[-5] - ee2[-5];
+ ee0[-4] += ee2[-4];//ee0[-4] = ee0[-4] + ee2[-4];
+ ee0[-5] += ee2[-5];//ee0[-5] = ee0[-5] + ee2[-5];
+ ee2[-4] = k00_20 * A[0] - k01_21 * A[1];
+ ee2[-5] = k01_21 * A[0] + k00_20 * A[1];
+ A += 8;
+
+ k00_20 = ee0[-6] - ee2[-6];
+ k01_21 = ee0[-7] - ee2[-7];
+ ee0[-6] += ee2[-6];//ee0[-6] = ee0[-6] + ee2[-6];
+ ee0[-7] += ee2[-7];//ee0[-7] = ee0[-7] + ee2[-7];
+ ee2[-6] = k00_20 * A[0] - k01_21 * A[1];
+ ee2[-7] = k01_21 * A[0] + k00_20 * A[1];
+ A += 8;
+ ee0 -= 8;
+ ee2 -= 8;
+ }
+}
+
+static void imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, float *A, int k1)
+{
+ int i;
+ float k00_20, k01_21;
+
+ float *e0 = e + d0;
+ float *e2 = e0 + k_off;
+
+ for (i=lim >> 2; i > 0; --i) {
+ k00_20 = e0[-0] - e2[-0];
+ k01_21 = e0[-1] - e2[-1];
+ e0[-0] += e2[-0];//e0[-0] = e0[-0] + e2[-0];
+ e0[-1] += e2[-1];//e0[-1] = e0[-1] + e2[-1];
+ e2[-0] = (k00_20)*A[0] - (k01_21) * A[1];
+ e2[-1] = (k01_21)*A[0] + (k00_20) * A[1];
+
+ A += k1;
+
+ k00_20 = e0[-2] - e2[-2];
+ k01_21 = e0[-3] - e2[-3];
+ e0[-2] += e2[-2];//e0[-2] = e0[-2] + e2[-2];
+ e0[-3] += e2[-3];//e0[-3] = e0[-3] + e2[-3];
+ e2[-2] = (k00_20)*A[0] - (k01_21) * A[1];
+ e2[-3] = (k01_21)*A[0] + (k00_20) * A[1];
+
+ A += k1;
+
+ k00_20 = e0[-4] - e2[-4];
+ k01_21 = e0[-5] - e2[-5];
+ e0[-4] += e2[-4];//e0[-4] = e0[-4] + e2[-4];
+ e0[-5] += e2[-5];//e0[-5] = e0[-5] + e2[-5];
+ e2[-4] = (k00_20)*A[0] - (k01_21) * A[1];
+ e2[-5] = (k01_21)*A[0] + (k00_20) * A[1];
+
+ A += k1;
+
+ k00_20 = e0[-6] - e2[-6];
+ k01_21 = e0[-7] - e2[-7];
+ e0[-6] += e2[-6];//e0[-6] = e0[-6] + e2[-6];
+ e0[-7] += e2[-7];//e0[-7] = e0[-7] + e2[-7];
+ e2[-6] = (k00_20)*A[0] - (k01_21) * A[1];
+ e2[-7] = (k01_21)*A[0] + (k00_20) * A[1];
+
+ e0 -= 8;
+ e2 -= 8;
+
+ A += k1;
+ }
+}
+
+static void imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, float *A, int a_off, int k0)
+{
+ int i;
+ float A0 = A[0];
+ float A1 = A[0+1];
+ float A2 = A[0+a_off];
+ float A3 = A[0+a_off+1];
+ float A4 = A[0+a_off*2+0];
+ float A5 = A[0+a_off*2+1];
+ float A6 = A[0+a_off*3+0];
+ float A7 = A[0+a_off*3+1];
+
+ float k00,k11;
+
+ float *ee0 = e +i_off;
+ float *ee2 = ee0+k_off;
+
+ for (i=n; i > 0; --i) {
+ k00 = ee0[ 0] - ee2[ 0];
+ k11 = ee0[-1] - ee2[-1];
+ ee0[ 0] = ee0[ 0] + ee2[ 0];
+ ee0[-1] = ee0[-1] + ee2[-1];
+ ee2[ 0] = (k00) * A0 - (k11) * A1;
+ ee2[-1] = (k11) * A0 + (k00) * A1;
+
+ k00 = ee0[-2] - ee2[-2];
+ k11 = ee0[-3] - ee2[-3];
+ ee0[-2] = ee0[-2] + ee2[-2];
+ ee0[-3] = ee0[-3] + ee2[-3];
+ ee2[-2] = (k00) * A2 - (k11) * A3;
+ ee2[-3] = (k11) * A2 + (k00) * A3;
+
+ k00 = ee0[-4] - ee2[-4];
+ k11 = ee0[-5] - ee2[-5];
+ ee0[-4] = ee0[-4] + ee2[-4];
+ ee0[-5] = ee0[-5] + ee2[-5];
+ ee2[-4] = (k00) * A4 - (k11) * A5;
+ ee2[-5] = (k11) * A4 + (k00) * A5;
+
+ k00 = ee0[-6] - ee2[-6];
+ k11 = ee0[-7] - ee2[-7];
+ ee0[-6] = ee0[-6] + ee2[-6];
+ ee0[-7] = ee0[-7] + ee2[-7];
+ ee2[-6] = (k00) * A6 - (k11) * A7;
+ ee2[-7] = (k11) * A6 + (k00) * A7;
+
+ ee0 -= k0;
+ ee2 -= k0;
+ }
+}
+
+static __forceinline void iter_54(float *z)
+{
+ float k00,k11,k22,k33;
+ float y0,y1,y2,y3;
+
+ k00 = z[ 0] - z[-4];
+ y0 = z[ 0] + z[-4];
+ y2 = z[-2] + z[-6];
+ k22 = z[-2] - z[-6];
+
+ z[-0] = y0 + y2; // z0 + z4 + z2 + z6
+ z[-2] = y0 - y2; // z0 + z4 - z2 - z6
+
+ // done with y0,y2
+
+ k33 = z[-3] - z[-7];
+
+ z[-4] = k00 + k33; // z0 - z4 + z3 - z7
+ z[-6] = k00 - k33; // z0 - z4 - z3 + z7
+
+ // done with k33
+
+ k11 = z[-1] - z[-5];
+ y1 = z[-1] + z[-5];
+ y3 = z[-3] + z[-7];
+
+ z[-1] = y1 + y3; // z1 + z5 + z3 + z7
+ z[-3] = y1 - y3; // z1 + z5 - z3 - z7
+ z[-5] = k11 - k22; // z1 - z5 + z2 - z6
+ z[-7] = k11 + k22; // z1 - z5 - z2 + z6
+}
+
+static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, int base_n)
+{
+ int a_off = base_n >> 3;
+ float A2 = A[0+a_off];
+ float *z = e + i_off;
+ float *base = z - 16 * n;
+
+ while (z > base) {
+ float k00,k11;
+
+ k00 = z[-0] - z[-8];
+ k11 = z[-1] - z[-9];
+ z[-0] = z[-0] + z[-8];
+ z[-1] = z[-1] + z[-9];
+ z[-8] = k00;
+ z[-9] = k11 ;
+
+ k00 = z[ -2] - z[-10];
+ k11 = z[ -3] - z[-11];
+ z[ -2] = z[ -2] + z[-10];
+ z[ -3] = z[ -3] + z[-11];
+ z[-10] = (k00+k11) * A2;
+ z[-11] = (k11-k00) * A2;
+
+ k00 = z[-12] - z[ -4]; // reverse to avoid a unary negation
+ k11 = z[ -5] - z[-13];
+ z[ -4] = z[ -4] + z[-12];
+ z[ -5] = z[ -5] + z[-13];
+ z[-12] = k11;
+ z[-13] = k00;
+
+ k00 = z[-14] - z[ -6]; // reverse to avoid a unary negation
+ k11 = z[ -7] - z[-15];
+ z[ -6] = z[ -6] + z[-14];
+ z[ -7] = z[ -7] + z[-15];
+ z[-14] = (k00+k11) * A2;
+ z[-15] = (k00-k11) * A2;
+
+ iter_54(z);
+ iter_54(z-8);
+ z -= 16;
+ }
+}
+
+static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype)
+{
+ int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l;
+ int ld;
+ // @OPTIMIZE: reduce register pressure by using fewer variables?
+ int save_point = temp_alloc_save(f);
+ float *buf2 = (float *) temp_alloc(f, n2 * sizeof(*buf2));
+ float *u=NULL,*v=NULL;
+ // twiddle factors
+ float *A = f->A[blocktype];
+
+ // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio"
+ // See notes about bugs in that paper in less-optimal implementation 'inverse_mdct_old' after this function.
+
+ // kernel from paper
+
+
+ // merged:
+ // copy and reflect spectral data
+ // step 0
+
+ // note that it turns out that the items added together during
+ // this step are, in fact, being added to themselves (as reflected
+ // by step 0). inexplicable inefficiency! this became obvious
+ // once I combined the passes.
+
+ // so there's a missing 'times 2' here (for adding X to itself).
+ // this propogates through linearly to the end, where the numbers
+ // are 1/2 too small, and need to be compensated for.
+
+ {
+ float *d,*e, *AA, *e_stop;
+ d = &buf2[n2-2];
+ AA = A;
+ e = &buffer[0];
+ e_stop = &buffer[n2];
+ while (e != e_stop) {
+ d[1] = (e[0] * AA[0] - e[2]*AA[1]);
+ d[0] = (e[0] * AA[1] + e[2]*AA[0]);
+ d -= 2;
+ AA += 2;
+ e += 4;
+ }
+
+ e = &buffer[n2-3];
+ while (d >= buf2) {
+ d[1] = (-e[2] * AA[0] - -e[0]*AA[1]);
+ d[0] = (-e[2] * AA[1] + -e[0]*AA[0]);
+ d -= 2;
+ AA += 2;
+ e -= 4;
+ }
+ }
+
+ // now we use symbolic names for these, so that we can
+ // possibly swap their meaning as we change which operations
+ // are in place
+
+ u = buffer;
+ v = buf2;
+
+ // step 2 (paper output is w, now u)
+ // this could be in place, but the data ends up in the wrong
+ // place... _somebody_'s got to swap it, so this is nominated
+ {
+ float *AA = &A[n2-8];
+ float *d0,*d1, *e0, *e1;
+
+ e0 = &v[n4];
+ e1 = &v[0];
+
+ d0 = &u[n4];
+ d1 = &u[0];
+
+ while (AA >= A) {
+ float v40_20, v41_21;
+
+ v41_21 = e0[1] - e1[1];
+ v40_20 = e0[0] - e1[0];
+ d0[1] = e0[1] + e1[1];
+ d0[0] = e0[0] + e1[0];
+ d1[1] = v41_21*AA[4] - v40_20*AA[5];
+ d1[0] = v40_20*AA[4] + v41_21*AA[5];
+
+ v41_21 = e0[3] - e1[3];
+ v40_20 = e0[2] - e1[2];
+ d0[3] = e0[3] + e1[3];
+ d0[2] = e0[2] + e1[2];
+ d1[3] = v41_21*AA[0] - v40_20*AA[1];
+ d1[2] = v40_20*AA[0] + v41_21*AA[1];
+
+ AA -= 8;
+
+ d0 += 4;
+ d1 += 4;
+ e0 += 4;
+ e1 += 4;
+ }
+ }
+
+ // step 3
+ ld = ilog(n) - 1; // ilog is off-by-one from normal definitions
+
+ // optimized step 3:
+
+ // the original step3 loop can be nested r inside s or s inside r;
+ // it's written originally as s inside r, but this is dumb when r
+ // iterates many times, and s few. So I have two copies of it and
+ // switch between them halfway.
+
+ // this is iteration 0 of step 3
+ imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n >> 3), A);
+ imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n >> 3), A);
+
+ // this is iteration 1 of step 3
+ imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n >> 4), A, 16);
+ imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n >> 4), A, 16);
+ imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n >> 4), A, 16);
+ imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n >> 4), A, 16);
+
+ l=2;
+ for (; l < (ld-3)>>1; ++l) {
+ int k0 = n >> (l+2), k0_2 = k0>>1;
+ int lim = 1 << (l+1);
+ int i;
+ for (i=0; i < lim; ++i)
+ imdct_step3_inner_r_loop(n >> (l+4), u, n2-1 - k0*i, -k0_2, A, 1 << (l+3));
+ }
+
+ for (; l < ld-6; ++l) {
+ int k0 = n >> (l+2), k1 = 1 << (l+3), k0_2 = k0>>1;
+ int rlim = n >> (l+6), r;
+ int lim = 1 << (l+1);
+ int i_off;
+ float *A0 = A;
+ i_off = n2-1;
+ for (r=rlim; r > 0; --r) {
+ imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, A0, k1, k0);
+ A0 += k1*4;
+ i_off -= 8;
+ }
+ }
+
+ // iterations with count:
+ // ld-6,-5,-4 all interleaved together
+ // the big win comes from getting rid of needless flops
+ // due to the constants on pass 5 & 4 being all 1 and 0;
+ // combining them to be simultaneous to improve cache made little difference
+ imdct_step3_inner_s_loop_ld654(n >> 5, u, n2-1, A, n);
+
+ // output is u
+
+ // step 4, 5, and 6
+ // cannot be in-place because of step 5
+ {
+ uint16 *bitrev = f->bit_reverse[blocktype];
+ // weirdly, I'd have thought reading sequentially and writing
+ // erratically would have been better than vice-versa, but in
+ // fact that's not what my testing showed. (That is, with
+ // j = bitreverse(i), do you read i and write j, or read j and write i.)
+
+ float *d0 = &v[n4-4];
+ float *d1 = &v[n2-4];
+ while (d0 >= v) {
+ int k4;
+
+ k4 = bitrev[0];
+ d1[3] = u[k4+0];
+ d1[2] = u[k4+1];
+ d0[3] = u[k4+2];
+ d0[2] = u[k4+3];
+
+ k4 = bitrev[1];
+ d1[1] = u[k4+0];
+ d1[0] = u[k4+1];
+ d0[1] = u[k4+2];
+ d0[0] = u[k4+3];
+
+ d0 -= 4;
+ d1 -= 4;
+ bitrev += 2;
+ }
+ }
+ // (paper output is u, now v)
+
+
+ // data must be in buf2
+ assert(v == buf2);
+
+ // step 7 (paper output is v, now v)
+ // this is now in place
+ {
+ float *C = f->C[blocktype];
+ float *d, *e;
+
+ d = v;
+ e = v + n2 - 4;
+
+ while (d < e) {
+ float a02,a11,b0,b1,b2,b3;
+
+ a02 = d[0] - e[2];
+ a11 = d[1] + e[3];
+
+ b0 = C[1]*a02 + C[0]*a11;
+ b1 = C[1]*a11 - C[0]*a02;
+
+ b2 = d[0] + e[ 2];
+ b3 = d[1] - e[ 3];
+
+ d[0] = b2 + b0;
+ d[1] = b3 + b1;
+ e[2] = b2 - b0;
+ e[3] = b1 - b3;
+
+ a02 = d[2] - e[0];
+ a11 = d[3] + e[1];
+
+ b0 = C[3]*a02 + C[2]*a11;
+ b1 = C[3]*a11 - C[2]*a02;
+
+ b2 = d[2] + e[ 0];
+ b3 = d[3] - e[ 1];
+
+ d[2] = b2 + b0;
+ d[3] = b3 + b1;
+ e[0] = b2 - b0;
+ e[1] = b1 - b3;
+
+ C += 4;
+ d += 4;
+ e -= 4;
+ }
+ }
+
+ // data must be in buf2
+
+
+ // step 8+decode (paper output is X, now buffer)
+ // this generates pairs of data a la 8 and pushes them directly through
+ // the decode kernel (pushing rather than pulling) to avoid having
+ // to make another pass later
+
+ // this cannot POSSIBLY be in place, so we refer to the buffers directly
+
+ {
+ float *d0,*d1,*d2,*d3;
+
+ float *B = f->B[blocktype] + n2 - 8;
+ float *e = buf2 + n2 - 8;
+ d0 = &buffer[0];
+ d1 = &buffer[n2-4];
+ d2 = &buffer[n2];
+ d3 = &buffer[n-4];
+ while (e >= v) {
+ float p0,p1,p2,p3;
+
+ p3 = e[6]*B[7] - e[7]*B[6];
+ p2 = -e[6]*B[6] - e[7]*B[7];
+
+ d0[0] = p3;
+ d1[3] = - p3;
+ d2[0] = p2;
+ d3[3] = p2;
+
+ p1 = e[4]*B[5] - e[5]*B[4];
+ p0 = -e[4]*B[4] - e[5]*B[5];
+
+ d0[1] = p1;
+ d1[2] = - p1;
+ d2[1] = p0;
+ d3[2] = p0;
+
+ p3 = e[2]*B[3] - e[3]*B[2];
+ p2 = -e[2]*B[2] - e[3]*B[3];
+
+ d0[2] = p3;
+ d1[1] = - p3;
+ d2[2] = p2;
+ d3[1] = p2;
+
+ p1 = e[0]*B[1] - e[1]*B[0];
+ p0 = -e[0]*B[0] - e[1]*B[1];
+
+ d0[3] = p1;
+ d1[0] = - p1;
+ d2[3] = p0;
+ d3[0] = p0;
+
+ B -= 8;
+ e -= 8;
+ d0 += 4;
+ d2 += 4;
+ d1 -= 4;
+ d3 -= 4;
+ }
+ }
+
+ temp_free(f,buf2);
+ temp_alloc_restore(f,save_point);
+}
+
+#if 0
+// this is the original version of the above code, if you want to optimize it from scratch
+void inverse_mdct_naive(float *buffer, int n)
+{
+ float s;
+ float A[1 << 12], B[1 << 12], C[1 << 11];
+ int i,k,k2,k4, n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l;
+ int n3_4 = n - n4, ld;
+ // how can they claim this only uses N words?!
+ // oh, because they're only used sparsely, whoops
+ float u[1 << 13], X[1 << 13], v[1 << 13], w[1 << 13];
+ // set up twiddle factors
+
+ for (k=k2=0; k < n4; ++k,k2+=2) {
+ A[k2 ] = (float) cos(4*k*M_PI/n);
+ A[k2+1] = (float) -sin(4*k*M_PI/n);
+ B[k2 ] = (float) cos((k2+1)*M_PI/n/2);
+ B[k2+1] = (float) sin((k2+1)*M_PI/n/2);
+ }
+ for (k=k2=0; k < n8; ++k,k2+=2) {
+ C[k2 ] = (float) cos(2*(k2+1)*M_PI/n);
+ C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n);
+ }
+
+ // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio"
+ // Note there are bugs in that pseudocode, presumably due to them attempting
+ // to rename the arrays nicely rather than representing the way their actual
+ // implementation bounces buffers back and forth. As a result, even in the
+ // "some formulars corrected" version, a direct implementation fails. These
+ // are noted below as "paper bug".
+
+ // copy and reflect spectral data
+ for (k=0; k < n2; ++k) u[k] = buffer[k];
+ for ( ; k < n ; ++k) u[k] = -buffer[n - k - 1];
+ // kernel from paper
+ // step 1
+ for (k=k2=k4=0; k < n4; k+=1, k2+=2, k4+=4) {
+ v[n-k4-1] = (u[k4] - u[n-k4-1]) * A[k2] - (u[k4+2] - u[n-k4-3])*A[k2+1];
+ v[n-k4-3] = (u[k4] - u[n-k4-1]) * A[k2+1] + (u[k4+2] - u[n-k4-3])*A[k2];
+ }
+ // step 2
+ for (k=k4=0; k < n8; k+=1, k4+=4) {
+ w[n2+3+k4] = v[n2+3+k4] + v[k4+3];
+ w[n2+1+k4] = v[n2+1+k4] + v[k4+1];
+ w[k4+3] = (v[n2+3+k4] - v[k4+3])*A[n2-4-k4] - (v[n2+1+k4]-v[k4+1])*A[n2-3-k4];
+ w[k4+1] = (v[n2+1+k4] - v[k4+1])*A[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*A[n2-3-k4];
+ }
+ // step 3
+ ld = ilog(n) - 1; // ilog is off-by-one from normal definitions
+ for (l=0; l < ld-3; ++l) {
+ int k0 = n >> (l+2), k1 = 1 << (l+3);
+ int rlim = n >> (l+4), r4, r;
+ int s2lim = 1 << (l+2), s2;
+ for (r=r4=0; r < rlim; r4+=4,++r) {
+ for (s2=0; s2 < s2lim; s2+=2) {
+ u[n-1-k0*s2-r4] = w[n-1-k0*s2-r4] + w[n-1-k0*(s2+1)-r4];
+ u[n-3-k0*s2-r4] = w[n-3-k0*s2-r4] + w[n-3-k0*(s2+1)-r4];
+ u[n-1-k0*(s2+1)-r4] = (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1]
+ - (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1+1];
+ u[n-3-k0*(s2+1)-r4] = (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1]
+ + (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1+1];
+ }
+ }
+ if (l+1 < ld-3) {
+ // paper bug: ping-ponging of u&w here is omitted
+ memcpy(w, u, sizeof(u));
+ }
+ }
+
+ // step 4
+ for (i=0; i < n8; ++i) {
+ int j = bit_reverse(i) >> (32-ld+3);
+ assert(j < n8);
+ if (i == j) {
+ // paper bug: original code probably swapped in place; if copying,
+ // need to directly copy in this case
+ int i8 = i << 3;
+ v[i8+1] = u[i8+1];
+ v[i8+3] = u[i8+3];
+ v[i8+5] = u[i8+5];
+ v[i8+7] = u[i8+7];
+ } else if (i < j) {
+ int i8 = i << 3, j8 = j << 3;
+ v[j8+1] = u[i8+1], v[i8+1] = u[j8 + 1];
+ v[j8+3] = u[i8+3], v[i8+3] = u[j8 + 3];
+ v[j8+5] = u[i8+5], v[i8+5] = u[j8 + 5];
+ v[j8+7] = u[i8+7], v[i8+7] = u[j8 + 7];
+ }
+ }
+ // step 5
+ for (k=0; k < n2; ++k) {
+ w[k] = v[k*2+1];
+ }
+ // step 6
+ for (k=k2=k4=0; k < n8; ++k, k2 += 2, k4 += 4) {
+ u[n-1-k2] = w[k4];
+ u[n-2-k2] = w[k4+1];
+ u[n3_4 - 1 - k2] = w[k4+2];
+ u[n3_4 - 2 - k2] = w[k4+3];
+ }
+ // step 7
+ for (k=k2=0; k < n8; ++k, k2 += 2) {
+ v[n2 + k2 ] = ( u[n2 + k2] + u[n-2-k2] + C[k2+1]*(u[n2+k2]-u[n-2-k2]) + C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2;
+ v[n-2 - k2] = ( u[n2 + k2] + u[n-2-k2] - C[k2+1]*(u[n2+k2]-u[n-2-k2]) - C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2;
+ v[n2+1+ k2] = ( u[n2+1+k2] - u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2;
+ v[n-1 - k2] = (-u[n2+1+k2] + u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2;
+ }
+ // step 8
+ for (k=k2=0; k < n4; ++k,k2 += 2) {
+ X[k] = v[k2+n2]*B[k2 ] + v[k2+1+n2]*B[k2+1];
+ X[n2-1-k] = v[k2+n2]*B[k2+1] - v[k2+1+n2]*B[k2 ];
+ }
+
+ // decode kernel to output
+ // determined the following value experimentally
+ // (by first figuring out what made inverse_mdct_slow work); then matching that here
+ // (probably vorbis encoder premultiplies by n or n/2, to save it on the decoder?)
+ s = 0.5; // theoretically would be n4
+
+ // [[[ note! the s value of 0.5 is compensated for by the B[] in the current code,
+ // so it needs to use the "old" B values to behave correctly, or else
+ // set s to 1.0 ]]]
+ for (i=0; i < n4 ; ++i) buffer[i] = s * X[i+n4];
+ for ( ; i < n3_4; ++i) buffer[i] = -s * X[n3_4 - i - 1];
+ for ( ; i < n ; ++i) buffer[i] = -s * X[i - n3_4];
+}
+#endif
+
+static float *get_window(vorb *f, int len)
+{
+ len <<= 1;
+ if (len == f->blocksize_0) return f->window[0];
+ if (len == f->blocksize_1) return f->window[1];
+ assert(0);
+ return NULL;
+}
+
+#ifndef STB_VORBIS_NO_DEFER_FLOOR
+typedef int16 YTYPE;
+#else
+typedef int YTYPE;
+#endif
+static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *finalY, uint8 *step2_flag)
+{
+ int n2 = n >> 1;
+ int s = map->chan[i].mux, floor;
+ floor = map->submap_floor[s];
+ if (f->floor_types[floor] == 0) {
+ return error(f, VORBIS_invalid_stream);
+ } else {
+ Floor1 *g = &f->floor_config[floor].floor1;
+ int j,q;
+ int lx = 0, ly = finalY[0] * g->floor1_multiplier;
+ for (q=1; q < g->values; ++q) {
+ j = g->sorted_order[q];
+ #ifndef STB_VORBIS_NO_DEFER_FLOOR
+ if (finalY[j] >= 0)
+ #else
+ if (step2_flag[j])
+ #endif
+ {
+ int hy = finalY[j] * g->floor1_multiplier;
+ int hx = g->Xlist[j];
+ if (lx != hx)
+ draw_line(target, lx,ly, hx,hy, n2);
+ CHECK(f);
+ lx = hx, ly = hy;
+ }
+ }
+ if (lx < n2) {
+ // optimization of: draw_line(target, lx,ly, n,ly, n2);
+ for (j=lx; j < n2; ++j)
+ LINE_OP(target[j], inverse_db_table[ly]);
+ CHECK(f);
+ }
+ }
+ return TRUE;
+}
+
+// The meaning of "left" and "right"
+//
+// For a given frame:
+// we compute samples from 0..n
+// window_center is n/2
+// we'll window and mix the samples from left_start to left_end with data from the previous frame
+// all of the samples from left_end to right_start can be output without mixing; however,
+// this interval is 0-length except when transitioning between short and long frames
+// all of the samples from right_start to right_end need to be mixed with the next frame,
+// which we don't have, so those get saved in a buffer
+// frame N's right_end-right_start, the number of samples to mix with the next frame,
+// has to be the same as frame N+1's left_end-left_start (which they are by
+// construction)
+
+static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode)
+{
+ Mode *m;
+ int i, n, prev, next, window_center;
+ f->channel_buffer_start = f->channel_buffer_end = 0;
+
+ retry:
+ if (f->eof) return FALSE;
+ if (!maybe_start_packet(f))
+ return FALSE;
+ // check packet type
+ if (get_bits(f,1) != 0) {
+ if (IS_PUSH_MODE(f))
+ return error(f,VORBIS_bad_packet_type);
+ while (EOP != get8_packet(f));
+ goto retry;
+ }
+
+ if (f->alloc.alloc_buffer)
+ assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
+
+ i = get_bits(f, ilog(f->mode_count-1));
+ if (i == EOP) return FALSE;
+ if (i >= f->mode_count) return FALSE;
+ *mode = i;
+ m = f->mode_config + i;
+ if (m->blockflag) {
+ n = f->blocksize_1;
+ prev = get_bits(f,1);
+ next = get_bits(f,1);
+ } else {
+ prev = next = 0;
+ n = f->blocksize_0;
+ }
+
+// WINDOWING
+
+ window_center = n >> 1;
+ if (m->blockflag && !prev) {
+ *p_left_start = (n - f->blocksize_0) >> 2;
+ *p_left_end = (n + f->blocksize_0) >> 2;
+ } else {
+ *p_left_start = 0;
+ *p_left_end = window_center;
+ }
+ if (m->blockflag && !next) {
+ *p_right_start = (n*3 - f->blocksize_0) >> 2;
+ *p_right_end = (n*3 + f->blocksize_0) >> 2;
+ } else {
+ *p_right_start = window_center;
+ *p_right_end = n;
+ }
+
+ return TRUE;
+}
+
+static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, int left_end, int right_start, int right_end, int *p_left)
+{
+ Mapping *map;
+ int i,j,k,n,n2;
+ int zero_channel[256];
+ int really_zero_channel[256];
+
+// WINDOWING
+
+ n = f->blocksize[m->blockflag];
+ map = &f->mapping[m->mapping];
+
+// FLOORS
+ n2 = n >> 1;
+
+ CHECK(f);
+
+ for (i=0; i < f->channels; ++i) {
+ int s = map->chan[i].mux, floor;
+ zero_channel[i] = FALSE;
+ floor = map->submap_floor[s];
+ if (f->floor_types[floor] == 0) {
+ return error(f, VORBIS_invalid_stream);
+ } else {
+ Floor1 *g = &f->floor_config[floor].floor1;
+ if (get_bits(f, 1)) {
+ short *finalY;
+ uint8 step2_flag[256];
+ static int range_list[4] = { 256, 128, 86, 64 };
+ int range = range_list[g->floor1_multiplier-1];
+ int offset = 2;
+ finalY = f->finalY[i];
+ finalY[0] = get_bits(f, ilog(range)-1);
+ finalY[1] = get_bits(f, ilog(range)-1);
+ for (j=0; j < g->partitions; ++j) {
+ int pclass = g->partition_class_list[j];
+ int cdim = g->class_dimensions[pclass];
+ int cbits = g->class_subclasses[pclass];
+ int csub = (1 << cbits)-1;
+ int cval = 0;
+ if (cbits) {
+ Codebook *c = f->codebooks + g->class_masterbooks[pclass];
+ DECODE(cval,f,c);
+ }
+ for (k=0; k < cdim; ++k) {
+ int book = g->subclass_books[pclass][cval & csub];
+ cval = cval >> cbits;
+ if (book >= 0) {
+ int temp;
+ Codebook *c = f->codebooks + book;
+ DECODE(temp,f,c);
+ finalY[offset++] = temp;
+ } else
+ finalY[offset++] = 0;
+ }
+ }
+ if (f->valid_bits == INVALID_BITS) goto error; // behavior according to spec
+ step2_flag[0] = step2_flag[1] = 1;
+ for (j=2; j < g->values; ++j) {
+ int low, high, pred, highroom, lowroom, room, val;
+ low = g->neighbors[j][0];
+ high = g->neighbors[j][1];
+ //neighbors(g->Xlist, j, &low, &high);
+ pred = predict_point(g->Xlist[j], g->Xlist[low], g->Xlist[high], finalY[low], finalY[high]);
+ val = finalY[j];
+ highroom = range - pred;
+ lowroom = pred;
+ if (highroom < lowroom)
+ room = highroom * 2;
+ else
+ room = lowroom * 2;
+ if (val) {
+ step2_flag[low] = step2_flag[high] = 1;
+ step2_flag[j] = 1;
+ if (val >= room)
+ if (highroom > lowroom)
+ finalY[j] = val - lowroom + pred;
+ else
+ finalY[j] = pred - val + highroom - 1;
+ else
+ if (val & 1)
+ finalY[j] = pred - ((val+1)>>1);
+ else
+ finalY[j] = pred + (val>>1);
+ } else {
+ step2_flag[j] = 0;
+ finalY[j] = pred;
+ }
+ }
+
+#ifdef STB_VORBIS_NO_DEFER_FLOOR
+ do_floor(f, map, i, n, f->floor_buffers[i], finalY, step2_flag);
+#else
+ // defer final floor computation until _after_ residue
+ for (j=0; j < g->values; ++j) {
+ if (!step2_flag[j])
+ finalY[j] = -1;
+ }
+#endif
+ } else {
+ error:
+ zero_channel[i] = TRUE;
+ }
+ // So we just defer everything else to later
+
+ // at this point we've decoded the floor into buffer
+ }
+ }
+ CHECK(f);
+ // at this point we've decoded all floors
+
+ if (f->alloc.alloc_buffer)
+ assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
+
+ // re-enable coupled channels if necessary
+ memcpy(really_zero_channel, zero_channel, sizeof(really_zero_channel[0]) * f->channels);
+ for (i=0; i < map->coupling_steps; ++i)
+ if (!zero_channel[map->chan[i].magnitude] || !zero_channel[map->chan[i].angle]) {
+ zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE;
+ }
+
+ CHECK(f);
+// RESIDUE DECODE
+ for (i=0; i < map->submaps; ++i) {
+ float *residue_buffers[STB_VORBIS_MAX_CHANNELS];
+ int r;
+ uint8 do_not_decode[256];
+ int ch = 0;
+ for (j=0; j < f->channels; ++j) {
+ if (map->chan[j].mux == i) {
+ if (zero_channel[j]) {
+ do_not_decode[ch] = TRUE;
+ residue_buffers[ch] = NULL;
+ } else {
+ do_not_decode[ch] = FALSE;
+ residue_buffers[ch] = f->channel_buffers[j];
+ }
+ ++ch;
+ }
+ }
+ r = map->submap_residue[i];
+ decode_residue(f, residue_buffers, ch, n2, r, do_not_decode);
+ }
+
+ if (f->alloc.alloc_buffer)
+ assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
+ CHECK(f);
+
+// INVERSE COUPLING
+ for (i = map->coupling_steps-1; i >= 0; --i) {
+ int n2 = n >> 1;
+ float *m = f->channel_buffers[map->chan[i].magnitude];
+ float *a = f->channel_buffers[map->chan[i].angle ];
+ for (j=0; j < n2; ++j) {
+ float a2,m2;
+ if (m[j] > 0)
+ if (a[j] > 0)
+ m2 = m[j], a2 = m[j] - a[j];
+ else
+ a2 = m[j], m2 = m[j] + a[j];
+ else
+ if (a[j] > 0)
+ m2 = m[j], a2 = m[j] + a[j];
+ else
+ a2 = m[j], m2 = m[j] - a[j];
+ m[j] = m2;
+ a[j] = a2;
+ }
+ }
+ CHECK(f);
+
+ // finish decoding the floors
+#ifndef STB_VORBIS_NO_DEFER_FLOOR
+ for (i=0; i < f->channels; ++i) {
+ if (really_zero_channel[i]) {
+ memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2);
+ } else {
+ do_floor(f, map, i, n, f->channel_buffers[i], f->finalY[i], NULL);
+ }
+ }
+#else
+ for (i=0; i < f->channels; ++i) {
+ if (really_zero_channel[i]) {
+ memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2);
+ } else {
+ for (j=0; j < n2; ++j)
+ f->channel_buffers[i][j] *= f->floor_buffers[i][j];
+ }
+ }
+#endif
+
+// INVERSE MDCT
+ CHECK(f);
+ for (i=0; i < f->channels; ++i)
+ inverse_mdct(f->channel_buffers[i], n, f, m->blockflag);
+ CHECK(f);
+
+ // this shouldn't be necessary, unless we exited on an error
+ // and want to flush to get to the next packet
+ flush_packet(f);
+
+ if (f->first_decode) {
+ // assume we start so first non-discarded sample is sample 0
+ // this isn't to spec, but spec would require us to read ahead
+ // and decode the size of all current frames--could be done,
+ // but presumably it's not a commonly used feature
+ f->current_loc = -n2; // start of first frame is positioned for discard
+ // we might have to discard samples "from" the next frame too,
+ // if we're lapping a large block then a small at the start?
+ f->discard_samples_deferred = n - right_end;
+ f->current_loc_valid = TRUE;
+ f->first_decode = FALSE;
+ } else if (f->discard_samples_deferred) {
+ if (f->discard_samples_deferred >= right_start - left_start) {
+ f->discard_samples_deferred -= (right_start - left_start);
+ left_start = right_start;
+ *p_left = left_start;
+ } else {
+ left_start += f->discard_samples_deferred;
+ *p_left = left_start;
+ f->discard_samples_deferred = 0;
+ }
+ } else if (f->previous_length == 0 && f->current_loc_valid) {
+ // we're recovering from a seek... that means we're going to discard
+ // the samples from this packet even though we know our position from
+ // the last page header, so we need to update the position based on
+ // the discarded samples here
+ // but wait, the code below is going to add this in itself even
+ // on a discard, so we don't need to do it here...
+ }
+
+ // check if we have ogg information about the sample # for this packet
+ if (f->last_seg_which == f->end_seg_with_known_loc) {
+ // if we have a valid current loc, and this is final:
+ if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) {
+ uint32 current_end = f->known_loc_for_packet - (n-right_end);
+ // then let's infer the size of the (probably) short final frame
+ if (current_end < f->current_loc + (right_end-left_start)) {
+ if (current_end < f->current_loc) {
+ // negative truncation, that's impossible!
+ *len = 0;
+ } else {
+ *len = current_end - f->current_loc;
+ }
+ *len += left_start;
+ if (*len > right_end) *len = right_end; // this should never happen
+ f->current_loc += *len;
+ return TRUE;
+ }
+ }
+ // otherwise, just set our sample loc
+ // guess that the ogg granule pos refers to the _middle_ of the
+ // last frame?
+ // set f->current_loc to the position of left_start
+ f->current_loc = f->known_loc_for_packet - (n2-left_start);
+ f->current_loc_valid = TRUE;
+ }
+ if (f->current_loc_valid)
+ f->current_loc += (right_start - left_start);
+
+ if (f->alloc.alloc_buffer)
+ assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
+ *len = right_end; // ignore samples after the window goes to 0
+ CHECK(f);
+
+ return TRUE;
+}
+
+static int vorbis_decode_packet(vorb *f, int *len, int *p_left, int *p_right)
+{
+ int mode, left_end, right_end;
+ if (!vorbis_decode_initial(f, p_left, &left_end, p_right, &right_end, &mode)) return 0;
+ return vorbis_decode_packet_rest(f, len, f->mode_config + mode, *p_left, left_end, *p_right, right_end, p_left);
+}
+
+static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right)
+{
+ int prev,i,j;
+ // we use right&left (the start of the right- and left-window sin()-regions)
+ // to determine how much to return, rather than inferring from the rules
+ // (same result, clearer code); 'left' indicates where our sin() window
+ // starts, therefore where the previous window's right edge starts, and
+ // therefore where to start mixing from the previous buffer. 'right'
+ // indicates where our sin() ending-window starts, therefore that's where
+ // we start saving, and where our returned-data ends.
+
+ // mixin from previous window
+ if (f->previous_length) {
+ int i,j, n = f->previous_length;
+ float *w = get_window(f, n);
+ for (i=0; i < f->channels; ++i) {
+ for (j=0; j < n; ++j)
+ f->channel_buffers[i][left+j] =
+ f->channel_buffers[i][left+j]*w[ j] +
+ f->previous_window[i][ j]*w[n-1-j];
+ }
+ }
+
+ prev = f->previous_length;
+
+ // last half of this data becomes previous window
+ f->previous_length = len - right;
+
+ // @OPTIMIZE: could avoid this copy by double-buffering the
+ // output (flipping previous_window with channel_buffers), but
+ // then previous_window would have to be 2x as large, and
+ // channel_buffers couldn't be temp mem (although they're NOT
+ // currently temp mem, they could be (unless we want to level
+ // performance by spreading out the computation))
+ for (i=0; i < f->channels; ++i)
+ for (j=0; right+j < len; ++j)
+ f->previous_window[i][j] = f->channel_buffers[i][right+j];
+
+ if (!prev)
+ // there was no previous packet, so this data isn't valid...
+ // this isn't entirely true, only the would-have-overlapped data
+ // isn't valid, but this seems to be what the spec requires
+ return 0;
+
+ // truncate a short frame
+ if (len < right) right = len;
+
+ f->samples_output += right-left;
+
+ return right - left;
+}
+
+static void vorbis_pump_first_frame(stb_vorbis *f)
+{
+ int len, right, left;
+ if (vorbis_decode_packet(f, &len, &left, &right))
+ vorbis_finish_frame(f, len, left, right);
+}
+
+#ifndef STB_VORBIS_NO_PUSHDATA_API
+static int is_whole_packet_present(stb_vorbis *f, int end_page)
+{
+ // make sure that we have the packet available before continuing...
+ // this requires a full ogg parse, but we know we can fetch from f->stream
+
+ // instead of coding this out explicitly, we could save the current read state,
+ // read the next packet with get8() until end-of-packet, check f->eof, then
+ // reset the state? but that would be slower, esp. since we'd have over 256 bytes
+ // of state to restore (primarily the page segment table)
+
+ int s = f->next_seg, first = TRUE;
+ uint8 *p = f->stream;
+
+ if (s != -1) { // if we're not starting the packet with a 'continue on next page' flag
+ for (; s < f->segment_count; ++s) {
+ p += f->segments[s];
+ if (f->segments[s] < 255) // stop at first short segment
+ break;
+ }
+ // either this continues, or it ends it...
+ if (end_page)
+ if (s < f->segment_count-1) return error(f, VORBIS_invalid_stream);
+ if (s == f->segment_count)
+ s = -1; // set 'crosses page' flag
+ if (p > f->stream_end) return error(f, VORBIS_need_more_data);
+ first = FALSE;
+ }
+ for (; s == -1;) {
+ uint8 *q;
+ int n;
+
+ // check that we have the page header ready
+ if (p + 26 >= f->stream_end) return error(f, VORBIS_need_more_data);
+ // validate the page
+ if (memcmp(p, ogg_page_header, 4)) return error(f, VORBIS_invalid_stream);
+ if (p[4] != 0) return error(f, VORBIS_invalid_stream);
+ if (first) { // the first segment must NOT have 'continued_packet', later ones MUST
+ if (f->previous_length)
+ if ((p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream);
+ // if no previous length, we're resynching, so we can come in on a continued-packet,
+ // which we'll just drop
+ } else {
+ if (!(p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream);
+ }
+ n = p[26]; // segment counts
+ q = p+27; // q points to segment table
+ p = q + n; // advance past header
+ // make sure we've read the segment table
+ if (p > f->stream_end) return error(f, VORBIS_need_more_data);
+ for (s=0; s < n; ++s) {
+ p += q[s];
+ if (q[s] < 255)
+ break;
+ }
+ if (end_page)
+ if (s < n-1) return error(f, VORBIS_invalid_stream);
+ if (s == n)
+ s = -1; // set 'crosses page' flag
+ if (p > f->stream_end) return error(f, VORBIS_need_more_data);
+ first = FALSE;
+ }
+ return TRUE;
+}
+#endif // !STB_VORBIS_NO_PUSHDATA_API
+
+static int start_decoder(vorb *f)
+{
+ uint8 header[6], x,y;
+ int len,i,j,k, max_submaps = 0;
+ int longest_floorlist=0;
+
+ // first page, first packet
+
+ if (!start_page(f)) return FALSE;
+ // validate page flag
+ if (!(f->page_flag & PAGEFLAG_first_page)) return error(f, VORBIS_invalid_first_page);
+ if (f->page_flag & PAGEFLAG_last_page) return error(f, VORBIS_invalid_first_page);
+ if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page);
+ // check for expected packet length
+ if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page);
+ if (f->segments[0] != 30) return error(f, VORBIS_invalid_first_page);
+ // read packet
+ // check packet header
+ if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page);
+ if (!getn(f, header, 6)) return error(f, VORBIS_unexpected_eof);
+ if (!vorbis_validate(header)) return error(f, VORBIS_invalid_first_page);
+ // vorbis_version
+ if (get32(f) != 0) return error(f, VORBIS_invalid_first_page);
+ f->channels = get8(f); if (!f->channels) return error(f, VORBIS_invalid_first_page);
+ if (f->channels > STB_VORBIS_MAX_CHANNELS) return error(f, VORBIS_too_many_channels);
+ f->sample_rate = get32(f); if (!f->sample_rate) return error(f, VORBIS_invalid_first_page);
+ get32(f); // bitrate_maximum
+ get32(f); // bitrate_nominal
+ get32(f); // bitrate_minimum
+ x = get8(f);
+ {
+ int log0,log1;
+ log0 = x & 15;
+ log1 = x >> 4;
+ f->blocksize_0 = 1 << log0;
+ f->blocksize_1 = 1 << log1;
+ if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup);
+ if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup);
+ if (log0 > log1) return error(f, VORBIS_invalid_setup);
+ }
+
+ // framing_flag
+ x = get8(f);
+ if (!(x & 1)) return error(f, VORBIS_invalid_first_page);
+
+ // second packet!
+ if (!start_page(f)) return FALSE;
+
+ if (!start_packet(f)) return FALSE;
+ do {
+ len = next_segment(f);
+ skip(f, len);
+ f->bytes_in_seg = 0;
+ } while (len);
+
+ // third packet!
+ if (!start_packet(f)) return FALSE;
+
+ #ifndef STB_VORBIS_NO_PUSHDATA_API
+ if (IS_PUSH_MODE(f)) {
+ if (!is_whole_packet_present(f, TRUE)) {
+ // convert error in ogg header to write type
+ if (f->error == VORBIS_invalid_stream)
+ f->error = VORBIS_invalid_setup;
+ return FALSE;
+ }
+ }
+ #endif
+
+ crc32_init(); // always init it, to avoid multithread race conditions
+
+ if (get8_packet(f) != VORBIS_packet_setup) return error(f, VORBIS_invalid_setup);
+ for (i=0; i < 6; ++i) header[i] = get8_packet(f);
+ if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup);
+
+ // codebooks
+
+ f->codebook_count = get_bits(f,8) + 1;
+ f->codebooks = (Codebook *) setup_malloc(f, sizeof(*f->codebooks) * f->codebook_count);
+ if (f->codebooks == NULL) return error(f, VORBIS_outofmem);
+ memset(f->codebooks, 0, sizeof(*f->codebooks) * f->codebook_count);
+ for (i=0; i < f->codebook_count; ++i) {
+ uint32 *values;
+ int ordered, sorted_count;
+ int total=0;
+ uint8 *lengths;
+ Codebook *c = f->codebooks+i;
+ CHECK(f);
+ x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup);
+ x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup);
+ x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup);
+ x = get_bits(f, 8);
+ c->dimensions = (get_bits(f, 8)<<8) + x;
+ x = get_bits(f, 8);
+ y = get_bits(f, 8);
+ c->entries = (get_bits(f, 8)<<16) + (y<<8) + x;
+ ordered = get_bits(f,1);
+ c->sparse = ordered ? 0 : get_bits(f,1);
+
+ if (c->dimensions == 0 && c->entries != 0) return error(f, VORBIS_invalid_setup);
+
+ if (c->sparse)
+ lengths = (uint8 *) setup_temp_malloc(f, c->entries);
+ else
+ lengths = c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries);
+
+ if (!lengths) return error(f, VORBIS_outofmem);
+
+ if (ordered) {
+ int current_entry = 0;
+ int current_length = get_bits(f,5) + 1;
+ while (current_entry < c->entries) {
+ int limit = c->entries - current_entry;
+ int n = get_bits(f, ilog(limit));
+ if (current_entry + n > (int) c->entries) { return error(f, VORBIS_invalid_setup); }
+ memset(lengths + current_entry, current_length, n);
+ current_entry += n;
+ ++current_length;
+ }
+ } else {
+ for (j=0; j < c->entries; ++j) {
+ int present = c->sparse ? get_bits(f,1) : 1;
+ if (present) {
+ lengths[j] = get_bits(f, 5) + 1;
+ ++total;
+ if (lengths[j] == 32)
+ return error(f, VORBIS_invalid_setup);
+ } else {
+ lengths[j] = NO_CODE;
+ }
+ }
+ }
+
+ if (c->sparse && total >= c->entries >> 2) {
+ // convert sparse items to non-sparse!
+ if (c->entries > (int) f->setup_temp_memory_required)
+ f->setup_temp_memory_required = c->entries;
+
+ c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries);
+ if (c->codeword_lengths == NULL) return error(f, VORBIS_outofmem);
+ memcpy(c->codeword_lengths, lengths, c->entries);
+ setup_temp_free(f, lengths, c->entries); // note this is only safe if there have been no intervening temp mallocs!
+ lengths = c->codeword_lengths;
+ c->sparse = 0;
+ }
+
+ // compute the size of the sorted tables
+ if (c->sparse) {
+ sorted_count = total;
+ } else {
+ sorted_count = 0;
+ #ifndef STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH
+ for (j=0; j < c->entries; ++j)
+ if (lengths[j] > STB_VORBIS_FAST_HUFFMAN_LENGTH && lengths[j] != NO_CODE)
+ ++sorted_count;
+ #endif
+ }
+
+ c->sorted_entries = sorted_count;
+ values = NULL;
+
+ CHECK(f);
+ if (!c->sparse) {
+ c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries);
+ if (!c->codewords) return error(f, VORBIS_outofmem);
+ } else {
+ unsigned int size;
+ if (c->sorted_entries) {
+ c->codeword_lengths = (uint8 *) setup_malloc(f, c->sorted_entries);
+ if (!c->codeword_lengths) return error(f, VORBIS_outofmem);
+ c->codewords = (uint32 *) setup_temp_malloc(f, sizeof(*c->codewords) * c->sorted_entries);
+ if (!c->codewords) return error(f, VORBIS_outofmem);
+ values = (uint32 *) setup_temp_malloc(f, sizeof(*values) * c->sorted_entries);
+ if (!values) return error(f, VORBIS_outofmem);
+ }
+ size = c->entries + (sizeof(*c->codewords) + sizeof(*values)) * c->sorted_entries;
+ if (size > f->setup_temp_memory_required)
+ f->setup_temp_memory_required = size;
+ }
+
+ if (!compute_codewords(c, lengths, c->entries, values)) {
+ if (c->sparse) setup_temp_free(f, values, 0);
+ return error(f, VORBIS_invalid_setup);
+ }
+
+ if (c->sorted_entries) {
+ // allocate an extra slot for sentinels
+ c->sorted_codewords = (uint32 *) setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries+1));
+ if (c->sorted_codewords == NULL) return error(f, VORBIS_outofmem);
+ // allocate an extra slot at the front so that c->sorted_values[-1] is defined
+ // so that we can catch that case without an extra if
+ c->sorted_values = ( int *) setup_malloc(f, sizeof(*c->sorted_values ) * (c->sorted_entries+1));
+ if (c->sorted_values == NULL) return error(f, VORBIS_outofmem);
+ ++c->sorted_values;
+ c->sorted_values[-1] = -1;
+ compute_sorted_huffman(c, lengths, values);
+ }
+
+ if (c->sparse) {
+ setup_temp_free(f, values, sizeof(*values)*c->sorted_entries);
+ setup_temp_free(f, c->codewords, sizeof(*c->codewords)*c->sorted_entries);
+ setup_temp_free(f, lengths, c->entries);
+ c->codewords = NULL;
+ }
+
+ compute_accelerated_huffman(c);
+
+ CHECK(f);
+ c->lookup_type = get_bits(f, 4);
+ if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup);
+ if (c->lookup_type > 0) {
+ uint16 *mults;
+ c->minimum_value = float32_unpack(get_bits(f, 32));
+ c->delta_value = float32_unpack(get_bits(f, 32));
+ c->value_bits = get_bits(f, 4)+1;
+ c->sequence_p = get_bits(f,1);
+ if (c->lookup_type == 1) {
+ c->lookup_values = lookup1_values(c->entries, c->dimensions);
+ } else {
+ c->lookup_values = c->entries * c->dimensions;
+ }
+ if (c->lookup_values == 0) return error(f, VORBIS_invalid_setup);
+ mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values);
+ if (mults == NULL) return error(f, VORBIS_outofmem);
+ for (j=0; j < (int) c->lookup_values; ++j) {
+ int q = get_bits(f, c->value_bits);
+ if (q == EOP) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_invalid_setup); }
+ mults[j] = q;
+ }
+
+#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ if (c->lookup_type == 1) {
+ int len, sparse = c->sparse;
+ float last=0;
+ // pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop
+ if (sparse) {
+ if (c->sorted_entries == 0) goto skip;
+ c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->sorted_entries * c->dimensions);
+ } else
+ c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->entries * c->dimensions);
+ if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
+ len = sparse ? c->sorted_entries : c->entries;
+ for (j=0; j < len; ++j) {
+ unsigned int z = sparse ? c->sorted_values[j] : j;
+ unsigned int div=1;
+ for (k=0; k < c->dimensions; ++k) {
+ int off = (z / div) % c->lookup_values;
+ float val = mults[off];
+ val = mults[off]*c->delta_value + c->minimum_value + last;
+ c->multiplicands[j*c->dimensions + k] = val;
+ if (c->sequence_p)
+ last = val;
+ if (k+1 < c->dimensions) {
+ if (div > UINT_MAX / (unsigned int) c->lookup_values) {
+ setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
+ return error(f, VORBIS_invalid_setup);
+ }
+ div *= c->lookup_values;
+ }
+ }
+ }
+ c->lookup_type = 2;
+ }
+ else
+#endif
+ {
+ float last=0;
+ CHECK(f);
+ c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values);
+ if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
+ for (j=0; j < (int) c->lookup_values; ++j) {
+ float val = mults[j] * c->delta_value + c->minimum_value + last;
+ c->multiplicands[j] = val;
+ if (c->sequence_p)
+ last = val;
+ }
+ }
+#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ skip:;
+#endif
+ setup_temp_free(f, mults, sizeof(mults[0])*c->lookup_values);
+
+ CHECK(f);
+ }
+ CHECK(f);
+ }
+
+ // time domain transfers (notused)
+
+ x = get_bits(f, 6) + 1;
+ for (i=0; i < x; ++i) {
+ uint32 z = get_bits(f, 16);
+ if (z != 0) return error(f, VORBIS_invalid_setup);
+ }
+
+ // Floors
+ f->floor_count = get_bits(f, 6)+1;
+ f->floor_config = (Floor *) setup_malloc(f, f->floor_count * sizeof(*f->floor_config));
+ if (f->floor_config == NULL) return error(f, VORBIS_outofmem);
+ for (i=0; i < f->floor_count; ++i) {
+ f->floor_types[i] = get_bits(f, 16);
+ if (f->floor_types[i] > 1) return error(f, VORBIS_invalid_setup);
+ if (f->floor_types[i] == 0) {
+ Floor0 *g = &f->floor_config[i].floor0;
+ g->order = get_bits(f,8);
+ g->rate = get_bits(f,16);
+ g->bark_map_size = get_bits(f,16);
+ g->amplitude_bits = get_bits(f,6);
+ g->amplitude_offset = get_bits(f,8);
+ g->number_of_books = get_bits(f,4) + 1;
+ for (j=0; j < g->number_of_books; ++j)
+ g->book_list[j] = get_bits(f,8);
+ return error(f, VORBIS_feature_not_supported);
+ } else {
+ Point p[31*8+2];
+ Floor1 *g = &f->floor_config[i].floor1;
+ int max_class = -1;
+ g->partitions = get_bits(f, 5);
+ for (j=0; j < g->partitions; ++j) {
+ g->partition_class_list[j] = get_bits(f, 4);
+ if (g->partition_class_list[j] > max_class)
+ max_class = g->partition_class_list[j];
+ }
+ for (j=0; j <= max_class; ++j) {
+ g->class_dimensions[j] = get_bits(f, 3)+1;
+ g->class_subclasses[j] = get_bits(f, 2);
+ if (g->class_subclasses[j]) {
+ g->class_masterbooks[j] = get_bits(f, 8);
+ if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
+ }
+ for (k=0; k < 1 << g->class_subclasses[j]; ++k) {
+ g->subclass_books[j][k] = get_bits(f,8)-1;
+ if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
+ }
+ }
+ g->floor1_multiplier = get_bits(f,2)+1;
+ g->rangebits = get_bits(f,4);
+ g->Xlist[0] = 0;
+ g->Xlist[1] = 1 << g->rangebits;
+ g->values = 2;
+ for (j=0; j < g->partitions; ++j) {
+ int c = g->partition_class_list[j];
+ for (k=0; k < g->class_dimensions[c]; ++k) {
+ g->Xlist[g->values] = get_bits(f, g->rangebits);
+ ++g->values;
+ }
+ }
+ // precompute the sorting
+ for (j=0; j < g->values; ++j) {
+ p[j].x = g->Xlist[j];
+ p[j].y = j;
+ }
+ qsort(p, g->values, sizeof(p[0]), point_compare);
+ for (j=0; j < g->values; ++j)
+ g->sorted_order[j] = (uint8) p[j].y;
+ // precompute the neighbors
+ for (j=2; j < g->values; ++j) {
+ int low,hi;
+ neighbors(g->Xlist, j, &low,&hi);
+ g->neighbors[j][0] = low;
+ g->neighbors[j][1] = hi;
+ }
+
+ if (g->values > longest_floorlist)
+ longest_floorlist = g->values;
+ }
+ }
+
+ // Residue
+ f->residue_count = get_bits(f, 6)+1;
+ f->residue_config = (Residue *) setup_malloc(f, f->residue_count * sizeof(f->residue_config[0]));
+ if (f->residue_config == NULL) return error(f, VORBIS_outofmem);
+ memset(f->residue_config, 0, f->residue_count * sizeof(f->residue_config[0]));
+ for (i=0; i < f->residue_count; ++i) {
+ uint8 residue_cascade[64];
+ Residue *r = f->residue_config+i;
+ f->residue_types[i] = get_bits(f, 16);
+ if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup);
+ r->begin = get_bits(f, 24);
+ r->end = get_bits(f, 24);
+ if (r->end < r->begin) return error(f, VORBIS_invalid_setup);
+ r->part_size = get_bits(f,24)+1;
+ r->classifications = get_bits(f,6)+1;
+ r->classbook = get_bits(f,8);
+ if (r->classbook >= f->codebook_count) return error(f, VORBIS_invalid_setup);
+ for (j=0; j < r->classifications; ++j) {
+ uint8 high_bits=0;
+ uint8 low_bits=get_bits(f,3);
+ if (get_bits(f,1))
+ high_bits = get_bits(f,5);
+ residue_cascade[j] = high_bits*8 + low_bits;
+ }
+ r->residue_books = (short (*)[8]) setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications);
+ if (r->residue_books == NULL) return error(f, VORBIS_outofmem);
+ for (j=0; j < r->classifications; ++j) {
+ for (k=0; k < 8; ++k) {
+ if (residue_cascade[j] & (1 << k)) {
+ r->residue_books[j][k] = get_bits(f, 8);
+ if (r->residue_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
+ } else {
+ r->residue_books[j][k] = -1;
+ }
+ }
+ }
+ // precompute the classifications[] array to avoid inner-loop mod/divide
+ // call it 'classdata' since we already have r->classifications
+ r->classdata = (uint8 **) setup_malloc(f, sizeof(*r->classdata) * f->codebooks[r->classbook].entries);
+ if (!r->classdata) return error(f, VORBIS_outofmem);
+ memset(r->classdata, 0, sizeof(*r->classdata) * f->codebooks[r->classbook].entries);
+ for (j=0; j < f->codebooks[r->classbook].entries; ++j) {
+ int classwords = f->codebooks[r->classbook].dimensions;
+ int temp = j;
+ r->classdata[j] = (uint8 *) setup_malloc(f, sizeof(r->classdata[j][0]) * classwords);
+ if (r->classdata[j] == NULL) return error(f, VORBIS_outofmem);
+ for (k=classwords-1; k >= 0; --k) {
+ r->classdata[j][k] = temp % r->classifications;
+ temp /= r->classifications;
+ }
+ }
+ }
+
+ f->mapping_count = get_bits(f,6)+1;
+ f->mapping = (Mapping *) setup_malloc(f, f->mapping_count * sizeof(*f->mapping));
+ if (f->mapping == NULL) return error(f, VORBIS_outofmem);
+ memset(f->mapping, 0, f->mapping_count * sizeof(*f->mapping));
+ for (i=0; i < f->mapping_count; ++i) {
+ Mapping *m = f->mapping + i;
+ int mapping_type = get_bits(f,16);
+ if (mapping_type != 0) return error(f, VORBIS_invalid_setup);
+ m->chan = (MappingChannel *) setup_malloc(f, f->channels * sizeof(*m->chan));
+ if (m->chan == NULL) return error(f, VORBIS_outofmem);
+ if (get_bits(f,1))
+ m->submaps = get_bits(f,4)+1;
+ else
+ m->submaps = 1;
+ if (m->submaps > max_submaps)
+ max_submaps = m->submaps;
+ if (get_bits(f,1)) {
+ m->coupling_steps = get_bits(f,8)+1;
+ for (k=0; k < m->coupling_steps; ++k) {
+ m->chan[k].magnitude = get_bits(f, ilog(f->channels-1));
+ m->chan[k].angle = get_bits(f, ilog(f->channels-1));
+ if (m->chan[k].magnitude >= f->channels) return error(f, VORBIS_invalid_setup);
+ if (m->chan[k].angle >= f->channels) return error(f, VORBIS_invalid_setup);
+ if (m->chan[k].magnitude == m->chan[k].angle) return error(f, VORBIS_invalid_setup);
+ }
+ } else
+ m->coupling_steps = 0;
+
+ // reserved field
+ if (get_bits(f,2)) return error(f, VORBIS_invalid_setup);
+ if (m->submaps > 1) {
+ for (j=0; j < f->channels; ++j) {
+ m->chan[j].mux = get_bits(f, 4);
+ if (m->chan[j].mux >= m->submaps) return error(f, VORBIS_invalid_setup);
+ }
+ } else
+ // @SPECIFICATION: this case is missing from the spec
+ for (j=0; j < f->channels; ++j)
+ m->chan[j].mux = 0;
+
+ for (j=0; j < m->submaps; ++j) {
+ get_bits(f,8); // discard
+ m->submap_floor[j] = get_bits(f,8);
+ m->submap_residue[j] = get_bits(f,8);
+ if (m->submap_floor[j] >= f->floor_count) return error(f, VORBIS_invalid_setup);
+ if (m->submap_residue[j] >= f->residue_count) return error(f, VORBIS_invalid_setup);
+ }
+ }
+
+ // Modes
+ f->mode_count = get_bits(f, 6)+1;
+ for (i=0; i < f->mode_count; ++i) {
+ Mode *m = f->mode_config+i;
+ m->blockflag = get_bits(f,1);
+ m->windowtype = get_bits(f,16);
+ m->transformtype = get_bits(f,16);
+ m->mapping = get_bits(f,8);
+ if (m->windowtype != 0) return error(f, VORBIS_invalid_setup);
+ if (m->transformtype != 0) return error(f, VORBIS_invalid_setup);
+ if (m->mapping >= f->mapping_count) return error(f, VORBIS_invalid_setup);
+ }
+
+ flush_packet(f);
+
+ f->previous_length = 0;
+
+ for (i=0; i < f->channels; ++i) {
+ f->channel_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1);
+ f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
+ f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist);
+ if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem);
+ #ifdef STB_VORBIS_NO_DEFER_FLOOR
+ f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
+ if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem);
+ #endif
+ }
+
+ if (!init_blocksize(f, 0, f->blocksize_0)) return FALSE;
+ if (!init_blocksize(f, 1, f->blocksize_1)) return FALSE;
+ f->blocksize[0] = f->blocksize_0;
+ f->blocksize[1] = f->blocksize_1;
+
+#ifdef STB_VORBIS_DIVIDE_TABLE
+ if (integer_divide_table[1][1]==0)
+ for (i=0; i < DIVTAB_NUMER; ++i)
+ for (j=1; j < DIVTAB_DENOM; ++j)
+ integer_divide_table[i][j] = i / j;
+#endif
+
+ // compute how much temporary memory is needed
+
+ // 1.
+ {
+ uint32 imdct_mem = (f->blocksize_1 * sizeof(float) >> 1);
+ uint32 classify_mem;
+ int i,max_part_read=0;
+ for (i=0; i < f->residue_count; ++i) {
+ Residue *r = f->residue_config + i;
+ int n_read = r->end - r->begin;
+ int part_read = n_read / r->part_size;
+ if (part_read > max_part_read)
+ max_part_read = part_read;
+ }
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(uint8 *));
+ #else
+ classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *));
+ #endif
+
+ f->temp_memory_required = classify_mem;
+ if (imdct_mem > f->temp_memory_required)
+ f->temp_memory_required = imdct_mem;
+ }
+
+ f->first_decode = TRUE;
+
+ if (f->alloc.alloc_buffer) {
+ assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes);
+ // check if there's enough temp memory so we don't error later
+ if (f->setup_offset + sizeof(*f) + f->temp_memory_required > (unsigned) f->temp_offset)
+ return error(f, VORBIS_outofmem);
+ }
+
+ f->first_audio_page_offset = stb_vorbis_get_file_offset(f);
+
+ return TRUE;
+}
+
+static void vorbis_deinit(stb_vorbis *p)
+{
+ int i,j;
+ if (p->residue_config) {
+ for (i=0; i < p->residue_count; ++i) {
+ Residue *r = p->residue_config+i;
+ if (r->classdata) {
+ for (j=0; j < p->codebooks[r->classbook].entries; ++j)
+ setup_free(p, r->classdata[j]);
+ setup_free(p, r->classdata);
+ }
+ setup_free(p, r->residue_books);
+ }
+ }
+
+ if (p->codebooks) {
+ CHECK(p);
+ for (i=0; i < p->codebook_count; ++i) {
+ Codebook *c = p->codebooks + i;
+ setup_free(p, c->codeword_lengths);
+ setup_free(p, c->multiplicands);
+ setup_free(p, c->codewords);
+ setup_free(p, c->sorted_codewords);
+ // c->sorted_values[-1] is the first entry in the array
+ setup_free(p, c->sorted_values ? c->sorted_values-1 : NULL);
+ }
+ setup_free(p, p->codebooks);
+ }
+ setup_free(p, p->floor_config);
+ setup_free(p, p->residue_config);
+ if (p->mapping) {
+ for (i=0; i < p->mapping_count; ++i)
+ setup_free(p, p->mapping[i].chan);
+ setup_free(p, p->mapping);
+ }
+ CHECK(p);
+ for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) {
+ setup_free(p, p->channel_buffers[i]);
+ setup_free(p, p->previous_window[i]);
+ #ifdef STB_VORBIS_NO_DEFER_FLOOR
+ setup_free(p, p->floor_buffers[i]);
+ #endif
+ setup_free(p, p->finalY[i]);
+ }
+ for (i=0; i < 2; ++i) {
+ setup_free(p, p->A[i]);
+ setup_free(p, p->B[i]);
+ setup_free(p, p->C[i]);
+ setup_free(p, p->window[i]);
+ setup_free(p, p->bit_reverse[i]);
+ }
+ #ifndef STB_VORBIS_NO_STDIO
+ if (p->close_on_free) fclose(p->f);
+ #endif
+}
+
+void stb_vorbis_close(stb_vorbis *p)
+{
+ if (p == NULL) return;
+ vorbis_deinit(p);
+ setup_free(p,p);
+}
+
+static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z)
+{
+ memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start
+ if (z) {
+ p->alloc = *z;
+ p->alloc.alloc_buffer_length_in_bytes = (p->alloc.alloc_buffer_length_in_bytes+3) & ~3;
+ p->temp_offset = p->alloc.alloc_buffer_length_in_bytes;
+ }
+ p->eof = 0;
+ p->error = VORBIS__no_error;
+ p->stream = NULL;
+ p->codebooks = NULL;
+ p->page_crc_tests = -1;
+ #ifndef STB_VORBIS_NO_STDIO
+ p->close_on_free = FALSE;
+ p->f = NULL;
+ #endif
+}
+
+int stb_vorbis_get_sample_offset(stb_vorbis *f)
+{
+ if (f->current_loc_valid)
+ return f->current_loc;
+ else
+ return -1;
+}
+
+stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f)
+{
+ stb_vorbis_info d;
+ d.channels = f->channels;
+ d.sample_rate = f->sample_rate;
+ d.setup_memory_required = f->setup_memory_required;
+ d.setup_temp_memory_required = f->setup_temp_memory_required;
+ d.temp_memory_required = f->temp_memory_required;
+ d.max_frame_size = f->blocksize_1 >> 1;
+ return d;
+}
+
+int stb_vorbis_get_error(stb_vorbis *f)
+{
+ int e = f->error;
+ f->error = VORBIS__no_error;
+ return e;
+}
+
+static stb_vorbis * vorbis_alloc(stb_vorbis *f)
+{
+ stb_vorbis *p = (stb_vorbis *) setup_malloc(f, sizeof(*p));
+ return p;
+}
+
+#ifndef STB_VORBIS_NO_PUSHDATA_API
+
+void stb_vorbis_flush_pushdata(stb_vorbis *f)
+{
+ f->previous_length = 0;
+ f->page_crc_tests = 0;
+ f->discard_samples_deferred = 0;
+ f->current_loc_valid = FALSE;
+ f->first_decode = FALSE;
+ f->samples_output = 0;
+ f->channel_buffer_start = 0;
+ f->channel_buffer_end = 0;
+}
+
+static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len)
+{
+ int i,n;
+ for (i=0; i < f->page_crc_tests; ++i)
+ f->scan[i].bytes_done = 0;
+
+ // if we have room for more scans, search for them first, because
+ // they may cause us to stop early if their header is incomplete
+ if (f->page_crc_tests < STB_VORBIS_PUSHDATA_CRC_COUNT) {
+ if (data_len < 4) return 0;
+ data_len -= 3; // need to look for 4-byte sequence, so don't miss
+ // one that straddles a boundary
+ for (i=0; i < data_len; ++i) {
+ if (data[i] == 0x4f) {
+ if (0==memcmp(data+i, ogg_page_header, 4)) {
+ int j,len;
+ uint32 crc;
+ // make sure we have the whole page header
+ if (i+26 >= data_len || i+27+data[i+26] >= data_len) {
+ // only read up to this page start, so hopefully we'll
+ // have the whole page header start next time
+ data_len = i;
+ break;
+ }
+ // ok, we have it all; compute the length of the page
+ len = 27 + data[i+26];
+ for (j=0; j < data[i+26]; ++j)
+ len += data[i+27+j];
+ // scan everything up to the embedded crc (which we must 0)
+ crc = 0;
+ for (j=0; j < 22; ++j)
+ crc = crc32_update(crc, data[i+j]);
+ // now process 4 0-bytes
+ for ( ; j < 26; ++j)
+ crc = crc32_update(crc, 0);
+ // len is the total number of bytes we need to scan
+ n = f->page_crc_tests++;
+ f->scan[n].bytes_left = len-j;
+ f->scan[n].crc_so_far = crc;
+ f->scan[n].goal_crc = data[i+22] + (data[i+23] << 8) + (data[i+24]<<16) + (data[i+25]<<24);
+ // if the last frame on a page is continued to the next, then
+ // we can't recover the sample_loc immediately
+ if (data[i+27+data[i+26]-1] == 255)
+ f->scan[n].sample_loc = ~0;
+ else
+ f->scan[n].sample_loc = data[i+6] + (data[i+7] << 8) + (data[i+ 8]<<16) + (data[i+ 9]<<24);
+ f->scan[n].bytes_done = i+j;
+ if (f->page_crc_tests == STB_VORBIS_PUSHDATA_CRC_COUNT)
+ break;
+ // keep going if we still have room for more
+ }
+ }
+ }
+ }
+
+ for (i=0; i < f->page_crc_tests;) {
+ uint32 crc;
+ int j;
+ int n = f->scan[i].bytes_done;
+ int m = f->scan[i].bytes_left;
+ if (m > data_len - n) m = data_len - n;
+ // m is the bytes to scan in the current chunk
+ crc = f->scan[i].crc_so_far;
+ for (j=0; j < m; ++j)
+ crc = crc32_update(crc, data[n+j]);
+ f->scan[i].bytes_left -= m;
+ f->scan[i].crc_so_far = crc;
+ if (f->scan[i].bytes_left == 0) {
+ // does it match?
+ if (f->scan[i].crc_so_far == f->scan[i].goal_crc) {
+ // Houston, we have page
+ data_len = n+m; // consumption amount is wherever that scan ended
+ f->page_crc_tests = -1; // drop out of page scan mode
+ f->previous_length = 0; // decode-but-don't-output one frame
+ f->next_seg = -1; // start a new page
+ f->current_loc = f->scan[i].sample_loc; // set the current sample location
+ // to the amount we'd have decoded had we decoded this page
+ f->current_loc_valid = f->current_loc != ~0U;
+ return data_len;
+ }
+ // delete entry
+ f->scan[i] = f->scan[--f->page_crc_tests];
+ } else {
+ ++i;
+ }
+ }
+
+ return data_len;
+}
+
+// return value: number of bytes we used
+int stb_vorbis_decode_frame_pushdata(
+ stb_vorbis *f, // the file we're decoding
+ const uint8 *data, int data_len, // the memory available for decoding
+ int *channels, // place to write number of float * buffers
+ float ***output, // place to write float ** array of float * buffers
+ int *samples // place to write number of output samples
+ )
+{
+ int i;
+ int len,right,left;
+
+ if (!IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
+
+ if (f->page_crc_tests >= 0) {
+ *samples = 0;
+ return vorbis_search_for_page_pushdata(f, (uint8 *) data, data_len);
+ }
+
+ f->stream = (uint8 *) data;
+ f->stream_end = (uint8 *) data + data_len;
+ f->error = VORBIS__no_error;
+
+ // check that we have the entire packet in memory
+ if (!is_whole_packet_present(f, FALSE)) {
+ *samples = 0;
+ return 0;
+ }
+
+ if (!vorbis_decode_packet(f, &len, &left, &right)) {
+ // save the actual error we encountered
+ enum STBVorbisError error = f->error;
+ if (error == VORBIS_bad_packet_type) {
+ // flush and resynch
+ f->error = VORBIS__no_error;
+ while (get8_packet(f) != EOP)
+ if (f->eof) break;
+ *samples = 0;
+ return (int) (f->stream - data);
+ }
+ if (error == VORBIS_continued_packet_flag_invalid) {
+ if (f->previous_length == 0) {
+ // we may be resynching, in which case it's ok to hit one
+ // of these; just discard the packet
+ f->error = VORBIS__no_error;
+ while (get8_packet(f) != EOP)
+ if (f->eof) break;
+ *samples = 0;
+ return (int) (f->stream - data);
+ }
+ }
+ // if we get an error while parsing, what to do?
+ // well, it DEFINITELY won't work to continue from where we are!
+ stb_vorbis_flush_pushdata(f);
+ // restore the error that actually made us bail
+ f->error = error;
+ *samples = 0;
+ return 1;
+ }
+
+ // success!
+ len = vorbis_finish_frame(f, len, left, right);
+ for (i=0; i < f->channels; ++i)
+ f->outputs[i] = f->channel_buffers[i] + left;
+
+ if (channels) *channels = f->channels;
+ *samples = len;
+ *output = f->outputs;
+ return (int) (f->stream - data);
+}
+
+stb_vorbis *stb_vorbis_open_pushdata(
+ const unsigned char *data, int data_len, // the memory available for decoding
+ int *data_used, // only defined if result is not NULL
+ int *error, const stb_vorbis_alloc *alloc)
+{
+ stb_vorbis *f, p;
+ vorbis_init(&p, alloc);
+ p.stream = (uint8 *) data;
+ p.stream_end = (uint8 *) data + data_len;
+ p.push_mode = TRUE;
+ if (!start_decoder(&p)) {
+ if (p.eof)
+ *error = VORBIS_need_more_data;
+ else
+ *error = p.error;
+ return NULL;
+ }
+ f = vorbis_alloc(&p);
+ if (f) {
+ *f = p;
+ *data_used = (int) (f->stream - data);
+ *error = 0;
+ return f;
+ } else {
+ vorbis_deinit(&p);
+ return NULL;
+ }
+}
+#endif // STB_VORBIS_NO_PUSHDATA_API
+
+unsigned int stb_vorbis_get_file_offset(stb_vorbis *f)
+{
+ #ifndef STB_VORBIS_NO_PUSHDATA_API
+ if (f->push_mode) return 0;
+ #endif
+ if (USE_MEMORY(f)) return (unsigned int) (f->stream - f->stream_start);
+ #ifndef STB_VORBIS_NO_STDIO
+ return (unsigned int) (ftell(f->f) - f->f_start);
+ #endif
+}
+
+#ifndef STB_VORBIS_NO_PULLDATA_API
+//
+// DATA-PULLING API
+//
+
+static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last)
+{
+ for(;;) {
+ int n;
+ if (f->eof) return 0;
+ n = get8(f);
+ if (n == 0x4f) { // page header candidate
+ unsigned int retry_loc = stb_vorbis_get_file_offset(f);
+ int i;
+ // check if we're off the end of a file_section stream
+ if (retry_loc - 25 > f->stream_len)
+ return 0;
+ // check the rest of the header
+ for (i=1; i < 4; ++i)
+ if (get8(f) != ogg_page_header[i])
+ break;
+ if (f->eof) return 0;
+ if (i == 4) {
+ uint8 header[27];
+ uint32 i, crc, goal, len;
+ for (i=0; i < 4; ++i)
+ header[i] = ogg_page_header[i];
+ for (; i < 27; ++i)
+ header[i] = get8(f);
+ if (f->eof) return 0;
+ if (header[4] != 0) goto invalid;
+ goal = header[22] + (header[23] << 8) + (header[24]<<16) + (header[25]<<24);
+ for (i=22; i < 26; ++i)
+ header[i] = 0;
+ crc = 0;
+ for (i=0; i < 27; ++i)
+ crc = crc32_update(crc, header[i]);
+ len = 0;
+ for (i=0; i < header[26]; ++i) {
+ int s = get8(f);
+ crc = crc32_update(crc, s);
+ len += s;
+ }
+ if (len && f->eof) return 0;
+ for (i=0; i < len; ++i)
+ crc = crc32_update(crc, get8(f));
+ // finished parsing probable page
+ if (crc == goal) {
+ // we could now check that it's either got the last
+ // page flag set, OR it's followed by the capture
+ // pattern, but I guess TECHNICALLY you could have
+ // a file with garbage between each ogg page and recover
+ // from it automatically? So even though that paranoia
+ // might decrease the chance of an invalid decode by
+ // another 2^32, not worth it since it would hose those
+ // invalid-but-useful files?
+ if (end)
+ *end = stb_vorbis_get_file_offset(f);
+ if (last) {
+ if (header[5] & 0x04)
+ *last = 1;
+ else
+ *last = 0;
+ }
+ set_file_offset(f, retry_loc-1);
+ return 1;
+ }
+ }
+ invalid:
+ // not a valid page, so rewind and look for next one
+ set_file_offset(f, retry_loc);
+ }
+ }
+}
+
+
+#define SAMPLE_unknown 0xffffffff
+
+// seeking is implemented with a binary search, which narrows down the range to
+// 64K, before using a linear search (because finding the synchronization
+// pattern can be expensive, and the chance we'd find the end page again is
+// relatively high for small ranges)
+//
+// two initial interpolation-style probes are used at the start of the search
+// to try to bound either side of the binary search sensibly, while still
+// working in O(log n) time if they fail.
+
+static int get_seek_page_info(stb_vorbis *f, ProbedPage *z)
+{
+ uint8 header[27], lacing[255];
+ int i,len;
+
+ // record where the page starts
+ z->page_start = stb_vorbis_get_file_offset(f);
+
+ // parse the header
+ getn(f, header, 27);
+ if (header[0] != 'O' || header[1] != 'g' || header[2] != 'g' || header[3] != 'S')
+ return 0;
+ getn(f, lacing, header[26]);
+
+ // determine the length of the payload
+ len = 0;
+ for (i=0; i < header[26]; ++i)
+ len += lacing[i];
+
+ // this implies where the page ends
+ z->page_end = z->page_start + 27 + header[26] + len;
+
+ // read the last-decoded sample out of the data
+ z->last_decoded_sample = header[6] + (header[7] << 8) + (header[8] << 16) + (header[9] << 24);
+
+ // restore file state to where we were
+ set_file_offset(f, z->page_start);
+ return 1;
+}
+
+// rarely used function to seek back to the preceeding page while finding the
+// start of a packet
+static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset)
+{
+ unsigned int previous_safe, end;
+
+ // now we want to seek back 64K from the limit
+ if (limit_offset >= 65536 && limit_offset-65536 >= f->first_audio_page_offset)
+ previous_safe = limit_offset - 65536;
+ else
+ previous_safe = f->first_audio_page_offset;
+
+ set_file_offset(f, previous_safe);
+
+ while (vorbis_find_page(f, &end, NULL)) {
+ if (end >= limit_offset && stb_vorbis_get_file_offset(f) < limit_offset)
+ return 1;
+ set_file_offset(f, end);
+ }
+
+ return 0;
+}
+
+// implements the search logic for finding a page and starting decoding. if
+// the function succeeds, current_loc_valid will be true and current_loc will
+// be less than or equal to the provided sample number (the closer the
+// better).
+static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
+{
+ ProbedPage left, right, mid;
+ int i, start_seg_with_known_loc, end_pos, page_start;
+ uint32 delta, stream_length, padding;
+ double offset, bytes_per_sample;
+ int probe = 0;
+
+ // find the last page and validate the target sample
+ stream_length = stb_vorbis_stream_length_in_samples(f);
+ if (stream_length == 0) return error(f, VORBIS_seek_without_length);
+ if (sample_number > stream_length) return error(f, VORBIS_seek_invalid);
+
+ // this is the maximum difference between the window-center (which is the
+ // actual granule position value), and the right-start (which the spec
+ // indicates should be the granule position (give or take one)).
+ padding = ((f->blocksize_1 - f->blocksize_0) >> 2);
+ if (sample_number < padding)
+ sample_number = 0;
+ else
+ sample_number -= padding;
+
+ left = f->p_first;
+ while (left.last_decoded_sample == ~0U) {
+ // (untested) the first page does not have a 'last_decoded_sample'
+ set_file_offset(f, left.page_end);
+ if (!get_seek_page_info(f, &left)) goto error;
+ }
+
+ right = f->p_last;
+ assert(right.last_decoded_sample != ~0U);
+
+ // starting from the start is handled differently
+ if (sample_number <= left.last_decoded_sample) {
+ stb_vorbis_seek_start(f);
+ return 1;
+ }
+
+ while (left.page_end != right.page_start) {
+ assert(left.page_end < right.page_start);
+ // search range in bytes
+ delta = right.page_start - left.page_end;
+ if (delta <= 65536) {
+ // there's only 64K left to search - handle it linearly
+ set_file_offset(f, left.page_end);
+ } else {
+ if (probe < 2) {
+ if (probe == 0) {
+ // first probe (interpolate)
+ double data_bytes = right.page_end - left.page_start;
+ bytes_per_sample = data_bytes / right.last_decoded_sample;
+ offset = left.page_start + bytes_per_sample * (sample_number - left.last_decoded_sample);
+ } else {
+ // second probe (try to bound the other side)
+ double error = ((double) sample_number - mid.last_decoded_sample) * bytes_per_sample;
+ if (error >= 0 && error < 8000) error = 8000;
+ if (error < 0 && error > -8000) error = -8000;
+ offset += error * 2;
+ }
+
+ // ensure the offset is valid
+ if (offset < left.page_end)
+ offset = left.page_end;
+ if (offset > right.page_start - 65536)
+ offset = right.page_start - 65536;
+
+ set_file_offset(f, (unsigned int) offset);
+ } else {
+ // binary search for large ranges (offset by 32K to ensure
+ // we don't hit the right page)
+ set_file_offset(f, left.page_end + (delta / 2) - 32768);
+ }
+
+ if (!vorbis_find_page(f, NULL, NULL)) goto error;
+ }
+
+ for (;;) {
+ if (!get_seek_page_info(f, &mid)) goto error;
+ if (mid.last_decoded_sample != ~0U) break;
+ // (untested) no frames end on this page
+ set_file_offset(f, mid.page_end);
+ assert(mid.page_start < right.page_start);
+ }
+
+ // if we've just found the last page again then we're in a tricky file,
+ // and we're close enough.
+ if (mid.page_start == right.page_start)
+ break;
+
+ if (sample_number < mid.last_decoded_sample)
+ right = mid;
+ else
+ left = mid;
+
+ ++probe;
+ }
+
+ // seek back to start of the last packet
+ page_start = left.page_start;
+ set_file_offset(f, page_start);
+ if (!start_page(f)) return error(f, VORBIS_seek_failed);
+ end_pos = f->end_seg_with_known_loc;
+ assert(end_pos >= 0);
+
+ for (;;) {
+ for (i = end_pos; i > 0; --i)
+ if (f->segments[i-1] != 255)
+ break;
+
+ start_seg_with_known_loc = i;
+
+ if (start_seg_with_known_loc > 0 || !(f->page_flag & PAGEFLAG_continued_packet))
+ break;
+
+ // (untested) the final packet begins on an earlier page
+ if (!go_to_page_before(f, page_start))
+ goto error;
+
+ page_start = stb_vorbis_get_file_offset(f);
+ if (!start_page(f)) goto error;
+ end_pos = f->segment_count - 1;
+ }
+
+ // prepare to start decoding
+ f->current_loc_valid = FALSE;
+ f->last_seg = FALSE;
+ f->valid_bits = 0;
+ f->packet_bytes = 0;
+ f->bytes_in_seg = 0;
+ f->previous_length = 0;
+ f->next_seg = start_seg_with_known_loc;
+
+ for (i = 0; i < start_seg_with_known_loc; i++)
+ skip(f, f->segments[i]);
+
+ // start decoding (optimizable - this frame is generally discarded)
+ vorbis_pump_first_frame(f);
+ return 1;
+
+error:
+ // try to restore the file to a valid state
+ stb_vorbis_seek_start(f);
+ return error(f, VORBIS_seek_failed);
+}
+
+// the same as vorbis_decode_initial, but without advancing
+static int peek_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode)
+{
+ int bits_read, bytes_read;
+
+ if (!vorbis_decode_initial(f, p_left_start, p_left_end, p_right_start, p_right_end, mode))
+ return 0;
+
+ // either 1 or 2 bytes were read, figure out which so we can rewind
+ bits_read = 1 + ilog(f->mode_count-1);
+ if (f->mode_config[*mode].blockflag)
+ bits_read += 2;
+ bytes_read = (bits_read + 7) / 8;
+
+ f->bytes_in_seg += bytes_read;
+ f->packet_bytes -= bytes_read;
+ skip(f, -bytes_read);
+ if (f->next_seg == -1)
+ f->next_seg = f->segment_count - 1;
+ else
+ f->next_seg--;
+ f->valid_bits = 0;
+
+ return 1;
+}
+
+int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number)
+{
+ uint32 max_frame_samples;
+
+ if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
+
+ // fast page-level search
+ if (!seek_to_sample_coarse(f, sample_number))
+ return 0;
+
+ assert(f->current_loc_valid);
+ assert(f->current_loc <= sample_number);
+
+ // linear search for the relevant packet
+ max_frame_samples = (f->blocksize_1*3 - f->blocksize_0) >> 2;
+ while (f->current_loc < sample_number) {
+ int left_start, left_end, right_start, right_end, mode, frame_samples;
+ if (!peek_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode))
+ return error(f, VORBIS_seek_failed);
+ // calculate the number of samples returned by the next frame
+ frame_samples = right_start - left_start;
+ if (f->current_loc + frame_samples > sample_number) {
+ return 1; // the next frame will contain the sample
+ } else if (f->current_loc + frame_samples + max_frame_samples > sample_number) {
+ // there's a chance the frame after this could contain the sample
+ vorbis_pump_first_frame(f);
+ } else {
+ // this frame is too early to be relevant
+ f->current_loc += frame_samples;
+ f->previous_length = 0;
+ maybe_start_packet(f);
+ flush_packet(f);
+ }
+ }
+ // the next frame will start with the sample
+ assert(f->current_loc == sample_number);
+ return 1;
+}
+
+int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number)
+{
+ if (!stb_vorbis_seek_frame(f, sample_number))
+ return 0;
+
+ if (sample_number != f->current_loc) {
+ int n;
+ uint32 frame_start = f->current_loc;
+ stb_vorbis_get_frame_float(f, &n, NULL);
+ assert(sample_number > frame_start);
+ assert(f->channel_buffer_start + (int) (sample_number-frame_start) <= f->channel_buffer_end);
+ f->channel_buffer_start += (sample_number - frame_start);
+ }
+
+ return 1;
+}
+
+void stb_vorbis_seek_start(stb_vorbis *f)
+{
+ if (IS_PUSH_MODE(f)) { error(f, VORBIS_invalid_api_mixing); return; }
+ set_file_offset(f, f->first_audio_page_offset);
+ f->previous_length = 0;
+ f->first_decode = TRUE;
+ f->next_seg = -1;
+ vorbis_pump_first_frame(f);
+}
+
+unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f)
+{
+ unsigned int restore_offset, previous_safe;
+ unsigned int end, last_page_loc;
+
+ if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
+ if (!f->total_samples) {
+ unsigned int last;
+ uint32 lo,hi;
+ char header[6];
+
+ // first, store the current decode position so we can restore it
+ restore_offset = stb_vorbis_get_file_offset(f);
+
+ // now we want to seek back 64K from the end (the last page must
+ // be at most a little less than 64K, but let's allow a little slop)
+ if (f->stream_len >= 65536 && f->stream_len-65536 >= f->first_audio_page_offset)
+ previous_safe = f->stream_len - 65536;
+ else
+ previous_safe = f->first_audio_page_offset;
+
+ set_file_offset(f, previous_safe);
+ // previous_safe is now our candidate 'earliest known place that seeking
+ // to will lead to the final page'
+
+ if (!vorbis_find_page(f, &end, &last)) {
+ // if we can't find a page, we're hosed!
+ f->error = VORBIS_cant_find_last_page;
+ f->total_samples = 0xffffffff;
+ goto done;
+ }
+
+ // check if there are more pages
+ last_page_loc = stb_vorbis_get_file_offset(f);
+
+ // stop when the last_page flag is set, not when we reach eof;
+ // this allows us to stop short of a 'file_section' end without
+ // explicitly checking the length of the section
+ while (!last) {
+ set_file_offset(f, end);
+ if (!vorbis_find_page(f, &end, &last)) {
+ // the last page we found didn't have the 'last page' flag
+ // set. whoops!
+ break;
+ }
+ previous_safe = last_page_loc+1;
+ last_page_loc = stb_vorbis_get_file_offset(f);
+ }
+
+ set_file_offset(f, last_page_loc);
+
+ // parse the header
+ getn(f, (unsigned char *)header, 6);
+ // extract the absolute granule position
+ lo = get32(f);
+ hi = get32(f);
+ if (lo == 0xffffffff && hi == 0xffffffff) {
+ f->error = VORBIS_cant_find_last_page;
+ f->total_samples = SAMPLE_unknown;
+ goto done;
+ }
+ if (hi)
+ lo = 0xfffffffe; // saturate
+ f->total_samples = lo;
+
+ f->p_last.page_start = last_page_loc;
+ f->p_last.page_end = end;
+ f->p_last.last_decoded_sample = lo;
+
+ done:
+ set_file_offset(f, restore_offset);
+ }
+ return f->total_samples == SAMPLE_unknown ? 0 : f->total_samples;
+}
+
+float stb_vorbis_stream_length_in_seconds(stb_vorbis *f)
+{
+ return stb_vorbis_stream_length_in_samples(f) / (float) f->sample_rate;
+}
+
+
+
+int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output)
+{
+ int len, right,left,i;
+ if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
+
+ if (!vorbis_decode_packet(f, &len, &left, &right)) {
+ f->channel_buffer_start = f->channel_buffer_end = 0;
+ return 0;
+ }
+
+ len = vorbis_finish_frame(f, len, left, right);
+ for (i=0; i < f->channels; ++i)
+ f->outputs[i] = f->channel_buffers[i] + left;
+
+ f->channel_buffer_start = left;
+ f->channel_buffer_end = left+len;
+
+ if (channels) *channels = f->channels;
+ if (output) *output = f->outputs;
+ return len;
+}
+
+#ifndef STB_VORBIS_NO_STDIO
+
+stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length)
+{
+ stb_vorbis *f, p;
+ vorbis_init(&p, alloc);
+ p.f = file;
+ p.f_start = (uint32) ftell(file);
+ p.stream_len = length;
+ p.close_on_free = close_on_free;
+ if (start_decoder(&p)) {
+ f = vorbis_alloc(&p);
+ if (f) {
+ *f = p;
+ vorbis_pump_first_frame(f);
+ return f;
+ }
+ }
+ if (error) *error = p.error;
+ vorbis_deinit(&p);
+ return NULL;
+}
+
+stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc)
+{
+ unsigned int len, start;
+ start = (unsigned int) ftell(file);
+ fseek(file, 0, SEEK_END);
+ len = (unsigned int) (ftell(file) - start);
+ fseek(file, start, SEEK_SET);
+ return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len);
+}
+
+stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc)
+{
+ FILE *f = fopen(filename, "rb");
+ if (f)
+ return stb_vorbis_open_file(f, TRUE, error, alloc);
+ if (error) *error = VORBIS_file_open_failure;
+ return NULL;
+}
+#endif // STB_VORBIS_NO_STDIO
+
+stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc)
+{
+ stb_vorbis *f, p;
+ if (data == NULL) return NULL;
+ vorbis_init(&p, alloc);
+ p.stream = (uint8 *) data;
+ p.stream_end = (uint8 *) data + len;
+ p.stream_start = (uint8 *) p.stream;
+ p.stream_len = len;
+ p.push_mode = FALSE;
+ if (start_decoder(&p)) {
+ f = vorbis_alloc(&p);
+ if (f) {
+ *f = p;
+ vorbis_pump_first_frame(f);
+ return f;
+ }
+ }
+ if (error) *error = p.error;
+ vorbis_deinit(&p);
+ return NULL;
+}
+
+#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
+#define PLAYBACK_MONO 1
+#define PLAYBACK_LEFT 2
+#define PLAYBACK_RIGHT 4
+
+#define L (PLAYBACK_LEFT | PLAYBACK_MONO)
+#define C (PLAYBACK_LEFT | PLAYBACK_RIGHT | PLAYBACK_MONO)
+#define R (PLAYBACK_RIGHT | PLAYBACK_MONO)
+
+static int8 channel_position[7][6] =
+{
+ { 0 },
+ { C },
+ { L, R },
+ { L, C, R },
+ { L, R, L, R },
+ { L, C, R, L, R },
+ { L, C, R, L, R, C },
+};
+
+
+#ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT
+ typedef union {
+ float f;
+ int i;
+ } float_conv;
+ typedef char stb_vorbis_float_size_test[sizeof(float)==4 && sizeof(int) == 4];
+ #define FASTDEF(x) float_conv x
+ // add (1<<23) to convert to int, then divide by 2^SHIFT, then add 0.5/2^SHIFT to round
+ #define MAGIC(SHIFT) (1.5f * (1 << (23-SHIFT)) + 0.5f/(1 << SHIFT))
+ #define ADDEND(SHIFT) (((150-SHIFT) << 23) + (1 << 22))
+ #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) (temp.f = (x) + MAGIC(s), temp.i - ADDEND(s))
+ #define check_endianness()
+#else
+ #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) ((int) ((x) * (1 << (s))))
+ #define check_endianness()
+ #define FASTDEF(x)
+#endif
+
+static void copy_samples(short *dest, float *src, int len)
+{
+ int i;
+ check_endianness();
+ for (i=0; i < len; ++i) {
+ FASTDEF(temp);
+ int v = FAST_SCALED_FLOAT_TO_INT(temp, src[i],15);
+ if ((unsigned int) (v + 32768) > 65535)
+ v = v < 0 ? -32768 : 32767;
+ dest[i] = v;
+ }
+}
+
+static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len)
+{
+ #define BUFFER_SIZE 32
+ float buffer[BUFFER_SIZE];
+ int i,j,o,n = BUFFER_SIZE;
+ check_endianness();
+ for (o = 0; o < len; o += BUFFER_SIZE) {
+ memset(buffer, 0, sizeof(buffer));
+ if (o + n > len) n = len - o;
+ for (j=0; j < num_c; ++j) {
+ if (channel_position[num_c][j] & mask) {
+ for (i=0; i < n; ++i)
+ buffer[i] += data[j][d_offset+o+i];
+ }
+ }
+ for (i=0; i < n; ++i) {
+ FASTDEF(temp);
+ int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15);
+ if ((unsigned int) (v + 32768) > 65535)
+ v = v < 0 ? -32768 : 32767;
+ output[o+i] = v;
+ }
+ }
+}
+
+static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len)
+{
+ #define BUFFER_SIZE 32
+ float buffer[BUFFER_SIZE];
+ int i,j,o,n = BUFFER_SIZE >> 1;
+ // o is the offset in the source data
+ check_endianness();
+ for (o = 0; o < len; o += BUFFER_SIZE >> 1) {
+ // o2 is the offset in the output data
+ int o2 = o << 1;
+ memset(buffer, 0, sizeof(buffer));
+ if (o + n > len) n = len - o;
+ for (j=0; j < num_c; ++j) {
+ int m = channel_position[num_c][j] & (PLAYBACK_LEFT | PLAYBACK_RIGHT);
+ if (m == (PLAYBACK_LEFT | PLAYBACK_RIGHT)) {
+ for (i=0; i < n; ++i) {
+ buffer[i*2+0] += data[j][d_offset+o+i];
+ buffer[i*2+1] += data[j][d_offset+o+i];
+ }
+ } else if (m == PLAYBACK_LEFT) {
+ for (i=0; i < n; ++i) {
+ buffer[i*2+0] += data[j][d_offset+o+i];
+ }
+ } else if (m == PLAYBACK_RIGHT) {
+ for (i=0; i < n; ++i) {
+ buffer[i*2+1] += data[j][d_offset+o+i];
+ }
+ }
+ }
+ for (i=0; i < (n<<1); ++i) {
+ FASTDEF(temp);
+ int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15);
+ if ((unsigned int) (v + 32768) > 65535)
+ v = v < 0 ? -32768 : 32767;
+ output[o2+i] = v;
+ }
+ }
+}
+
+static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples)
+{
+ int i;
+ if (buf_c != data_c && buf_c <= 2 && data_c <= 6) {
+ static int channel_selector[3][2] = { {0}, {PLAYBACK_MONO}, {PLAYBACK_LEFT, PLAYBACK_RIGHT} };
+ for (i=0; i < buf_c; ++i)
+ compute_samples(channel_selector[buf_c][i], buffer[i]+b_offset, data_c, data, d_offset, samples);
+ } else {
+ int limit = buf_c < data_c ? buf_c : data_c;
+ for (i=0; i < limit; ++i)
+ copy_samples(buffer[i]+b_offset, data[i]+d_offset, samples);
+ for ( ; i < buf_c; ++i)
+ memset(buffer[i]+b_offset, 0, sizeof(short) * samples);
+ }
+}
+
+int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples)
+{
+ float **output;
+ int len = stb_vorbis_get_frame_float(f, NULL, &output);
+ if (len > num_samples) len = num_samples;
+ if (len)
+ convert_samples_short(num_c, buffer, 0, f->channels, output, 0, len);
+ return len;
+}
+
+static void convert_channels_short_interleaved(int buf_c, short *buffer, int data_c, float **data, int d_offset, int len)
+{
+ int i;
+ check_endianness();
+ if (buf_c != data_c && buf_c <= 2 && data_c <= 6) {
+ assert(buf_c == 2);
+ for (i=0; i < buf_c; ++i)
+ compute_stereo_samples(buffer, data_c, data, d_offset, len);
+ } else {
+ int limit = buf_c < data_c ? buf_c : data_c;
+ int j;
+ for (j=0; j < len; ++j) {
+ for (i=0; i < limit; ++i) {
+ FASTDEF(temp);
+ float f = data[i][d_offset+j];
+ int v = FAST_SCALED_FLOAT_TO_INT(temp, f,15);//data[i][d_offset+j],15);
+ if ((unsigned int) (v + 32768) > 65535)
+ v = v < 0 ? -32768 : 32767;
+ *buffer++ = v;
+ }
+ for ( ; i < buf_c; ++i)
+ *buffer++ = 0;
+ }
+ }
+}
+
+int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts)
+{
+ float **output;
+ int len;
+ if (num_c == 1) return stb_vorbis_get_frame_short(f,num_c,&buffer, num_shorts);
+ len = stb_vorbis_get_frame_float(f, NULL, &output);
+ if (len) {
+ if (len*num_c > num_shorts) len = num_shorts / num_c;
+ convert_channels_short_interleaved(num_c, buffer, f->channels, output, 0, len);
+ }
+ return len;
+}
+
+int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts)
+{
+ float **outputs;
+ int len = num_shorts / channels;
+ int n=0;
+ int z = f->channels;
+ if (z > channels) z = channels;
+ while (n < len) {
+ int k = f->channel_buffer_end - f->channel_buffer_start;
+ if (n+k >= len) k = len - n;
+ if (k)
+ convert_channels_short_interleaved(channels, buffer, f->channels, f->channel_buffers, f->channel_buffer_start, k);
+ buffer += k*channels;
+ n += k;
+ f->channel_buffer_start += k;
+ if (n == len) break;
+ if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break;
+ }
+ return n;
+}
+
+int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int len)
+{
+ float **outputs;
+ int n=0;
+ int z = f->channels;
+ if (z > channels) z = channels;
+ while (n < len) {
+ int k = f->channel_buffer_end - f->channel_buffer_start;
+ if (n+k >= len) k = len - n;
+ if (k)
+ convert_samples_short(channels, buffer, n, f->channels, f->channel_buffers, f->channel_buffer_start, k);
+ n += k;
+ f->channel_buffer_start += k;
+ if (n == len) break;
+ if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break;
+ }
+ return n;
+}
+
+#ifndef STB_VORBIS_NO_STDIO
+int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output)
+{
+ int data_len, offset, total, limit, error;
+ short *data;
+ stb_vorbis *v = stb_vorbis_open_filename(filename, &error, NULL);
+ if (v == NULL) return -1;
+ limit = v->channels * 4096;
+ *channels = v->channels;
+ if (sample_rate)
+ *sample_rate = v->sample_rate;
+ offset = data_len = 0;
+ total = limit;
+ data = (short *) malloc(total * sizeof(*data));
+ if (data == NULL) {
+ stb_vorbis_close(v);
+ return -2;
+ }
+ for (;;) {
+ int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data+offset, total-offset);
+ if (n == 0) break;
+ data_len += n;
+ offset += n * v->channels;
+ if (offset + limit > total) {
+ short *data2;
+ total *= 2;
+ data2 = (short *) realloc(data, total * sizeof(*data));
+ if (data2 == NULL) {
+ free(data);
+ stb_vorbis_close(v);
+ return -2;
+ }
+ data = data2;
+ }
+ }
+ *output = data;
+ stb_vorbis_close(v);
+ return data_len;
+}
+#endif // NO_STDIO
+
+int stb_vorbis_decode_memory(const uint8 *mem, int len, int *channels, int *sample_rate, short **output)
+{
+ int data_len, offset, total, limit, error;
+ short *data;
+ stb_vorbis *v = stb_vorbis_open_memory(mem, len, &error, NULL);
+ if (v == NULL) return -1;
+ limit = v->channels * 4096;
+ *channels = v->channels;
+ if (sample_rate)
+ *sample_rate = v->sample_rate;
+ offset = data_len = 0;
+ total = limit;
+ data = (short *) malloc(total * sizeof(*data));
+ if (data == NULL) {
+ stb_vorbis_close(v);
+ return -2;
+ }
+ for (;;) {
+ int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data+offset, total-offset);
+ if (n == 0) break;
+ data_len += n;
+ offset += n * v->channels;
+ if (offset + limit > total) {
+ short *data2;
+ total *= 2;
+ data2 = (short *) realloc(data, total * sizeof(*data));
+ if (data2 == NULL) {
+ free(data);
+ stb_vorbis_close(v);
+ return -2;
+ }
+ data = data2;
+ }
+ }
+ *output = data;
+ stb_vorbis_close(v);
+ return data_len;
+}
+#endif // STB_VORBIS_NO_INTEGER_CONVERSION
+
+int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats)
+{
+ float **outputs;
+ int len = num_floats / channels;
+ int n=0;
+ int z = f->channels;
+ if (z > channels) z = channels;
+ while (n < len) {
+ int i,j;
+ int k = f->channel_buffer_end - f->channel_buffer_start;
+ if (n+k >= len) k = len - n;
+ for (j=0; j < k; ++j) {
+ for (i=0; i < z; ++i)
+ *buffer++ = f->channel_buffers[i][f->channel_buffer_start+j];
+ for ( ; i < channels; ++i)
+ *buffer++ = 0;
+ }
+ n += k;
+ f->channel_buffer_start += k;
+ if (n == len)
+ break;
+ if (!stb_vorbis_get_frame_float(f, NULL, &outputs))
+ break;
+ }
+ return n;
+}
+
+int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples)
+{
+ float **outputs;
+ int n=0;
+ int z = f->channels;
+ if (z > channels) z = channels;
+ while (n < num_samples) {
+ int i;
+ int k = f->channel_buffer_end - f->channel_buffer_start;
+ if (n+k >= num_samples) k = num_samples - n;
+ if (k) {
+ for (i=0; i < z; ++i)
+ memcpy(buffer[i]+n, f->channel_buffers[i]+f->channel_buffer_start, sizeof(float)*k);
+ for ( ; i < channels; ++i)
+ memset(buffer[i]+n, 0, sizeof(float) * k);
+ }
+ n += k;
+ f->channel_buffer_start += k;
+ if (n == num_samples)
+ break;
+ if (!stb_vorbis_get_frame_float(f, NULL, &outputs))
+ break;
+ }
+ return n;
+}
+#endif // STB_VORBIS_NO_PULLDATA_API
+
+/* Version history
+ 1.09 - 2016/04/04 - back out 'avoid discarding last frame' fix from previous version
+ 1.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks;
+ avoid discarding last frame of audio data
+ 1.07 - 2015/01/16 - fixed some warnings, fix mingw, const-correct API
+ some more crash fixes when out of memory or with corrupt files
+ 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson)
+ some crash fixes when out of memory or with corrupt files
+ 1.05 - 2015/04/19 - don't define __forceinline if it's redundant
+ 1.04 - 2014/08/27 - fix missing const-correct case in API
+ 1.03 - 2014/08/07 - Warning fixes
+ 1.02 - 2014/07/09 - Declare qsort compare function _cdecl on windows
+ 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float
+ 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in multichannel
+ (API change) report sample rate for decode-full-file funcs
+ 0.99996 - bracket #include <malloc.h> for macintosh compilation by Laurent Gomila
+ 0.99995 - use union instead of pointer-cast for fast-float-to-int to avoid alias-optimization problem
+ 0.99994 - change fast-float-to-int to work in single-precision FPU mode, remove endian-dependence
+ 0.99993 - remove assert that fired on legal files with empty tables
+ 0.99992 - rewind-to-start
+ 0.99991 - bugfix to stb_vorbis_get_samples_short by Bernhard Wodo
+ 0.9999 - (should have been 0.99990) fix no-CRT support, compiling as C++
+ 0.9998 - add a full-decode function with a memory source
+ 0.9997 - fix a bug in the read-from-FILE case in 0.9996 addition
+ 0.9996 - query length of vorbis stream in samples/seconds
+ 0.9995 - bugfix to another optimization that only happened in certain files
+ 0.9994 - bugfix to one of the optimizations that caused significant (but inaudible?) errors
+ 0.9993 - performance improvements; runs in 99% to 104% of time of reference implementation
+ 0.9992 - performance improvement of IMDCT; now performs close to reference implementation
+ 0.9991 - performance improvement of IMDCT
+ 0.999 - (should have been 0.9990) performance improvement of IMDCT
+ 0.998 - no-CRT support from Casey Muratori
+ 0.997 - bugfixes for bugs found by Terje Mathisen
+ 0.996 - bugfix: fast-huffman decode initialized incorrectly for sparse codebooks; fixing gives 10% speedup - found by Terje Mathisen
+ 0.995 - bugfix: fix to 'effective' overrun detection - found by Terje Mathisen
+ 0.994 - bugfix: garbage decode on final VQ symbol of a non-multiple - found by Terje Mathisen
+ 0.993 - bugfix: pushdata API required 1 extra byte for empty page (failed to consume final page if empty) - found by Terje Mathisen
+ 0.992 - fixes for MinGW warning
+ 0.991 - turn fast-float-conversion on by default
+ 0.990 - fix push-mode seek recovery if you seek into the headers
+ 0.98b - fix to bad release of 0.98
+ 0.98 - fix push-mode seek recovery; robustify float-to-int and support non-fast mode
+ 0.97 - builds under c++ (typecasting, don't use 'class' keyword)
+ 0.96 - somehow MY 0.95 was right, but the web one was wrong, so here's my 0.95 rereleased as 0.96, fixes a typo in the clamping code
+ 0.95 - clamping code for 16-bit functions
+ 0.94 - not publically released
+ 0.93 - fixed all-zero-floor case (was decoding garbage)
+ 0.92 - fixed a memory leak
+ 0.91 - conditional compiles to omit parts of the API and the infrastructure to support them: STB_VORBIS_NO_PULLDATA_API, STB_VORBIS_NO_PUSHDATA_API, STB_VORBIS_NO_STDIO, STB_VORBIS_NO_INTEGER_CONVERSION
+ 0.90 - first public release
+*/
+
+#endif // STB_VORBIS_HEADER_ONLY
diff --git a/tools/editor/SCsub b/tools/editor/SCsub
index caf45d25be..a0e6802348 100644
--- a/tools/editor/SCsub
+++ b/tools/editor/SCsub
@@ -55,7 +55,7 @@ if (env["tools"] == "yes"):
reg_exporters = 'void register_exporters() {\n'
for e in env.platform_exporters:
env.tool_sources.append("#platform/" + e + "/export/export.cpp")
- reg_exporters += '\tregister_' + e + '_exporter();\n'
+ reg_exporters += '\t//register_' + e + '_exporter();\n'
reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n'
reg_exporters += '}\n'
f = open("register_exporters.cpp", "wb")
@@ -78,3 +78,4 @@ if (env["tools"] == "yes"):
SConscript('plugins/SCsub')
SConscript('fileserver/SCsub')
SConscript('io_plugins/SCsub')
+ SConscript('import/SCsub')
diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp
index 759d33dea8..f256e351ae 100644
--- a/tools/editor/animation_editor.cpp
+++ b/tools/editor/animation_editor.cpp
@@ -179,12 +179,12 @@ private:
bool sg = val < 0;
val = Math::absf(val);
- val = Math::log(val)/Math::log(2);
+ val = Math::log(val)/Math::log((float)2.0);
//logspace
val+=rel*0.05;
//
- val = Math::pow(2,val);
+ val = Math::pow((float)2.0,val);
if (sg)
val=-val;
@@ -1055,9 +1055,9 @@ float AnimationKeyEditor::_get_zoom_scale() const {
float zv = zoom->get_value();
if (zv<1) {
zv = 1.0-zv;
- return Math::pow(1.0+zv,8.0)*100;
+ return Math::pow(1.0f+zv,8.0f)*100;
} else {
- return 1.0/Math::pow(zv,8.0)*100;
+ return 1.0/Math::pow(zv,8.0f)*100;
}
}
@@ -1487,8 +1487,8 @@ void AnimationKeyEditor::_track_editor_draw() {
//draw the keys;
int tt = animation->track_get_type(idx);
- float key_vofs = Math::floor((h - type_icon[tt]->get_height())/2);
- float key_hofs = -Math::floor(type_icon[tt]->get_height()/2);
+ float key_vofs = Math::floor((float)(h - type_icon[tt]->get_height())/2);
+ float key_hofs = -Math::floor((float)type_icon[tt]->get_height()/2);
int kc=animation->track_get_key_count(idx);
bool first=true;
@@ -1592,8 +1592,8 @@ void AnimationKeyEditor::_track_editor_draw() {
continue;
int y = h+i*h+sep;
- float key_vofs = Math::floor((h - type_selected->get_height())/2);
- float key_hofs = -Math::floor(type_selected->get_height()/2);
+ float key_vofs = Math::floor((float)(h - type_selected->get_height())/2);
+ float key_hofs = -Math::floor((float)type_selected->get_height()/2);
float time = animation->track_get_key_time(idx,E->key().key);
float diff = time-from_t;
diff --git a/tools/editor/editor_audio_buses.cpp b/tools/editor/editor_audio_buses.cpp
new file mode 100644
index 0000000000..6ee18f08d8
--- /dev/null
+++ b/tools/editor/editor_audio_buses.cpp
@@ -0,0 +1,1192 @@
+#include "editor_audio_buses.h"
+#include "editor_node.h"
+#include "servers/audio_server.h"
+#include "os/keyboard.h"
+#include "io/resource_saver.h"
+#include "filesystem_dock.h"
+
+void EditorAudioBus::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_READY) {
+
+ vu_l->set_under_texture(get_icon("BusVuEmpty","EditorIcons"));
+ vu_l->set_progress_texture(get_icon("BusVuFull","EditorIcons"));
+ vu_r->set_under_texture(get_icon("BusVuEmpty","EditorIcons"));
+ vu_r->set_progress_texture(get_icon("BusVuFull","EditorIcons"));
+ scale->set_texture( get_icon("BusVuDb","EditorIcons"));
+
+ disabled_vu = get_icon("BusVuFrozen","EditorIcons");
+
+ prev_active=true;
+ update_bus();
+ set_process(true);
+ }
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+ if (has_focus()) {
+ draw_style_box(get_stylebox("focus","Button"),Rect2(Vector2(),get_size()));
+ }
+ }
+
+ if (p_what==NOTIFICATION_PROCESS) {
+
+ float real_peak[2]={-100,-100};
+ bool activity_found=false;
+
+ int cc;
+ switch(AudioServer::get_singleton()->get_speaker_mode()) {
+ case AudioServer::SPEAKER_MODE_STEREO: cc = 1; break;
+ case AudioServer::SPEAKER_SURROUND_51: cc = 4; break;
+ case AudioServer::SPEAKER_SURROUND_71: cc = 5; break;
+ }
+
+ for(int i=0;i<cc;i++) {
+ if (AudioServer::get_singleton()->is_bus_channel_active(get_index(),i)) {
+ activity_found=true;
+ real_peak[0]=MAX(real_peak[0],AudioServer::get_singleton()->get_bus_peak_volume_left_db(get_index(),i));
+ real_peak[1]=MAX(real_peak[1],AudioServer::get_singleton()->get_bus_peak_volume_right_db(get_index(),i));
+ }
+ }
+
+
+ if (real_peak[0]>peak_l) {
+ peak_l = real_peak[0];
+ } else {
+ peak_l-=get_process_delta_time()*60.0;
+ }
+
+ if (real_peak[1]>peak_r) {
+ peak_r = real_peak[1];
+ } else {
+ peak_r-=get_process_delta_time()*60.0;
+
+ }
+
+ vu_l->set_value(peak_l);
+ vu_r->set_value(peak_r);
+
+ if (activity_found!=prev_active) {
+ if (activity_found) {
+ vu_l->set_over_texture(Ref<Texture>());
+ vu_r->set_over_texture(Ref<Texture>());
+ } else {
+ vu_l->set_over_texture(disabled_vu);
+ vu_r->set_over_texture(disabled_vu);
+
+ }
+
+ prev_active=activity_found;
+ }
+
+ }
+
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ peak_l=-100;
+ peak_r=-100;
+ prev_active=true;
+
+ set_process(is_visible_in_tree());
+ }
+
+}
+
+void EditorAudioBus::update_send() {
+
+ send->clear();
+ if (get_index()==0) {
+ send->set_disabled(true);
+ send->set_text("Speakers");
+ } else {
+ send->set_disabled(false);
+ StringName current_send = AudioServer::get_singleton()->get_bus_send(get_index());
+ int current_send_index=0; //by default to master
+
+ for(int i=0;i<get_index();i++) {
+ StringName send_name = AudioServer::get_singleton()->get_bus_name(i);
+ send->add_item(send_name);
+ if (send_name==current_send) {
+ current_send_index=i;
+ }
+ }
+
+ send->select(current_send_index);
+ }
+}
+
+void EditorAudioBus::update_bus() {
+
+ if (updating_bus)
+ return;
+
+ updating_bus=true;
+
+ int index = get_index();
+
+ slider->set_value(AudioServer::get_singleton()->get_bus_volume_db(index));
+ track_name->set_text(AudioServer::get_singleton()->get_bus_name(index));
+ if (get_index()==0)
+ track_name->set_editable(false);
+
+ solo->set_pressed( AudioServer::get_singleton()->is_bus_solo(index));
+ mute->set_pressed( AudioServer::get_singleton()->is_bus_mute(index));
+ bypass->set_pressed( AudioServer::get_singleton()->is_bus_bypassing_effects(index));
+ // effects..
+ effects->clear();
+
+ TreeItem *root = effects->create_item();
+ for(int i=0;i<AudioServer::get_singleton()->get_bus_effect_count(index);i++) {
+
+ Ref<AudioEffect> afx = AudioServer::get_singleton()->get_bus_effect(index,i);
+
+ TreeItem *fx = effects->create_item(root);
+ fx->set_cell_mode(0,TreeItem::CELL_MODE_CHECK);
+ fx->set_editable(0,true);
+ fx->set_checked(0,AudioServer::get_singleton()->is_bus_effect_enabled(index,i));
+ fx->set_text(0,afx->get_name());
+ fx->set_metadata(0,i);
+
+ }
+
+ TreeItem *add = effects->create_item(root);
+ add->set_cell_mode(0,TreeItem::CELL_MODE_CUSTOM);
+ add->set_editable(0,true);
+ add->set_selectable(0,false);
+ add->set_text(0,"Add Effect");
+
+ update_send();
+
+ updating_bus=false;
+
+}
+
+
+void EditorAudioBus::_name_changed(const String& p_new_name) {
+
+ if (p_new_name==AudioServer::get_singleton()->get_bus_name(get_index()))
+ return;
+
+ String attempt=p_new_name;
+ int attempts=1;
+
+ while(true) {
+
+ bool name_free=true;
+ for(int i=0;i<AudioServer::get_singleton()->get_bus_count();i++) {
+
+ if (AudioServer::get_singleton()->get_bus_name(i)==attempt) {
+ name_free=false;
+ break;
+ }
+ }
+
+ if (name_free) {
+ break;
+ }
+
+ attempts++;
+ attempt=p_new_name+" "+itos(attempts);
+ }
+ updating_bus=true;
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ StringName current = AudioServer::get_singleton()->get_bus_name(get_index());
+ ur->create_action("Rename Audio Bus");
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_name",get_index(),attempt);
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_name",get_index(),current);
+
+ for(int i=0;i<AudioServer::get_singleton()->get_bus_count();i++) {
+ if (AudioServer::get_singleton()->get_bus_send(i)==current) {
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_send",i,attempt);
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_send",i,current);
+ }
+ }
+
+ ur->add_do_method(buses,"_update_bus",get_index());
+ ur->add_undo_method(buses,"_update_bus",get_index());
+
+
+ ur->add_do_method(buses,"_update_sends");
+ ur->add_undo_method(buses,"_update_sends");
+ ur->commit_action();
+
+ updating_bus=false;
+
+}
+
+void EditorAudioBus::_volume_db_changed(float p_db){
+
+ if (updating_bus)
+ return;
+
+ updating_bus=true;
+
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change Audio Bus Volume",UndoRedo::MERGE_ENDS);
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_volume_db",get_index(),p_db);
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_volume_db",get_index(),AudioServer::get_singleton()->get_bus_volume_db(get_index()));
+ ur->add_do_method(buses,"_update_bus",get_index());
+ ur->add_undo_method(buses,"_update_bus",get_index());
+ ur->commit_action();
+
+ updating_bus=false;
+
+}
+void EditorAudioBus::_solo_toggled(){
+
+ updating_bus=true;
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Toggle Audio Bus Solo");
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_solo",get_index(),solo->is_pressed());
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_solo",get_index(),AudioServer::get_singleton()->is_bus_solo(get_index()));
+ ur->add_do_method(buses,"_update_bus",get_index());
+ ur->add_undo_method(buses,"_update_bus",get_index());
+ ur->commit_action();
+
+ updating_bus=false;
+
+}
+void EditorAudioBus::_mute_toggled(){
+
+ updating_bus=true;
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Toggle Audio Bus Mute");
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_mute",get_index(),mute->is_pressed());
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_mute",get_index(),AudioServer::get_singleton()->is_bus_mute(get_index()));
+ ur->add_do_method(buses,"_update_bus",get_index());
+ ur->add_undo_method(buses,"_update_bus",get_index());
+ ur->commit_action();
+
+ updating_bus=false;
+
+}
+void EditorAudioBus::_bypass_toggled(){
+
+ updating_bus=true;
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Toggle Audio Bus Bypass Effects");
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_bypass_effects",get_index(),bypass->is_pressed());
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_bypass_effects",get_index(),AudioServer::get_singleton()->is_bus_bypassing_effects(get_index()));
+ ur->add_do_method(buses,"_update_bus",get_index());
+ ur->add_undo_method(buses,"_update_bus",get_index());
+ ur->commit_action();
+
+ updating_bus=false;
+
+
+}
+
+void EditorAudioBus::_send_selected(int p_which) {
+
+ updating_bus=true;
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Select Audio Bus Send");
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_send",get_index(),send->get_item_text(p_which));
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_send",get_index(),AudioServer::get_singleton()->get_bus_send(get_index()));
+ ur->add_do_method(buses,"_update_bus",get_index());
+ ur->add_undo_method(buses,"_update_bus",get_index());
+ ur->commit_action();
+
+ updating_bus=false;
+}
+
+void EditorAudioBus::_effect_selected() {
+
+ TreeItem *effect = effects->get_selected();
+ if (!effect)
+ return;
+ updating_bus=true;
+
+ if (effect->get_metadata(0)!=Variant()) {
+
+ int index = effect->get_metadata(0);
+ Ref<AudioEffect> effect = AudioServer::get_singleton()->get_bus_effect(get_index(),index);
+ if (effect.is_valid()) {
+ EditorNode::get_singleton()->push_item(effect.ptr());
+ }
+ }
+
+ updating_bus=false;
+
+}
+
+void EditorAudioBus::_effect_edited() {
+
+ if (updating_bus)
+ return;
+
+ TreeItem *effect = effects->get_edited();
+ if (!effect)
+ return;
+
+ if (effect->get_metadata(0)==Variant()) {
+ Rect2 area = effects->get_item_rect(effect);
+
+ effect_options->set_pos(effects->get_global_pos()+area.pos+Vector2(0,area.size.y));
+ effect_options->popup();
+ //add effect
+ } else {
+ int index = effect->get_metadata(0);
+ updating_bus=true;
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Select Audio Bus Send");
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_effect_enabled",get_index(),index,effect->is_checked(0));
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_effect_enabled",get_index(),index,AudioServer::get_singleton()->is_bus_effect_enabled(get_index(),index));
+ ur->add_do_method(buses,"_update_bus",get_index());
+ ur->add_undo_method(buses,"_update_bus",get_index());
+ ur->commit_action();
+
+ updating_bus=false;
+
+ }
+
+}
+
+void EditorAudioBus::_effect_add(int p_which) {
+
+ if (updating_bus)
+ return;
+
+ StringName name = effect_options->get_item_metadata(p_which);
+
+ Object *fx = ClassDB::instance(name);
+ ERR_FAIL_COND(!fx);
+ AudioEffect *afx = fx->cast_to<AudioEffect>();
+ ERR_FAIL_COND(!afx);
+ Ref<AudioEffect> afxr = Ref<AudioEffect>(afx);
+
+ afxr->set_name(effect_options->get_item_text(p_which));
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Add Audio Bus Effect");
+ ur->add_do_method(AudioServer::get_singleton(),"add_bus_effect",get_index(),afxr,-1);
+ ur->add_undo_method(AudioServer::get_singleton(),"remove_bus_effect",get_index(),AudioServer::get_singleton()->get_bus_effect_count(get_index()));
+ ur->add_do_method(buses,"_update_bus",get_index());
+ ur->add_undo_method(buses,"_update_bus",get_index());
+ ur->commit_action();
+}
+
+void EditorAudioBus::_gui_input(const InputEvent& p_event) {
+
+ if (p_event.type==InputEvent::KEY && p_event.key.pressed && p_event.key.scancode==KEY_DELETE && !p_event.key.echo) {
+ accept_event();
+ emit_signal("delete_request");
+ }
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==2 && p_event.mouse_button.pressed) {
+
+ Vector2 pos = Vector2(p_event.mouse_button.x,p_event.mouse_button.y);
+ delete_popup->set_pos(get_global_pos()+pos);
+ delete_popup->popup();
+ }
+}
+
+void EditorAudioBus::_delete_pressed(int p_option) {
+
+ if (p_option==1) {
+ emit_signal("delete_request");
+ } else if (p_option==0) {
+ //duplicate
+ emit_signal("duplicate_request",get_index());
+ }
+
+}
+
+
+Variant EditorAudioBus::get_drag_data(const Point2& p_point) {
+
+ if (get_index()==0) {
+ return Variant();
+ }
+
+ Control *c = memnew(Control);
+ Panel *p = memnew( Panel );
+ c->add_child(p);
+ p->add_style_override("panel",get_stylebox("focus","Button"));
+ p->set_size(get_size());
+ p->set_pos(-p_point);
+ set_drag_preview(c);
+ Dictionary d;
+ d["type"]="move_audio_bus";
+ d["index"]=get_index();
+ emit_signal("drop_end_request");
+ return d;
+}
+
+bool EditorAudioBus::can_drop_data(const Point2& p_point,const Variant& p_data) const {
+
+ if (get_index()==0)
+ return false;
+ Dictionary d=p_data;
+ if (d.has("type") && String(d["type"])=="move_audio_bus") {
+ return true;
+ }
+
+ return false;
+}
+void EditorAudioBus::drop_data(const Point2& p_point,const Variant& p_data) {
+
+ Dictionary d=p_data;
+ emit_signal("dropped",d["index"],get_index());
+
+}
+
+Variant EditorAudioBus::get_drag_data_fw(const Point2& p_point,Control* p_from) {
+
+ print_line("drag fw");
+ TreeItem *item = effects->get_item_at_pos(p_point);
+ if (!item) {
+ print_line("no item");
+ return Variant();
+ }
+
+ Variant md = item->get_metadata(0);
+
+ if (md.get_type()==Variant::INT) {
+ Dictionary fxd;
+ fxd["type"]="audio_bus_effect";
+ fxd["bus"]=get_index();
+ fxd["effect"]=md;
+
+ Label *l = memnew( Label );
+ l->set_text(item->get_text(0));
+ effects->set_drag_preview(l);
+
+ return fxd;
+ }
+
+ return Variant();
+
+}
+
+bool EditorAudioBus::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const{
+
+ Dictionary d = p_data;
+ if (!d.has("type") || String(d["type"])!="audio_bus_effect")
+ return false;
+
+ TreeItem *item = effects->get_item_at_pos(p_point);
+ if (!item)
+ return false;
+
+ effects->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
+
+ return true;
+}
+
+void EditorAudioBus::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from){
+
+ Dictionary d = p_data;
+
+ TreeItem *item = effects->get_item_at_pos(p_point);
+ if (!item)
+ return;
+ int pos=effects->get_drop_section_at_pos(p_point);
+ Variant md = item->get_metadata(0);
+
+ int paste_at;
+ int bus = d["bus"];
+ int effect = d["effect"];
+
+ if (md.get_type()==Variant::INT) {
+ paste_at=md;
+ if (pos>0)
+ paste_at++;
+
+ if (bus==get_index() && paste_at >effect) {
+ paste_at--;
+ }
+ } else {
+ paste_at=-1;
+ }
+
+
+ bool enabled = AudioServer::get_singleton()->is_bus_effect_enabled(bus,effect);
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Move Bus Effect");
+ ur->add_do_method(AudioServer::get_singleton(),"remove_bus_effect",bus,effect);
+ ur->add_do_method(AudioServer::get_singleton(),"add_bus_effect",get_index(),AudioServer::get_singleton()->get_bus_effect(bus,effect),paste_at);
+
+ if (paste_at==-1) {
+ paste_at = AudioServer::get_singleton()->get_bus_effect_count(get_index());
+ if (bus==get_index()) {
+ paste_at--;
+ }
+ }
+ if (!enabled) {
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_effect_enabled",get_index(),paste_at,false);
+ }
+
+ ur->add_undo_method(AudioServer::get_singleton(),"remove_bus_effect",get_index(),paste_at);
+ ur->add_undo_method(AudioServer::get_singleton(),"add_bus_effect",bus,AudioServer::get_singleton()->get_bus_effect(bus,effect),effect);
+ if (!enabled) {
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_effect_enabled",bus,effect,false);
+ }
+
+ ur->add_do_method(buses,"_update_bus",get_index());
+ ur->add_undo_method(buses,"_update_bus",get_index());
+ if (get_index()!=bus) {
+ ur->add_do_method(buses,"_update_bus",bus);
+ ur->add_undo_method(buses,"_update_bus",bus);
+ }
+ ur->commit_action();
+
+
+
+}
+
+void EditorAudioBus::_delete_effect_pressed(int p_option) {
+
+ TreeItem * item = effects->get_selected();
+ if (!item)
+ return;
+
+ if (item->get_metadata(0).get_type()!=Variant::INT)
+ return;
+
+ int index = item->get_metadata(0);
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Delete Bus Effect");
+ ur->add_do_method(AudioServer::get_singleton(),"remove_bus_effect",get_index(),index);
+ ur->add_undo_method(AudioServer::get_singleton(),"add_bus_effect",get_index(),AudioServer::get_singleton()->get_bus_effect(get_index(),index),index);
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_effect_enabled",get_index(),index,AudioServer::get_singleton()->is_bus_effect_enabled(get_index(),index));
+ ur->add_do_method(buses,"_update_bus",get_index());
+ ur->add_undo_method(buses,"_update_bus",get_index());
+ ur->commit_action();
+
+
+}
+
+void EditorAudioBus::_effect_rmb(const Vector2& p_pos) {
+
+ TreeItem * item = effects->get_selected();
+ if (!item)
+ return;
+
+ if (item->get_metadata(0).get_type()!=Variant::INT)
+ return;
+
+ delete_effect_popup->set_pos(get_global_mouse_pos());
+ delete_effect_popup->popup();
+}
+
+void EditorAudioBus::_bind_methods() {
+
+ ClassDB::bind_method("update_bus",&EditorAudioBus::update_bus);
+ ClassDB::bind_method("update_send",&EditorAudioBus::update_send);
+ ClassDB::bind_method("_name_changed",&EditorAudioBus::_name_changed);
+ ClassDB::bind_method("_volume_db_changed",&EditorAudioBus::_volume_db_changed);
+ ClassDB::bind_method("_solo_toggled",&EditorAudioBus::_solo_toggled);
+ ClassDB::bind_method("_mute_toggled",&EditorAudioBus::_mute_toggled);
+ ClassDB::bind_method("_bypass_toggled",&EditorAudioBus::_bypass_toggled);
+ ClassDB::bind_method("_name_focus_exit",&EditorAudioBus::_name_focus_exit);
+ ClassDB::bind_method("_send_selected",&EditorAudioBus::_send_selected);
+ ClassDB::bind_method("_effect_edited",&EditorAudioBus::_effect_edited);
+ ClassDB::bind_method("_effect_selected",&EditorAudioBus::_effect_selected);
+ ClassDB::bind_method("_effect_add",&EditorAudioBus::_effect_add);
+ ClassDB::bind_method("_gui_input",&EditorAudioBus::_gui_input);
+ ClassDB::bind_method("_delete_pressed",&EditorAudioBus::_delete_pressed);
+ ClassDB::bind_method("get_drag_data_fw",&EditorAudioBus::get_drag_data_fw);
+ ClassDB::bind_method("can_drop_data_fw",&EditorAudioBus::can_drop_data_fw);
+ ClassDB::bind_method("drop_data_fw",&EditorAudioBus::drop_data_fw);
+ ClassDB::bind_method("_delete_effect_pressed",&EditorAudioBus::_delete_effect_pressed);
+ ClassDB::bind_method("_effect_rmb",&EditorAudioBus::_effect_rmb);
+
+
+
+ ADD_SIGNAL(MethodInfo("duplicate_request"));
+ ADD_SIGNAL(MethodInfo("delete_request"));
+ ADD_SIGNAL(MethodInfo("drop_end_request"));
+ ADD_SIGNAL(MethodInfo("dropped"));
+
+}
+
+EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses) {
+
+ buses=p_buses;
+ updating_bus=false;
+
+ VBoxContainer *vb = memnew( VBoxContainer );
+ add_child(vb);
+
+ set_v_size_flags(SIZE_EXPAND_FILL);
+
+ track_name = memnew( LineEdit );
+ vb->add_child(track_name);
+ track_name->connect("text_entered",this,"_name_changed");
+ track_name->connect("focus_exited",this,"_name_focus_exit");
+
+ HBoxContainer *hbc = memnew( HBoxContainer);
+ vb->add_child(hbc);
+ hbc->add_spacer();
+ solo = memnew( ToolButton );
+ solo->set_text("S");
+ solo->set_toggle_mode(true);
+ solo->set_modulate(Color(0.8,1.2,0.8));
+ solo->set_focus_mode(FOCUS_NONE);
+ solo->connect("pressed",this,"_solo_toggled");
+ hbc->add_child(solo);
+ mute = memnew( ToolButton );
+ mute->set_text("M");
+ mute->set_toggle_mode(true);
+ mute->set_modulate(Color(1.2,0.8,0.8));
+ mute->set_focus_mode(FOCUS_NONE);
+ mute->connect("pressed",this,"_mute_toggled");
+ hbc->add_child(mute);
+ bypass = memnew( ToolButton );
+ bypass->set_text("B");
+ bypass->set_toggle_mode(true);
+ bypass->set_modulate(Color(1.1,1.1,0.8));
+ bypass->set_focus_mode(FOCUS_NONE);
+ bypass->connect("pressed",this,"_bypass_toggled");
+ hbc->add_child(bypass);
+ hbc->add_spacer();
+
+ HBoxContainer *hb = memnew( HBoxContainer );
+ vb->add_child(hb);
+ slider = memnew( VSlider );
+ slider->set_min(-80);
+ slider->set_max(24);
+ slider->set_step(0.1);
+
+ slider->connect("value_changed",this,"_volume_db_changed");
+ hb->add_child(slider);
+ vu_l = memnew( TextureProgress );
+ vu_l->set_fill_mode(TextureProgress::FILL_BOTTOM_TO_TOP);
+ hb->add_child(vu_l);
+ vu_l->set_min(-80);
+ vu_l->set_max(24);
+ vu_l->set_step(0.1);
+
+ vu_r = memnew( TextureProgress );
+ vu_r->set_fill_mode(TextureProgress::FILL_BOTTOM_TO_TOP);
+ hb->add_child(vu_r);
+ vu_r->set_min(-80);
+ vu_r->set_max(24);
+ vu_r->set_step(0.1);
+
+ scale = memnew( TextureRect );
+ hb->add_child(scale);
+
+ //add_child(hb);
+
+ effects = memnew( Tree );
+ effects->set_hide_root(true);
+ effects->set_custom_minimum_size(Size2(0,90)*EDSCALE);
+ effects->set_hide_folding(true);
+ vb->add_child(effects);
+ effects->connect("item_edited",this,"_effect_edited");
+ effects->connect("cell_selected",this,"_effect_selected");
+ effects->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
+ effects->set_drag_forwarding(this);
+ effects->connect("item_rmb_selected",this,"_effect_rmb");
+ effects->set_allow_rmb_select(true);
+
+ send = memnew( OptionButton );
+ send->set_clip_text(true);
+ send->connect("item_selected",this,"_send_selected");
+ vb->add_child(send);
+
+ set_focus_mode(FOCUS_CLICK);
+
+ effect_options = memnew( PopupMenu );
+ effect_options->connect("index_pressed",this,"_effect_add");
+ add_child(effect_options);
+ List<StringName> effects;
+ ClassDB::get_inheriters_from_class("AudioEffect",&effects);
+ effects.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E=effects.front();E;E=E->next()) {
+ if (!ClassDB::can_instance(E->get()))
+ continue;
+
+ Ref<Texture> icon;
+ if (has_icon(E->get(),"EditorIcons")) {
+ icon = get_icon(E->get(),"EditorIcons");
+ }
+ String name = E->get().operator String().replace("AudioEffect","");
+ effect_options->add_item(name);
+ effect_options->set_item_metadata(effect_options->get_item_count()-1,E->get());
+ effect_options->set_item_icon(effect_options->get_item_count()-1,icon);
+ }
+
+ delete_popup = memnew( PopupMenu );
+ delete_popup->add_item("Duplicate");
+ delete_popup->add_item("Delete");
+ add_child(delete_popup);
+ delete_popup->connect("index_pressed",this,"_delete_pressed");
+
+ delete_effect_popup = memnew( PopupMenu );
+ delete_effect_popup->add_item("Delete Effect");
+ add_child(delete_effect_popup);
+ delete_effect_popup->connect("index_pressed",this,"_delete_effect_pressed");
+
+}
+
+
+
+bool EditorAudioBusDrop::can_drop_data(const Point2& p_point,const Variant& p_data) const {
+
+ Dictionary d=p_data;
+ if (d.has("type") && String(d["type"])=="move_audio_bus") {
+ return true;
+ }
+
+ return false;
+}
+void EditorAudioBusDrop::drop_data(const Point2& p_point,const Variant& p_data){
+
+ Dictionary d=p_data;
+ emit_signal("dropped",d["index"],-1);
+
+}
+
+void EditorAudioBusDrop::_bind_methods() {
+
+ ADD_SIGNAL(MethodInfo("dropped"));
+}
+
+EditorAudioBusDrop::EditorAudioBusDrop() {
+
+
+}
+
+
+void EditorAudioBuses::_update_buses() {
+
+ while(bus_hb->get_child_count()>0) {
+ memdelete(bus_hb->get_child(0));
+ }
+
+ drop_end=NULL;
+
+ for(int i=0;i<AudioServer::get_singleton()->get_bus_count();i++) {
+
+ EditorAudioBus *audio_bus = memnew( EditorAudioBus(this) );
+ if (i==0) {
+ audio_bus->set_self_modulate(Color(1,0.9,0.9));
+ }
+ bus_hb->add_child(audio_bus);
+ audio_bus->connect("delete_request",this,"_delete_bus",varray(audio_bus),CONNECT_DEFERRED);
+ audio_bus->connect("duplicate_request",this,"_duplicate_bus",varray(),CONNECT_DEFERRED);
+ audio_bus->connect("drop_end_request",this,"_request_drop_end");
+ audio_bus->connect("dropped",this,"_drop_at_index",varray(),CONNECT_DEFERRED);
+
+
+
+ }
+}
+
+EditorAudioBuses *EditorAudioBuses::register_editor() {
+
+ EditorAudioBuses * audio_buses = memnew( EditorAudioBuses );
+ EditorNode::get_singleton()->add_bottom_panel_item("Audio",audio_buses);
+ return audio_buses;
+}
+
+void EditorAudioBuses::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_READY) {
+ _update_buses();
+ }
+
+ if (p_what==NOTIFICATION_DRAG_END) {
+ if (drop_end) {
+ drop_end->queue_delete();
+ drop_end=NULL;
+ }
+ }
+
+ if (p_what==NOTIFICATION_PROCESS) {
+
+ //check if anything was edited
+ bool edited = AudioServer::get_singleton()->is_edited();
+ for(int i=0;i<AudioServer::get_singleton()->get_bus_count();i++) {
+ for(int j=0;j<AudioServer::get_singleton()->get_bus_effect_count(i);j++) {
+ Ref<AudioEffect> effect = AudioServer::get_singleton()->get_bus_effect(i,j);
+ if (effect->is_edited()) {
+ edited=true;
+ effect->set_edited(false);
+ }
+ }
+ }
+
+ AudioServer::get_singleton()->set_edited(false);
+
+ if (edited) {
+
+ save_timer->start();
+ }
+ }
+
+}
+
+
+void EditorAudioBuses::_add_bus() {
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ //need to simulate new name, so we can undi :(
+ ur->create_action("Add Audio Bus");
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_count",AudioServer::get_singleton()->get_bus_count()+1);
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_count",AudioServer::get_singleton()->get_bus_count());
+ ur->add_do_method(this,"_update_buses");
+ ur->add_undo_method(this,"_update_buses");
+ ur->commit_action();
+
+}
+
+void EditorAudioBuses::_update_bus(int p_index) {
+
+ if (p_index>=bus_hb->get_child_count())
+ return;
+
+ bus_hb->get_child(p_index)->call("update_bus");
+}
+
+void EditorAudioBuses::_update_sends() {
+
+ for(int i=0;i<bus_hb->get_child_count();i++) {
+ bus_hb->get_child(i)->call("update_send");
+ }
+}
+
+void EditorAudioBuses::_delete_bus(Object* p_which) {
+
+ EditorAudioBus *bus = p_which->cast_to<EditorAudioBus>();
+ int index = bus->get_index();
+ if (index==0) {
+ EditorNode::get_singleton()->show_warning("Master bus can't be deleted!");
+ return;
+ }
+
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ ur->create_action("Delete Audio Bus");
+ ur->add_do_method(AudioServer::get_singleton(),"remove_bus",index);
+ ur->add_undo_method(AudioServer::get_singleton(),"add_bus",index);
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_name",index,AudioServer::get_singleton()->get_bus_name(index));
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_volume_db",index,AudioServer::get_singleton()->get_bus_volume_db(index));
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_send",index,AudioServer::get_singleton()->get_bus_send(index));
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_solo",index,AudioServer::get_singleton()->is_bus_solo(index));
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_mute",index,AudioServer::get_singleton()->is_bus_mute(index));
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_bypass_effects",index,AudioServer::get_singleton()->is_bus_bypassing_effects(index));
+ for(int i=0;i<AudioServer::get_singleton()->get_bus_effect_count(index);i++) {
+
+ ur->add_undo_method(AudioServer::get_singleton(),"add_bus_effect",index,AudioServer::get_singleton()->get_bus_effect(index,i));
+ ur->add_undo_method(AudioServer::get_singleton(),"set_bus_effect_enabled",index,i,AudioServer::get_singleton()->is_bus_effect_enabled(index,i));
+ }
+ ur->add_do_method(this,"_update_buses");
+ ur->add_undo_method(this,"_update_buses");
+ ur->commit_action();
+
+}
+
+
+void EditorAudioBuses::_duplicate_bus(int p_which) {
+
+ int add_at_pos = p_which+1;
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Duplicate Audio Bus");
+ ur->add_do_method(AudioServer::get_singleton(),"add_bus",add_at_pos);
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_name",add_at_pos,AudioServer::get_singleton()->get_bus_name(p_which)+" Copy");
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_volume_db",add_at_pos,AudioServer::get_singleton()->get_bus_volume_db(p_which));
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_send",add_at_pos,AudioServer::get_singleton()->get_bus_send(p_which));
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_solo",add_at_pos,AudioServer::get_singleton()->is_bus_solo(p_which));
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_mute",add_at_pos,AudioServer::get_singleton()->is_bus_mute(p_which));
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_bypass_effects",add_at_pos,AudioServer::get_singleton()->is_bus_bypassing_effects(p_which));
+ for(int i=0;i<AudioServer::get_singleton()->get_bus_effect_count(p_which);i++) {
+
+ ur->add_do_method(AudioServer::get_singleton(),"add_bus_effect",add_at_pos,AudioServer::get_singleton()->get_bus_effect(p_which,i));
+ ur->add_do_method(AudioServer::get_singleton(),"set_bus_effect_enabled",add_at_pos,i,AudioServer::get_singleton()->is_bus_effect_enabled(p_which,i));
+ }
+ ur->add_undo_method(AudioServer::get_singleton(),"remove_bus",add_at_pos);
+ ur->add_do_method(this,"_update_buses");
+ ur->add_undo_method(this,"_update_buses");
+ ur->commit_action();
+
+}
+
+void EditorAudioBuses::_request_drop_end() {
+
+ if (!drop_end && bus_hb->get_child_count()) {
+ drop_end = memnew( EditorAudioBusDrop );
+
+ bus_hb->add_child(drop_end);
+ drop_end->set_custom_minimum_size(bus_hb->get_child(0)->cast_to<Control>()->get_size());
+ drop_end->connect("dropped",this,"_drop_at_index",varray(),CONNECT_DEFERRED);
+ }
+}
+
+void EditorAudioBuses::_drop_at_index(int p_bus,int p_index) {
+
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ //need to simulate new name, so we can undi :(
+ ur->create_action("Move Audio Bus");
+ ur->add_do_method(AudioServer::get_singleton(),"move_bus",p_bus,p_index);
+ int final_pos;
+ if (p_index==p_bus) {
+ final_pos=p_bus;
+ } else if (p_index==-1) {
+ final_pos = AudioServer::get_singleton()->get_bus_count()-1;
+ } else if (p_index<p_bus) {
+ final_pos = p_index;
+ } else {
+ final_pos = p_index -1;
+ }
+ ur->add_undo_method(AudioServer::get_singleton(),"move_bus",final_pos,p_bus);
+
+ ur->add_do_method(this,"_update_buses");
+ ur->add_undo_method(this,"_update_buses");
+ ur->commit_action();
+}
+
+void EditorAudioBuses::_server_save() {
+
+ Ref<AudioBusLayout> state = AudioServer::get_singleton()->generate_bus_layout();
+ ResourceSaver::save(edited_path,state);
+
+}
+
+void EditorAudioBuses::_select_layout() {
+
+ EditorNode::get_singleton()->get_filesystem_dock()->select_file(edited_path);
+}
+
+void EditorAudioBuses::_save_as_layout() {
+
+ file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_dialog->set_title(TTR("Save Audio Bus Layout As.."));
+ file_dialog->set_current_path(edited_path);
+ file_dialog->popup_centered_ratio();
+ new_layout=false;
+}
+
+
+void EditorAudioBuses::_new_layout() {
+
+ file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_dialog->set_title(TTR("Location for New Layout.."));
+ file_dialog->set_current_path(edited_path);
+ file_dialog->popup_centered_ratio();
+ new_layout=true;
+}
+
+void EditorAudioBuses::_load_layout() {
+
+ file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file_dialog->set_title(TTR("Open Audio Bus Layout"));
+ file_dialog->set_current_path(edited_path);
+ file_dialog->popup_centered_ratio();
+ new_layout=false;
+}
+
+
+void EditorAudioBuses::_load_default_layout() {
+
+
+ Ref<AudioBusLayout> state = ResourceLoader::load("res://default_bus_layout.tres");
+ if (state.is_null()) {
+ EditorNode::get_singleton()->show_warning("There is no 'res://default_bus_layout.tres' file.");
+ return;
+ }
+
+ edited_path="res://default_bus_layout.tres";
+ file->set_text(edited_path.get_file());
+ AudioServer::get_singleton()->set_bus_layout(state);
+ _update_buses();
+ EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ call_deferred("_select_layout");
+}
+
+void EditorAudioBuses::_file_dialog_callback(const String& p_string) {
+
+ if (file_dialog->get_mode()==EditorFileDialog::MODE_OPEN_FILE) {
+ Ref<AudioBusLayout> state = ResourceLoader::load(p_string);
+ if (state.is_null()) {
+ EditorNode::get_singleton()->show_warning("Invalid file, not an audio bus layout.");
+ return;
+ }
+
+ edited_path=p_string;
+ file->set_text(p_string.get_file());
+ AudioServer::get_singleton()->set_bus_layout(state);
+ _update_buses();
+ EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ call_deferred("_select_layout");
+
+ } else if (file_dialog->get_mode()==EditorFileDialog::MODE_SAVE_FILE) {
+
+ if (new_layout) {
+ Ref<AudioBusLayout> empty_state;
+ empty_state.instance();
+ AudioServer::get_singleton()->set_bus_layout(empty_state);
+ }
+
+ Error err = ResourceSaver::save(p_string,AudioServer::get_singleton()->generate_bus_layout());
+
+ if (err!=OK) {
+ EditorNode::get_singleton()->show_warning("Error saving file: "+p_string);
+ return;
+ }
+
+ edited_path=p_string;
+ file->set_text(p_string.get_file());
+ _update_buses();
+ EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ call_deferred("_select_layout");
+ }
+
+}
+
+void EditorAudioBuses::_bind_methods() {
+
+ ClassDB::bind_method("_add_bus",&EditorAudioBuses::_add_bus);
+ ClassDB::bind_method("_update_buses",&EditorAudioBuses::_update_buses);
+ ClassDB::bind_method("_update_bus",&EditorAudioBuses::_update_bus);
+ ClassDB::bind_method("_update_sends",&EditorAudioBuses::_update_sends);
+ ClassDB::bind_method("_delete_bus",&EditorAudioBuses::_delete_bus);
+ ClassDB::bind_method("_request_drop_end",&EditorAudioBuses::_request_drop_end);
+ ClassDB::bind_method("_drop_at_index",&EditorAudioBuses::_drop_at_index);
+ ClassDB::bind_method("_server_save",&EditorAudioBuses::_server_save);
+ ClassDB::bind_method("_select_layout",&EditorAudioBuses::_select_layout);
+ ClassDB::bind_method("_save_as_layout",&EditorAudioBuses::_save_as_layout);
+ ClassDB::bind_method("_load_layout",&EditorAudioBuses::_load_layout);
+ ClassDB::bind_method("_load_default_layout",&EditorAudioBuses::_load_default_layout);
+ ClassDB::bind_method("_new_layout",&EditorAudioBuses::_new_layout);
+ ClassDB::bind_method("_duplicate_bus",&EditorAudioBuses::_duplicate_bus);
+
+ ClassDB::bind_method("_file_dialog_callback",&EditorAudioBuses::_file_dialog_callback);
+}
+
+EditorAudioBuses::EditorAudioBuses()
+{
+
+ drop_end = NULL;
+ top_hb = memnew( HBoxContainer );
+ add_child(top_hb);
+
+ add = memnew( Button );
+ top_hb->add_child(add);;
+ add->set_text(TTR("Add Bus"));
+
+ add->connect("pressed",this,"_add_bus");
+
+
+
+ top_hb->add_spacer();
+
+ file = memnew( ToolButton );
+ file->set_text("default_bus_layout.tres");
+ top_hb->add_child(file);
+ file->connect("pressed",this,"_select_layout");
+
+ load = memnew( Button );
+ load->set_text(TTR("Load"));
+ top_hb->add_child(load);
+ load->connect("pressed",this,"_load_layout");
+
+ save_as = memnew( Button );
+ save_as->set_text(TTR("Save As"));
+ top_hb->add_child(save_as);
+ save_as->connect("pressed",this,"_save_as_layout");
+
+ _default = memnew( Button );
+ _default->set_text(TTR("Default"));
+ top_hb->add_child(_default);
+ _default->connect("pressed",this,"_load_default_layout");
+
+ _new = memnew( Button );
+ _new->set_text(TTR("Create"));
+ top_hb->add_child(_new);
+ _new->connect("pressed",this,"_new_layout");
+
+ bus_scroll = memnew( ScrollContainer );
+ bus_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
+ bus_scroll->set_enable_h_scroll(true);
+ bus_scroll->set_enable_v_scroll(false);
+ add_child(bus_scroll);
+ bus_hb = memnew( HBoxContainer );
+ bus_scroll->add_child(bus_hb);
+
+ save_timer=memnew(Timer);
+ save_timer->set_wait_time(0.8);
+ save_timer->set_one_shot(true);
+ add_child(save_timer);
+ save_timer->connect("timeout",this,"_server_save");
+
+ set_v_size_flags(SIZE_EXPAND_FILL);
+
+
+ edited_path = "res://default_bus_layout.tres";
+
+ file_dialog = memnew( EditorFileDialog );
+ List<String> ext;
+ ResourceLoader::get_recognized_extensions_for_type("AudioServerState",&ext);
+ for (List<String>::Element *E=ext.front();E;E=E->next()) {
+ file_dialog->add_filter("*."+E->get()+"; Audio Bus State");
+ }
+ add_child(file_dialog);
+ file_dialog->connect("file_selected",this,"_file_dialog_callback");
+
+ set_process(true);
+
+}
+void EditorAudioBuses::open_layout(const String& p_path) {
+
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
+
+ Ref<AudioBusLayout> state = ResourceLoader::load(p_path);
+ if (state.is_null()) {
+ EditorNode::get_singleton()->show_warning("Invalid file, not an audio bus layout.");
+ return;
+ }
+
+ edited_path=p_path;
+ file->set_text(p_path.get_file());
+ AudioServer::get_singleton()->set_bus_layout(state);
+ _update_buses();
+ EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ call_deferred("_select_layout");
+}
+
+void AudioBusesEditorPlugin::edit(Object *p_node) {
+
+ if (p_node->cast_to<AudioBusLayout>()) {
+
+ String path = p_node->cast_to<AudioBusLayout>()->get_path();
+ if (path.is_resource_file()) {
+ audio_bus_editor->open_layout(path);
+ }
+ }
+}
+
+bool AudioBusesEditorPlugin::handles(Object *p_node) const {
+
+ return (p_node->cast_to<AudioBusLayout>()!=NULL);
+}
+
+void AudioBusesEditorPlugin::make_visible(bool p_visible){
+
+
+}
+
+AudioBusesEditorPlugin::AudioBusesEditorPlugin(EditorAudioBuses *p_node) {
+
+ audio_bus_editor=p_node;
+}
+
+AudioBusesEditorPlugin::~AudioBusesEditorPlugin() {
+
+}
diff --git a/tools/editor/editor_audio_buses.h b/tools/editor/editor_audio_buses.h
new file mode 100644
index 0000000000..e44f8cd579
--- /dev/null
+++ b/tools/editor/editor_audio_buses.h
@@ -0,0 +1,186 @@
+#ifndef EDITORAUDIOBUSES_H
+#define EDITORAUDIOBUSES_H
+
+
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/tool_button.h"
+#include "scene/gui/scroll_container.h"
+#include "scene/gui/panel_container.h"
+#include "scene/gui/slider.h"
+#include "scene/gui/texture_progress.h"
+#include "scene/gui/texture_rect.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/tree.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/panel.h"
+#include "tools/editor/editor_file_dialog.h"
+#include "editor_plugin.h"
+
+class EditorAudioBuses;
+
+class EditorAudioBus : public PanelContainer {
+
+ GDCLASS( EditorAudioBus, PanelContainer )
+
+ bool prev_active;
+ float peak_l;
+ float peak_r;
+
+ Ref<Texture> disabled_vu;
+ LineEdit *track_name;
+ VSlider *slider;
+ TextureProgress *vu_l;
+ TextureProgress *vu_r;
+ TextureRect *scale;
+ OptionButton *send;
+
+ PopupMenu *effect_options;
+ PopupMenu *delete_popup;
+ PopupMenu *delete_effect_popup;
+
+ Button *solo;
+ Button *mute;
+ Button *bypass;
+
+ Tree *effects;
+
+ bool updating_bus;
+
+ void _gui_input(const InputEvent& p_event);
+ void _delete_pressed(int p_option);
+
+ void _name_changed(const String& p_new_name);
+ void _name_focus_exit() { _name_changed(track_name->get_text()); }
+ void _volume_db_changed(float p_db);
+ void _solo_toggled();
+ void _mute_toggled();
+ void _bypass_toggled();
+ void _send_selected(int p_which);
+ void _effect_edited();
+ void _effect_add(int p_which);
+ void _effect_selected();
+ void _delete_effect_pressed(int p_option);
+ void _effect_rmb(const Vector2& p_pos);
+
+
+ virtual Variant get_drag_data(const Point2& p_point);
+ virtual bool can_drop_data(const Point2& p_point,const Variant& p_data) const;
+ virtual void drop_data(const Point2& p_point,const Variant& p_data);
+
+
+ Variant get_drag_data_fw(const Point2& p_point,Control* p_from);
+ bool can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const;
+ void drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from);
+
+friend class EditorAudioBuses;
+
+ EditorAudioBuses *buses;
+
+protected:
+
+ static void _bind_methods();
+ void _notification(int p_what);
+public:
+
+ void update_bus();
+ void update_send();
+
+ EditorAudioBus(EditorAudioBuses *p_buses=NULL);
+};
+
+
+class EditorAudioBusDrop : public Panel {
+
+ GDCLASS(EditorAudioBusDrop,Panel);
+
+ virtual bool can_drop_data(const Point2& p_point,const Variant& p_data) const;
+ virtual void drop_data(const Point2& p_point,const Variant& p_data);
+protected:
+
+ static void _bind_methods();
+public:
+
+ EditorAudioBusDrop();
+};
+
+class EditorAudioBuses : public VBoxContainer {
+
+ GDCLASS(EditorAudioBuses,VBoxContainer)
+
+ HBoxContainer *top_hb;
+
+ Button *add;
+ ScrollContainer *bus_scroll;
+ HBoxContainer *bus_hb;
+
+ EditorAudioBusDrop *drop_end;
+
+ Button *file;
+ Button *load;
+ Button *save_as;
+ Button *_default;
+ Button *_new;
+
+ Timer *save_timer;
+ String edited_path;
+
+ void _add_bus();
+ void _update_buses();
+ void _update_bus(int p_index);
+ void _update_sends();
+
+ void _delete_bus(Object* p_which);
+ void _duplicate_bus(int p_which);
+
+
+ void _request_drop_end();
+ void _drop_at_index(int p_bus,int p_index);
+
+ void _server_save();
+
+ void _select_layout();
+ void _load_layout();
+ void _save_as_layout();
+ void _load_default_layout();
+ void _new_layout();
+
+ EditorFileDialog *file_dialog;
+ bool new_layout;
+
+ void _file_dialog_callback(const String& p_string);
+
+protected:
+
+ static void _bind_methods();
+ void _notification(int p_what);
+public:
+
+ void open_layout(const String& p_path);
+
+ static EditorAudioBuses* register_editor();
+
+ EditorAudioBuses();
+};
+
+
+
+class AudioBusesEditorPlugin : public EditorPlugin {
+
+ GDCLASS( AudioBusesEditorPlugin, EditorPlugin );
+
+ EditorAudioBuses *audio_bus_editor;
+public:
+
+ virtual String get_name() const { return "SampleLibrary"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_node);
+ virtual bool handles(Object *p_node) const;
+ virtual void make_visible(bool p_visible);
+
+ AudioBusesEditorPlugin(EditorAudioBuses *p_node);
+ ~AudioBusesEditorPlugin();
+
+};
+
+#endif // EDITORAUDIOBUSES_H
diff --git a/tools/editor/editor_data.cpp b/tools/editor/editor_data.cpp
index 44de1836b6..ef839d7e74 100644
--- a/tools/editor/editor_data.cpp
+++ b/tools/editor/editor_data.cpp
@@ -769,26 +769,6 @@ Dictionary EditorData::restore_edited_scene_state(EditorSelection *p_selection,
}
-void EditorData::set_edited_scene_import_metadata(Ref<ResourceImportMetadata> p_mdata) {
-
- ERR_FAIL_INDEX(current_edited_scene,edited_scene.size());
- edited_scene[current_edited_scene].medatata=p_mdata;
-
-}
-
-Ref<ResourceImportMetadata> EditorData::get_edited_scene_import_metadata(int idx) const{
-
- ERR_FAIL_INDEX_V(current_edited_scene,edited_scene.size(),Ref<ResourceImportMetadata>());
- if(idx<0) {
- return edited_scene[current_edited_scene].medatata;
- } else {
- ERR_FAIL_INDEX_V(idx,edited_scene.size(),Ref<ResourceImportMetadata>());
- return edited_scene[idx].medatata;
- }
-}
-
-
-
void EditorData::clear_edited_scenes() {
for(int i=0;i<edited_scene.size();i++) {
diff --git a/tools/editor/editor_data.h b/tools/editor/editor_data.h
index f0bc5983a2..fce606f722 100644
--- a/tools/editor/editor_data.h
+++ b/tools/editor/editor_data.h
@@ -129,7 +129,6 @@ private:
struct EditedScene {
Node* root;
Dictionary editor_states;
- Ref<ResourceImportMetadata> medatata;
List<Node*> selection;
Vector<EditorHistory::History> history_stored;
int history_current;
@@ -184,8 +183,6 @@ public:
void remove_scene(int p_idx);
void set_edited_scene(int p_idx);
void set_edited_scene_root(Node* p_root);
- void set_edited_scene_import_metadata(Ref<ResourceImportMetadata> p_mdata);
- Ref<ResourceImportMetadata> get_edited_scene_import_metadata(int p_idx = -1) const;
int get_edited_scene() const;
Node* get_edited_scene_root(int p_idx = -1);
int get_edited_scene_count() const;
diff --git a/tools/editor/editor_file_system.cpp b/tools/editor/editor_file_system.cpp
index 39869beef4..1d7d58591c 100644
--- a/tools/editor/editor_file_system.cpp
+++ b/tools/editor/editor_file_system.cpp
@@ -34,8 +34,10 @@
#include "os/file_access.h"
#include "editor_node.h"
#include "io/resource_saver.h"
+#include "io/resource_import.h"
#include "editor_settings.h"
#include "editor_resource_preview.h"
+#include "variant_parser.h"
EditorFileSystem *EditorFileSystem::singleton=NULL;
@@ -115,74 +117,12 @@ String EditorFileSystemDirectory::get_file_path(int p_idx) const {
return "res://"+file;
}
-bool EditorFileSystemDirectory::get_file_meta(int p_idx) const {
-
- ERR_FAIL_INDEX_V(p_idx,files.size(),"");
- return files[p_idx]->meta.enabled;
-}
Vector<String> EditorFileSystemDirectory::get_file_deps(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>());
- return files[p_idx]->meta.deps;
-
-}
-Vector<String> EditorFileSystemDirectory::get_missing_sources(int p_idx) const {
-
- ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>());
- Vector<String> missing;
- for(int i=0;i<files[p_idx]->meta.sources.size();i++) {
- if (files[p_idx]->meta.sources[i].missing)
- missing.push_back(files[p_idx]->meta.sources[i].path);
- }
-
- return missing;
-
-
-}
-bool EditorFileSystemDirectory::is_missing_sources(int p_idx) const {
-
- ERR_FAIL_INDEX_V(p_idx,files.size(),false);
- for(int i=0;i<files[p_idx]->meta.sources.size();i++) {
- if (files[p_idx]->meta.sources[i].missing)
- return true;
- }
-
- return false;
-}
-
-bool EditorFileSystemDirectory::have_sources_changed(int p_idx) const {
-
- ERR_FAIL_INDEX_V(p_idx,files.size(),false);
- return files[p_idx]->meta.sources_changed;
-
-}
-
-int EditorFileSystemDirectory::get_source_count(int p_idx) const {
-
- ERR_FAIL_INDEX_V(p_idx,files.size(),0);
- if (!files[p_idx]->meta.enabled)
- return 0;
- return files[p_idx]->meta.sources.size();
-}
-String EditorFileSystemDirectory::get_source_file(int p_idx,int p_source) const {
-
- ERR_FAIL_INDEX_V(p_idx,files.size(),String());
- ERR_FAIL_INDEX_V(p_source,files[p_idx]->meta.sources.size(),String());
- if (!files[p_idx]->meta.enabled)
- return String();
-
- return files[p_idx]->meta.sources[p_source].path;
-
-}
-bool EditorFileSystemDirectory::is_source_file_missing(int p_idx,int p_source) const {
-
- ERR_FAIL_INDEX_V(p_idx,files.size(),false);
- ERR_FAIL_INDEX_V(p_source,files[p_idx]->meta.sources.size(),false);
- if (!files[p_idx]->meta.enabled)
- return false;
+ return files[p_idx]->deps;
- return files[p_idx]->meta.sources[p_source].missing;
}
@@ -210,7 +150,6 @@ void EditorFileSystemDirectory::_bind_methods() {
ClassDB::bind_method(_MD("get_file","idx"),&EditorFileSystemDirectory::get_file);
ClassDB::bind_method(_MD("get_file_path","idx"),&EditorFileSystemDirectory::get_file_path);
ClassDB::bind_method(_MD("get_file_type","idx"),&EditorFileSystemDirectory::get_file_type);
- ClassDB::bind_method(_MD("is_missing_sources","idx"),&EditorFileSystemDirectory::is_missing_sources);
ClassDB::bind_method(_MD("get_name"),&EditorFileSystemDirectory::get_name);
ClassDB::bind_method(_MD("get_path"),&EditorFileSystemDirectory::get_path);
ClassDB::bind_method(_MD("get_parent:EditorFileSystemDirectory"),&EditorFileSystemDirectory::get_parent);
@@ -244,39 +183,6 @@ EditorFileSystemDirectory::~EditorFileSystemDirectory() {
-
-EditorFileSystemDirectory::ImportMeta EditorFileSystem::_get_meta(const String& p_path) {
-
- Ref<ResourceImportMetadata> imd = ResourceLoader::load_import_metadata(p_path);
- EditorFileSystemDirectory::ImportMeta m;
- if (imd.is_null()) {
- m.enabled=false;
- m.sources_changed=false;
- } else {
- m.enabled=true;
- m.sources_changed=false;
-
- for(int i=0;i<imd->get_source_count();i++) {
- EditorFileSystemDirectory::ImportMeta::Source s;
- s.path=imd->get_source_path(i);
- s.md5=imd->get_source_md5(i);
- s.modified_time=0;
- s.missing=false;
- m.sources.push_back(s);
- }
- m.import_editor=imd->get_editor();
- }
-
- List<String> deps;
- ResourceLoader::get_dependencies(p_path,&deps);
- for(List<String>::Element *E=deps.front();E;E=E->next()) {
- m.deps.push_back(E->get());
- }
-
- return m;
-}
-
-
void EditorFileSystem::_scan_filesystem() {
ERR_FAIL_COND(!scanning || new_filesystem);
@@ -289,7 +195,7 @@ void EditorFileSystem::_scan_filesystem() {
String project=GlobalConfig::get_singleton()->get_resource_path();
- String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache");
+ String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache2");
FileAccess *f =FileAccess::open(fscache,FileAccess::READ);
if (f) {
@@ -319,30 +225,14 @@ void EditorFileSystem::_scan_filesystem() {
FileCache fc;
fc.type=split[1];
fc.modification_time=split[2].to_int64();
- String meta = split[3].strip_edges();
- fc.meta.enabled=false;
- if (meta.find("<>")!=-1){
- Vector<String> spl = meta.split("<>");
- int sc = spl.size()-1;
- if (sc%3==0){
- fc.meta.enabled=true;
- fc.meta.import_editor=spl[0];
- fc.meta.sources.resize(sc/3);
- for(int i=0;i<fc.meta.sources.size();i++) {
- fc.meta.sources[i].path=spl[1+i*3+0];
- fc.meta.sources[i].md5=spl[1+i*3+1];
- fc.meta.sources[i].modified_time=spl[1+i*3+2].to_int64();
- }
+ fc.import_modification_time = split[3].to_int64();
- }
-
- }
String deps = split[4].strip_edges();
if (deps.length()) {
Vector<String> dp = deps.split("<>");
for(int i=0;i<dp.size();i++) {
String path=dp[i];
- fc.meta.deps.push_back(path);
+ fc.deps.push_back(path);
}
}
@@ -390,7 +280,14 @@ void EditorFileSystem::_scan_filesystem() {
}
+void EditorFileSystem::_save_filesystem_cache() {
+ String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache2");
+ FileAccess *f=FileAccess::open(fscache,FileAccess::WRITE);
+ _save_filesystem_cache(filesystem,f);
+ f->close();
+ memdelete(f);
+}
void EditorFileSystem::_thread_func(void *_userdata) {
@@ -405,6 +302,8 @@ bool EditorFileSystem::_update_scan_actions() {
bool fs_changed=false;
+ Vector<String> reimports;
+
for (List<ItemAction>::Element *E=scan_actions.front();E;E=E->next()) {
ItemAction&ia = E->get();
@@ -469,18 +368,25 @@ bool EditorFileSystem::_update_scan_actions() {
//print_line("*ACTION REMOVE FILE: "+ia.file);
} break;
- case ItemAction::ACTION_FILE_SOURCES_CHANGED: {
+ case ItemAction::ACTION_FILE_REIMPORT: {
+
int idx = ia.dir->find_file_index(ia.file);
ERR_CONTINUE(idx==-1);
String full_path = ia.dir->get_file_path(idx);
- sources_changed.push_back(full_path);
+ reimports.push_back(full_path);
+ fs_changed=true;
} break;
}
}
+
+ if (reimports.size()) {
+ reimport_files(reimports);
+
+ }
scan_actions.clear();
return fs_changed;
@@ -492,9 +398,10 @@ void EditorFileSystem::scan() {
if (false /*&& bool(Globals::get_singleton()->get("debug/disable_scan"))*/)
return;
- if (scanning || scanning_sources|| thread)
+ if (scanning || scanning_changes|| thread)
return;
+ _update_extensions();
abort_scan=false;
if (!use_threads) {
@@ -529,42 +436,6 @@ void EditorFileSystem::scan() {
}
-bool EditorFileSystem::_check_meta_sources(EditorFileSystemDirectory::ImportMeta & p_meta) {
-
- if (p_meta.enabled) {
-
- for(int j=0;j<p_meta.sources.size();j++) {
-
-
- String src = EditorImportPlugin::expand_source_path(p_meta.sources[j].path);
-
- if (!FileAccess::exists(src)) {
- p_meta.sources[j].missing=true;
- continue;
- }
-
- p_meta.sources[j].missing=false;
-
- uint64_t mt = FileAccess::get_modified_time(src);
-
- if (mt!=p_meta.sources[j].modified_time) {
- //scan
- String md5 = FileAccess::get_md5(src);
- //print_line("checking: "+src);
- //print_line("md5: "+md5);
- //print_line("vs: "+p_meta.sources[j].md5);
- if (md5!=p_meta.sources[j].md5) {
- //really changed
- return true;
- }
- p_meta.sources[j].modified_time=mt;
- }
- }
- }
-
- return false;
-}
-
void EditorFileSystem::ScanProgress::update(int p_current,int p_total) const {
float ratio = low + ((hi-low)/p_total)*p_current;
@@ -580,9 +451,75 @@ EditorFileSystem::ScanProgress EditorFileSystem::ScanProgress::get_sub(int p_cur
sp.hi=slice;
return sp;
-
}
+bool EditorFileSystem::_check_missing_imported_files(const String& p_path) {
+
+ if (!reimport_on_missing_imported_files)
+ return true;
+
+ Error err;
+ FileAccess *f= FileAccess::open(p_path+".import",FileAccess::READ,&err);
+
+ if (!f) {
+ print_line("could not open import for "+p_path);
+ return false;
+ }
+
+ VariantParser::StreamFile stream;
+ stream.f=f;
+
+ String assign;
+ Variant value;
+ VariantParser::Tag next_tag;
+
+ int lines=0;
+ String error_text;
+
+ List<String> to_check;
+
+ while(true) {
+
+ assign=Variant();
+ next_tag.fields.clear();
+ next_tag.name=String();
+
+ err = VariantParser::parse_tag_assign_eof(&stream,lines,error_text,next_tag,assign,value,NULL,true);
+ if (err==ERR_FILE_EOF) {
+ memdelete(f);
+ return OK;
+ }
+ else if (err!=OK) {
+ ERR_PRINTS("ResourceFormatImporter::load - "+p_path+".import:"+itos(lines)+" error: "+error_text);
+ memdelete(f);
+ return false;
+ }
+
+ if (assign!=String()) {
+ if (assign.begins_with("path")) {
+ to_check.push_back(value);
+ } else if (assign=="files") {
+ Array fa = value;
+ for(int i=0;i<fa.size();i++) {
+ to_check.push_back(fa[i]);
+ }
+ }
+
+ } else if (next_tag.name!="remap" && next_tag.name!="deps") {
+ break;
+ }
+ }
+
+ memdelete(f);
+
+ for (List<String>::Element *E=to_check.front();E;E=E->next()) {
+ if (!FileAccess::exists(E->get())) {
+ print_line("missing "+E->get()+", reimport" );
+ return false;
+ }
+ }
+ return true;
+}
void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir,DirAccess *da,const ScanProgress& p_progress) {
@@ -671,9 +608,11 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir,DirAccess
for (List<String>::Element*E=files.front();E;E=E->next(),idx++) {
+
String ext = E->get().get_extension().to_lower();
- if (!valid_extensions.has(ext))
+ if (!valid_extensions.has(ext)) {
continue; //invalid
+ }
EditorFileSystemDirectory::FileInfo *fi = memnew( EditorFileSystemDirectory::FileInfo );
fi->file=E->get();
@@ -683,32 +622,45 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir,DirAccess
FileCache *fc = file_cache.getptr(path);
uint64_t mt = FileAccess::get_modified_time(path);
- if (fc && fc->modification_time == mt) {
+ if (import_extensions.has(ext)) {
- fi->meta=fc->meta;
- fi->type=fc->type;
- fi->modified_time=fc->modification_time;
- } else {
- fi->meta=_get_meta(path);
- fi->type=ResourceLoader::get_resource_type(path);
- fi->modified_time=mt;
+ //is imported
+ uint64_t import_mt=0;
+ if (FileAccess::exists(path+".import")) {
+ import_mt=FileAccess::get_modified_time(path+".import");
+ }
- }
+ if (fc && fc->modification_time==mt && fc->import_modification_time==import_mt && _check_missing_imported_files(path)) {
+
+ fi->type=fc->type;
+ fi->modified_time=fc->modification_time;
+ fi->import_modified_time=fc->import_modification_time;
+
+ } else {
+
+ print_line("REIMPORT BECAUSE: time changed");
+ fi->type=ResourceFormatImporter::get_singleton()->get_resource_type(path);
+ fi->modified_time=0;
+ fi->import_modified_time=0;
- if (fi->meta.enabled) {
- if (_check_meta_sources(fi->meta)) {
ItemAction ia;
- ia.action=ItemAction::ACTION_FILE_SOURCES_CHANGED;
+ ia.action=ItemAction::ACTION_FILE_REIMPORT;
ia.dir=p_dir;
ia.file=E->get();
scan_actions.push_back(ia);
- fi->meta.sources_changed=true;
- } else {
- fi->meta.sources_changed=false;
}
-
} else {
- fi->meta.sources_changed=true;
+ //not imported, so just update type if changed
+ if (fc && fc->modification_time == mt) {
+
+ fi->type=fc->type;
+ fi->modified_time=fc->modification_time;
+ fi->import_modified_time=0;
+ } else {
+ fi->type=ResourceLoader::get_resource_type(path);
+ fi->modified_time=mt;
+ fi->import_modified_time=0;
+ }
}
p_dir->files.push_back(fi);
@@ -718,11 +670,13 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir,DirAccess
}
+
void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir,const ScanProgress& p_progress) {
uint64_t current_mtime = FileAccess::get_modified_time(p_dir->get_path());
bool updated_dir=false;
+ String cd = p_dir->get_path();
//print_line("dir: "+p_dir->get_path()+" MODTIME: "+itos(p_dir->modified_time)+" CTIME: "+itos(current_mtime));
@@ -747,7 +701,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir,const S
//then scan files and directories and check what's different
DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- String cd = p_dir->get_path();
+
da->change_dir(cd);
da->list_dir_begin();
while (true) {
@@ -803,7 +757,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir,const S
String path = cd.plus_file(fi->file);
fi->modified_time=FileAccess::get_modified_time(path);
- fi->meta=_get_meta(path);
+ fi->import_modified_time=0;
fi->type=ResourceLoader::get_resource_type(path);
{
@@ -813,19 +767,18 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir,const S
ia.file=f;
ia.new_file=fi;
scan_actions.push_back(ia);
- }
- //take the chance and scan sources
- if (_check_meta_sources(fi->meta)) {
+ }
+
+ if (import_extensions.has(ext)) {
+ //if it can be imported, and it was added, it needs to be reimported
+ print_line("REIMPORT: file was not found before, reimport");
ItemAction ia;
- ia.action=ItemAction::ACTION_FILE_SOURCES_CHANGED;
+ ia.action=ItemAction::ACTION_FILE_REIMPORT;
ia.dir=p_dir;
ia.file=f;
scan_actions.push_back(ia);
- fi->meta.sources_changed=true;
- } else {
- fi->meta.sources_changed=false;
}
} else {
@@ -855,15 +808,42 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir,const S
}
- if (_check_meta_sources(p_dir->files[i]->meta)) {
- ItemAction ia;
- ia.action=ItemAction::ACTION_FILE_SOURCES_CHANGED;
- ia.dir=p_dir;
- ia.file=p_dir->files[i]->file;
- scan_actions.push_back(ia);
- p_dir->files[i]->meta.sources_changed=true;
- } else {
- p_dir->files[i]->meta.sources_changed=false;
+ if (import_extensions.has(p_dir->files[i]->file.get_extension().to_lower())) {
+ //check here if file must be imported or not
+
+ String path = cd.plus_file(p_dir->files[i]->file);
+
+ uint64_t mt = FileAccess::get_modified_time(path);
+
+ bool reimport=false;
+
+ if (mt!=p_dir->files[i]->modified_time) {
+ print_line("REIMPORT: modified time changed, reimport");
+ reimport=true; //it was modified, must be reimported.
+ } else if (!FileAccess::exists(path+".import")) {
+ print_line("REIMPORT: no .import exists, reimport");
+ reimport=true; //no .import file, obviously reimport
+ } else {
+
+ uint64_t import_mt=FileAccess::get_modified_time(path+".import");
+ if (import_mt!=p_dir->files[i]->import_modified_time) {
+ print_line("REIMPORT: import modified changed, reimport");
+ reimport=true;
+ } else if (!_check_missing_imported_files(path)) {
+ print_line("REIMPORT: imported files removed");
+ reimport=true;
+ }
+ }
+
+ if (reimport) {
+
+ ItemAction ia;
+ ia.action=ItemAction::ACTION_FILE_REIMPORT;
+ ia.dir=p_dir;
+ ia.file=p_dir->files[i]->file;
+ scan_actions.push_back(ia);
+ }
+
}
EditorResourcePreview::get_singleton()->check_for_invalidation(p_dir->get_file_path(i));
@@ -896,7 +876,7 @@ void EditorFileSystem::_thread_func_sources(void *_userdata) {
sp.low=0;
efs->_scan_fs_changes(efs->filesystem,sp);
}
- efs->scanning_sources_done=true;
+ efs->scanning_changes_done=true;
}
void EditorFileSystem::get_changed_sources(List<String> *r_changed) {
@@ -904,14 +884,15 @@ void EditorFileSystem::get_changed_sources(List<String> *r_changed) {
*r_changed=sources_changed;
}
-void EditorFileSystem::scan_sources() {
+void EditorFileSystem::scan_changes() {
- if (scanning || scanning_sources|| thread)
+ if (scanning || scanning_changes|| thread)
return;
+ _update_extensions();
sources_changed.clear();
- scanning_sources=true;
- scanning_sources_done=false;
+ scanning_changes=true;
+ scanning_changes_done=false;
abort_scan=false;
@@ -927,8 +908,8 @@ void EditorFileSystem::scan_sources() {
if (_update_scan_actions())
emit_signal("filesystem_changed");
}
- scanning_sources=false;
- scanning_sources_done=true;
+ scanning_changes=false;
+ scanning_changes_done=true;
emit_signal("sources_changed",sources_changed.size()>0);
} else {
@@ -983,11 +964,11 @@ void EditorFileSystem::_notification(int p_what) {
if (use_threads) {
- if (scanning_sources) {
+ if (scanning_changes) {
- if (scanning_sources_done) {
+ if (scanning_changes_done) {
- scanning_sources=false;
+ scanning_changes=false;
set_process(false);
@@ -1049,22 +1030,13 @@ void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory*p_dir,Fi
for(int i=0;i<p_dir->files.size();i++) {
- String s=p_dir->files[i]->file+"::"+p_dir->files[i]->type+"::"+String::num(p_dir->files[i]->modified_time)+"::";
- if (p_dir->files[i]->meta.enabled) {
- s+=p_dir->files[i]->meta.import_editor;
- for(int j=0;j<p_dir->files[i]->meta.sources.size();j++){
- s+="<>"+p_dir->files[i]->meta.sources[j].path;
- s+="<>"+p_dir->files[i]->meta.sources[j].md5;
- s+="<>"+String::num(p_dir->files[i]->meta.sources[j].modified_time);
-
- }
- }
+ String s=p_dir->files[i]->file+"::"+p_dir->files[i]->type+"::"+itos(p_dir->files[i]->modified_time)+"::"+itos(p_dir->files[i]->import_modified_time);
s+="::";
- for(int j=0;j<p_dir->files[i]->meta.deps.size();j++) {
+ for(int j=0;j<p_dir->files[i]->deps.size();j++) {
if (j>0)
s+="<>";
- s+=p_dir->files[i]->meta.deps[j];
+ s+=p_dir->files[i]->deps[j];
}
p_file->store_line(s);
@@ -1257,35 +1229,9 @@ void EditorFileSystem::_resource_saved(const String& p_path){
}
-String EditorFileSystem::_find_first_from_source(EditorFileSystemDirectory* p_dir,const String &p_src) const {
-
- for(int i=0;i<p_dir->files.size();i++) {
- for(int j=0;j<p_dir->files[i]->meta.sources.size();j++) {
-
- if (p_dir->files[i]->meta.sources[j].path==p_src)
- return p_dir->get_file_path(i);
- }
- }
-
- for(int i=0;i<p_dir->subdirs.size();i++) {
-
- String ret = _find_first_from_source(p_dir->subdirs[i],p_src);
- if (ret.length()>0)
- return ret;
- }
-
- return String();
-}
-
-String EditorFileSystem::find_resource_from_source(const String& p_path) const {
- if (filesystem)
- return _find_first_from_source(filesystem,p_path);
- return String();
-}
-
void EditorFileSystem::update_file(const String& p_file) {
EditorFileSystemDirectory *fs=NULL;
@@ -1335,7 +1281,7 @@ void EditorFileSystem::update_file(const String& p_file) {
//print_line("UPDATING: "+p_file);
fs->files[cpos]->type=type;
fs->files[cpos]->modified_time=FileAccess::get_modified_time(p_file);
- fs->files[cpos]->meta=_get_meta(p_file);
+ fs->files[cpos]->import_modified_time=0;
EditorResourcePreview::get_singleton()->call_deferred("check_for_invalidation",p_file);
call_deferred("emit_signal","filesystem_changed"); //update later
@@ -1343,6 +1289,148 @@ void EditorFileSystem::update_file(const String& p_file) {
}
+void EditorFileSystem::_reimport_file(const String& p_file) {
+
+ print_line("REIMPORTING: "+p_file);
+
+ EditorFileSystemDirectory *fs=NULL;
+ int cpos=-1;
+ bool found = _find_file(p_file,&fs,cpos);
+ ERR_FAIL_COND(!found);
+
+ //try to obtain existing params
+
+ Map<StringName,Variant> params;
+ String importer_name;
+
+ if (FileAccess::exists(p_file+".import")) {
+
+ Ref<ConfigFile> cf;
+ cf.instance();
+ Error err = cf->load(p_file+".import");
+ if (err==OK) {
+ List<String> sk;
+ cf->get_section_keys("params",&sk);
+ for(List<String>::Element *E=sk.front();E;E=E->next()) {
+ params[E->get()]=cf->get_value("params",E->get());
+ }
+ importer_name = cf->get_value("remap","importer");
+ }
+ }
+
+ Ref<ResourceImporter> importer;
+ //find the importer
+ if (importer_name!="") {
+ importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
+ }
+
+ if (importer.is_null()) {
+ //not found by name, find by extension
+ importer = ResourceFormatImporter::get_singleton()->get_importer_by_extension(p_file.get_extension());
+ if (importer.is_null()) {
+ ERR_PRINT("BUG: File queued for import, but can't be imported!");
+ ERR_FAIL();
+
+ }
+ }
+
+ //mix with default params, in case a parameter is missing
+
+ List<ResourceImporter::ImportOption> opts;
+ importer->get_import_options(&opts);
+ for (List<ResourceImporter::ImportOption>::Element *E=opts.front();E;E=E->next()) {
+ if (!params.has(E->get().option.name)) { //this one is not present
+ params[E->get().option.name]=E->get().default_value;
+ }
+ }
+
+ //finally, perform import!!
+ String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(p_file);
+
+ List<String> import_variants;
+ List<String> gen_files;
+
+ Error err = importer->import(p_file,base_path,params,&import_variants,&gen_files);
+
+ if (err!=OK) {
+ ERR_PRINTS("Error importing: "+p_file);
+ }
+
+ //as import is complete, save the .import file
+
+ FileAccess *f = FileAccess::open(p_file+".import",FileAccess::WRITE);
+ ERR_FAIL_COND(!f);
+
+ //write manually, as order matters ([remap] has to go first for performance).
+ f->store_line("[remap]");
+ f->store_line("");
+ f->store_line("importer=\""+importer->get_importer_name()+"\"");
+ if (importer->get_resource_type()!="") {
+ f->store_line("type=\""+importer->get_resource_type()+"\"");
+ }
+
+ if (importer->get_save_extension()=="") {
+ //no path
+ } else if (import_variants.size()) {
+ //import with variants
+ for(List<String>::Element *E=import_variants.front();E;E=E->next()) {
+
+
+ f->store_line("path."+E->get()+"=\""+base_path.c_escape()+"."+E->get()+"."+importer->get_save_extension()+"\"");
+ }
+ } else {
+
+ f->store_line("path=\""+base_path+"."+importer->get_save_extension()+"\"");
+ }
+
+ f->store_line("");
+ if (gen_files.size()) {
+ f->store_line("[gen]");
+ Array genf;
+ for (List<String>::Element *E=gen_files.front();E;E=E->next()) {
+ genf.push_back(E->get());
+ }
+
+ String value;
+ VariantWriter::write_to_string(genf,value);
+ f->store_line("files="+value);
+ f->store_line("");
+ }
+
+
+ f->store_line("[params]");
+ f->store_line("");
+
+ //store options in provided order, to avoid file changing
+ for (List<ResourceImporter::ImportOption>::Element *E=opts.front();E;E=E->next()) {
+
+ String base = E->get().option.name;
+ String value;
+ VariantWriter::write_to_string(params[base],value);
+ f->store_line(base+"="+value);
+
+
+ }
+
+ memdelete(f);
+
+ //update modified times, to avoid reimport
+ fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file);
+ fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(p_file+".import");
+}
+
+void EditorFileSystem::reimport_files(const Vector<String>& p_files) {
+
+
+ EditorProgress pr("reimport",TTR("(Re)Importing Assets"),p_files.size());
+ for(int i=0;i<p_files.size();i++) {
+ pr.step(p_files[i].get_file(),i);
+
+ _reimport_file(p_files[i]);
+ }
+
+ _save_filesystem_cache();
+}
void EditorFileSystem::_bind_methods() {
@@ -1351,7 +1439,7 @@ void EditorFileSystem::_bind_methods() {
ClassDB::bind_method(_MD("is_scanning"),&EditorFileSystem::is_scanning);
ClassDB::bind_method(_MD("get_scanning_progress"),&EditorFileSystem::get_scanning_progress);
ClassDB::bind_method(_MD("scan"),&EditorFileSystem::scan);
- ClassDB::bind_method(_MD("scan_sources"),&EditorFileSystem::scan_sources);
+ ClassDB::bind_method(_MD("scan_sources"),&EditorFileSystem::scan_changes);
ClassDB::bind_method(_MD("update_file","path"),&EditorFileSystem::update_file);
ClassDB::bind_method(_MD("get_filesystem_path:EditorFileSystemDirectory","path"),&EditorFileSystem::get_filesystem_path);
ClassDB::bind_method(_MD("get_file_type","path"),&EditorFileSystem::get_file_type);
@@ -1361,10 +1449,29 @@ void EditorFileSystem::_bind_methods() {
}
+void EditorFileSystem::_update_extensions() {
+
+ valid_extensions.clear();
+ import_extensions.clear();
+
+ List<String> extensionsl;
+ ResourceLoader::get_recognized_extensions_for_type("",&extensionsl);
+ for(List<String>::Element *E = extensionsl.front();E;E=E->next()) {
+
+ valid_extensions.insert(E->get());
+ }
+ extensionsl.clear();
+ ResourceFormatImporter::get_singleton()->get_recognized_extensions(&extensionsl);
+ for(List<String>::Element *E = extensionsl.front();E;E=E->next()) {
+
+ import_extensions.insert(E->get());
+ }
+}
EditorFileSystem::EditorFileSystem() {
+ reimport_on_missing_imported_files = GLOBAL_DEF("editor/reimport_missing_imported_files",true);
singleton=this;
filesystem=memnew( EditorFileSystemDirectory ); //like, empty
@@ -1375,16 +1482,14 @@ EditorFileSystem::EditorFileSystem() {
thread_sources=NULL;
new_filesystem=NULL;
- scanning_sources=false;
+ scanning_changes=false;
ResourceSaver::set_save_callback(_resource_saved);
- List<String> extensionsl;
- ResourceLoader::get_recognized_extensions_for_type("",&extensionsl);
- for(List<String>::Element *E = extensionsl.front();E;E=E->next()) {
-
- valid_extensions.insert(E->get());
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (da->change_dir("res://.import")!=OK) {
+ da->make_dir("res://.import");
}
-
+ memdelete(da);
scan_total=0;
}
diff --git a/tools/editor/editor_file_system.h b/tools/editor/editor_file_system.h
index 3a26f46aa9..92169907a4 100644
--- a/tools/editor/editor_file_system.h
+++ b/tools/editor/editor_file_system.h
@@ -48,30 +48,13 @@ class EditorFileSystemDirectory : public Object {
EditorFileSystemDirectory *parent;
Vector<EditorFileSystemDirectory*> subdirs;
- struct ImportMeta {
-
- struct Source {
-
- String path;
- String md5;
- uint64_t modified_time;
- bool missing;
-
- };
-
- Vector<Source> sources;
- String import_editor;
- Vector<String> deps;
- bool enabled;
- bool sources_changed;
-
- };
struct FileInfo {
String file;
StringName type;
uint64_t modified_time;
- ImportMeta meta;
+ uint64_t import_modified_time;
+ Vector<String> deps;
bool verified; //used for checking changes
};
@@ -101,14 +84,7 @@ public:
String get_file(int p_idx) const;
String get_file_path(int p_idx) const;
StringName get_file_type(int p_idx) const;
- bool get_file_meta(int p_idx) const;
- bool is_missing_sources(int p_idx) const;
- bool have_sources_changed(int p_idx) const;
- Vector<String> get_missing_sources(int p_idx) const;
Vector<String> get_file_deps(int p_idx) const;
- int get_source_count(int p_idx) const;
- String get_source_file(int p_idx,int p_source) const;
- bool is_source_file_missing(int p_idx,int p_source) const;
EditorFileSystemDirectory *get_parent();
@@ -136,7 +112,7 @@ class EditorFileSystem : public Node {
ACTION_DIR_REMOVE,
ACTION_FILE_ADD,
ACTION_FILE_REMOVE,
- ACTION_FILE_SOURCES_CHANGED
+ ACTION_FILE_REIMPORT
};
Action action;
@@ -171,7 +147,7 @@ class EditorFileSystem : public Node {
String type;
uint64_t modification_time;
- EditorFileSystemDirectory::ImportMeta meta;
+ uint64_t import_modification_time;
Vector<String> deps;
};
@@ -186,25 +162,25 @@ class EditorFileSystem : public Node {
ScanProgress get_sub(int p_current,int p_total) const;
};
- static EditorFileSystemDirectory::ImportMeta _get_meta(const String& p_path);
-
- bool _check_meta_sources(EditorFileSystemDirectory::ImportMeta & p_meta);
+ void _save_filesystem_cache();
void _save_filesystem_cache(EditorFileSystemDirectory *p_dir,FileAccess *p_file);
bool _find_file(const String& p_file,EditorFileSystemDirectory ** r_d, int &r_file_pos) const;
void _scan_fs_changes(EditorFileSystemDirectory *p_dir, const ScanProgress &p_progress);
+
int md_count;
Set<String> valid_extensions;
+ Set<String> import_extensions;
void _scan_new_dir(EditorFileSystemDirectory *p_dir,DirAccess *da,const ScanProgress& p_progress);
Thread *thread_sources;
- bool scanning_sources;
- bool scanning_sources_done;
+ bool scanning_changes;
+ bool scanning_changes_done;
static void _thread_func_sources(void *_userdata);
@@ -214,7 +190,14 @@ class EditorFileSystem : public Node {
bool _update_scan_actions();
static void _resource_saved(const String& p_path);
- String _find_first_from_source(EditorFileSystemDirectory* p_dir,const String &p_src) const;
+
+ void _update_extensions();
+
+ void _reimport_file(const String &p_file);
+
+ bool _check_missing_imported_files(const String& p_path);
+
+ bool reimport_on_missing_imported_files;
protected:
@@ -229,14 +212,16 @@ public:
bool is_scanning() const;
float get_scanning_progress() const;
void scan();
- void scan_sources();
+ void scan_changes();
void get_changed_sources(List<String> *r_changed);
void update_file(const String& p_file);
- String find_resource_from_source(const String& p_path) const;
+
EditorFileSystemDirectory *get_filesystem_path(const String& p_path);
String get_file_type(const String& p_file) const;
EditorFileSystemDirectory* find_file(const String& p_file,int* r_index) const;
+ void reimport_files(const Vector<String>& p_files);
+
EditorFileSystem();
~EditorFileSystem();
};
diff --git a/tools/editor/editor_import_export.cpp b/tools/editor/editor_import_export.cpp
index 6ef238920d..b79bf7042b 100644
--- a/tools/editor/editor_import_export.cpp
+++ b/tools/editor/editor_import_export.cpp
@@ -28,6 +28,7 @@
/*************************************************************************/
#include "editor_import_export.h"
+#if 0
#include "version.h"
#include "script_language.h"
#include "globals.h"
@@ -2302,3 +2303,4 @@ EditorImportExport::~EditorImportExport() {
}
+#endif
diff --git a/tools/editor/editor_import_export.h b/tools/editor/editor_import_export.h
index fb75373f17..2654a4ea33 100644
--- a/tools/editor/editor_import_export.h
+++ b/tools/editor/editor_import_export.h
@@ -29,6 +29,8 @@
#ifndef EDITOR_IMPORT_EXPORT_H
#define EDITOR_IMPORT_EXPORT_H
+#if 0
+
#include "resource.h"
#include "scene/main/node.h"
#include "scene/resources/texture.h"
@@ -419,4 +421,5 @@ VARIANT_ENUM_CAST(EditorImportExport::ImageAction);
VARIANT_ENUM_CAST(EditorImportExport::ScriptAction);
VARIANT_ENUM_CAST(EditorImportExport::SampleAction);
+#endif
#endif // EDITOR_IMPORT_EXPORT_H
diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp
index 0c8d786f03..a51507e96f 100644
--- a/tools/editor/editor_node.cpp
+++ b/tools/editor/editor_node.cpp
@@ -55,7 +55,7 @@
#include "animation_editor.h"
#include "io/stream_peer_ssl.h"
#include "main/input_default.h"
-
+#include "os/input.h"
// plugins
#include "plugins/sprite_frames_editor_plugin.h"
#include "plugins/texture_region_editor_plugin.h"
@@ -99,7 +99,8 @@
#include "plugins/color_ramp_editor_plugin.h"
#include "plugins/collision_shape_2d_editor_plugin.h"
#include "plugins/gi_probe_editor_plugin.h"
-
+#include "import/resource_import_texture.h"
+#include "import/resource_importer_csv_translation.h"
// end
#include "editor_settings.h"
#include "io_plugins/editor_texture_import_plugin.h"
@@ -115,6 +116,7 @@
#include "plugins/editor_preview_plugins.h"
#include "editor_initialize_ssl.h"
+#include "editor_audio_buses.h"
#include "script_editor_debugger.h"
EditorNode *EditorNode::singleton=NULL;
@@ -189,6 +191,9 @@ void EditorNode::_unhandled_input(const InputEvent& p_event) {
next_tab = next_tab >= 0 ? next_tab : editor_data.get_edited_scene_count() - 1;
_scene_tab_changed(next_tab);
}
+ if (ED_IS_SHORTCUT("editor/filter_files", p_event)) {
+ filesystem_dock->focus_on_filter();
+ }
switch(p_event.key.scancode) {
@@ -329,21 +334,6 @@ void EditorNode::_notification(int p_what) {
_editor_select(EDITOR_3D);
- if (defer_load_scene!="") {
-
- load_scene(defer_load_scene);
- defer_load_scene="";
- }
-
- if (defer_translatable!="") {
-
- Error ok = save_translatable_strings(defer_translatable);
- if (ok!=OK)
- OS::get_singleton()->set_exit_code(255);
- defer_translatable="";
- get_tree()->quit();
- }
-
/*
if (defer_optimize!="") {
Error ok = save_optimized_copy(defer_optimize,defer_optimize_preset);
@@ -366,40 +356,7 @@ void EditorNode::_notification(int p_what) {
if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_IN) {
- /*
- List<Ref<Resource> > cached;
- ResourceCache::get_cached_resources(&cached);
-
- bool changes=false;
- for(List<Ref<Resource> >::Element *E=cached.front();E;E=E->next()) {
-
- if (!E->get()->can_reload_from_file())
- continue;
- if (E->get()->get_path().find("::")!=-1)
- continue;
- uint64_t mt = FileAccess::get_modified_time(E->get()->get_path());
- if (mt!=E->get()->get_last_modified_time()) {
- changes=true;
- break;
- }
- }
-
-
-
- sources_button->get_popup()->set_item_disabled(sources_button->get_popup()->get_item_index(DEPENDENCY_UPDATE_LOCAL),!changes);
- if (changes && sources_button->get_popup()->is_item_disabled(sources_button->get_popup()->get_item_index(DEPENDENCY_UPDATE_IMPORTED))) {
- sources_button->set_icon(gui_base->get_icon("DependencyLocalChanged","EditorIcons"));
- }
-*/
-
- if (bool(EDITOR_DEF("filesystem/resources/auto_reload_modified_images",true))) {
-
- _menu_option_confirm(DEPENDENCY_LOAD_CHANGED_IMAGES,true);
- }
-
- waiting_for_sources_changed=true;
- EditorFileSystem::get_singleton()->scan_sources();
-
+ EditorFileSystem::get_singleton()->scan_changes();
}
if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST) {
@@ -427,63 +384,73 @@ void EditorNode::_fs_changed() {
if (export_defer.platform!="") {
- project_export_settings->export_platform(export_defer.platform,export_defer.path,export_defer.debug,export_defer.password,true);
+ //project_export_settings->export_platform(export_defer.platform,export_defer.path,export_defer.debug,export_defer.password,true);
export_defer.platform="";
}
-}
-
-void EditorNode::_sources_changed(bool p_exist) {
+ {
- if (p_exist && bool(EditorSettings::get_singleton()->get("filesystem/import/automatic_reimport_on_sources_changed"))) {
- p_exist=false;
+ //reload changed resources
+ List<Ref<Resource> > changed;
- List<String> changed_sources;
- EditorFileSystem::get_singleton()->get_changed_sources(&changed_sources);
+ List<Ref<Resource> > cached;
+ ResourceCache::get_cached_resources(&cached);
+ //this should probably be done in a thread..
+ for(List<Ref<Resource> >::Element *E=cached.front();E;E=E->next()) {
+ if (!E->get()->editor_can_reload_from_file())
+ continue;
+ if (!E->get()->get_path().is_resource_file() && !E->get()->get_path().is_abs_path())
+ continue;
+ if (!FileAccess::exists(E->get()->get_path()))
+ continue;
- EditorProgress ep("reimport",TTR("Re-Importing"),changed_sources.size());
- int step_idx=0;
+ if (E->get()->get_import_path()!=String()) {
+ //imported resource
+ uint64_t mt = FileAccess::get_modified_time(E->get()->get_import_path());
- for(List<String>::Element *E=changed_sources.front();E;E=E->next()) {
+ if (mt!=E->get()->get_import_last_modified_time()) {
+ changed.push_back(E->get());
+ }
- ep.step(TTR("Importing:")+" "+E->get(),step_idx++);
+ } else {
+ uint64_t mt = FileAccess::get_modified_time(E->get()->get_path());
- Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(E->get());
- ERR_CONTINUE(rimd.is_null());
- String editor = rimd->get_editor();
- if (editor.begins_with("texture_")) {
- editor="texture"; //compatibility fix for old versions
- }
- Ref<EditorImportPlugin> eip = EditorImportExport::get_singleton()->get_import_plugin_by_name(editor);
- ERR_CONTINUE(eip.is_null());
- Error err = eip->import(E->get(),rimd);
- if (err!=OK) {
- EditorNode::add_io_error("Error Re Importing:\n "+E->get());
+ if (mt!=E->get()->get_last_modified_time()) {
+ changed.push_back(E->get());
+ }
}
+ }
+
+ if (changed.size()) {
+ //EditorProgress ep("reload_res","Reload Modified Resources",changed.size());
+ int idx=0;
+ for(List<Ref<Resource> >::Element *E=changed.front();E;E=E->next()) {
+ //ep.step(E->get()->get_path(),idx++);
+ E->get()->reload_from_file();
+ }
}
- EditorFileSystem::get_singleton()->scan_sources();
- waiting_for_sources_changed=false;
- return;
}
+}
- if (p_exist) {
+void EditorNode::_sources_changed(bool p_exist) {
- sources_button->set_icon(gui_base->get_icon("DependencyChanged","EditorIcons"));
- sources_button->set_disabled(false);
+ if (waiting_for_first_scan) {
- } else {
+ if (defer_load_scene!="") {
- sources_button->set_icon(gui_base->get_icon("DependencyOk","EditorIcons"));
- sources_button->set_disabled(true);
+ print_line("loading scene DEFERED");
+ load_scene(defer_load_scene);
+ defer_load_scene="";
+ }
+ waiting_for_first_scan=false;
}
- waiting_for_sources_changed=false;
}
@@ -498,9 +465,11 @@ void EditorNode::_rebuild_import_menu()
p->clear();
//p->add_item(TTR("Node From Scene"), FILE_IMPORT_SUBSCENE);
//p->add_separator();
+#if 0
for (int i = 0; i < editor_import_export->get_import_plugin_count(); i++) {
p->add_item(editor_import_export->get_import_plugin(i)->get_visible_name(), IMPORT_PLUGIN_BASE + i);
}
+#endif
}
void EditorNode::_node_renamed() {
@@ -1004,7 +973,6 @@ void EditorNode::_save_scene(String p_file, int idx) {
return;
}
- sdata->set_import_metadata(editor_data.get_edited_scene_import_metadata(idx));
int flg=0;
if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources"))
flg|=ResourceSaver::FLAG_COMPRESS;
@@ -1201,12 +1169,6 @@ void EditorNode::_dialog_action(String p_file) {
get_undo_redo()->clear_history();
} break;
- case FILE_DUMP_STRINGS: {
-
- save_translatable_strings(p_file);
-
- } break;
-
case FILE_SAVE_SCENE:
case FILE_SAVE_AS_SCENE: {
@@ -1924,17 +1886,17 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
editor_data.save_editor_external_data();
}
- if (bool(EDITOR_DEF("run/always_clear_output_on_play", true))) {
+ if (bool(EDITOR_DEF("run/output/always_clear_output_on_play", true))) {
log->clear();
}
- if (bool(EDITOR_DEF("run/always_open_output_on_play", true))) {
+ if (bool(EDITOR_DEF("run/output/always_open_output_on_play", true))) {
make_bottom_panel_item_visible(log);
}
List<String> breakpoints;
editor_data.get_editor_breakpoints(&breakpoints);
-
+
args = GlobalConfig::get_singleton()->get("editor/main_run_args");
Error error = editor_run.run(run_filename,args,breakpoints,current_filename);
@@ -2075,14 +2037,6 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
quick_open->set_title(TTR("Quick Open Script.."));
} break;
- case FILE_QUICK_OPEN_FILE: {
-
-
- //quick_open->popup("Resource", false, true);
- //quick_open->set_title("Quick Search File..");
- scenes_dock->focus_on_filter();
-
- } break;
case FILE_RUN_SCRIPT: {
file_script->popup_centered_ratio();
@@ -2206,46 +2160,6 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
_menu_option_confirm(FILE_SAVE_AND_RUN, true);
} break;
- case FILE_DUMP_STRINGS: {
-
- Node *scene = editor_data.get_edited_scene_root();
-
- if (!scene) {
-
- current_option=-1;
- //confirmation->get_cancel()->hide();
- accept->get_ok()->set_text(TTR("I see.."));
- accept->set_text("This operation can't be done without a tree root.");
- accept->popup_centered_minsize();
- break;
- }
-
- String cpath;
- if (scene->get_filename()!="") {
- cpath = scene->get_filename();
-
- String fn = cpath.substr(0,cpath.length() - cpath.get_extension().size());
- String ext=cpath.get_extension();
- cpath=fn+".pot";
-
-
- } else {
- current_option=-1;
- //confirmation->get_cancel()->hide();
- accept->get_ok()->set_text(TTR("I see.."));
- accept->set_text(TTR("Please save the scene first."));
- accept->popup_centered_minsize();
- break;
-
- }
-
- file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
-
- file->set_current_path(cpath);
- file->set_title(TTR("Save Translatable Strings"));
- file->popup_centered_ratio();
-
- } break;
case FILE_SAVE_OPTIMIZED: {
#if 0
Node *scene = editor_data.get_edited_scene_root();
@@ -2286,7 +2200,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
case FILE_EXPORT_PROJECT: {
- project_export_settings->popup_export();
+ //project_export_settings->popup_export();
/*
String target = export_db->get_current_platform();
Ref<EditorExporter> exporter = export_db->get_exporter(target);
@@ -2409,8 +2323,12 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
case EDIT_UNDO: {
- if (OS::get_singleton()->get_mouse_button_state())
+
+
+ if (Input::get_singleton()->get_mouse_button_mask()&0x7) {
+ print_line("no because state");
break; // can't undo while mouse buttons are pressed
+ }
String action = editor_data.get_undo_redo().get_current_action_name();
if (action!="")
@@ -2420,7 +2338,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
} break;
case EDIT_REDO: {
- if (OS::get_singleton()->get_mouse_button_state())
+ if (Input::get_singleton()->get_mouse_button_mask()&0x7)
break; // can't redo while mouse buttons are pressed
editor_data.get_undo_redo().redo();
@@ -2807,10 +2725,10 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
update_menu->get_popup()->set_item_checked(1,true);
OS::get_singleton()->set_low_processor_usage_mode(true);
} break;
- case SETTINGS_UPDATE_SPINNER_HIDE: {
+ case SETTINGS_UPDATE_SPINNER_HIDE: {
update_menu->set_icon(gui_base->get_icon("Collapse","EditorIcons"));
- update_menu->get_popup()->toggle_item_checked(3);
- } break;
+ update_menu->get_popup()->toggle_item_checked(3);
+ } break;
case SETTINGS_PREFERENCES: {
settings_config_dialog->popup_edit_settings();
@@ -2861,29 +2779,11 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
} break;
case SOURCES_REIMPORT: {
- reimport_dialog->popup_reimport();
+ //reimport_dialog->popup_reimport();
} break;
case DEPENDENCY_LOAD_CHANGED_IMAGES: {
- List<Ref<Resource> > cached;
- ResourceCache::get_cached_resources(&cached);
- //this should probably be done in a thread..
- for(List<Ref<Resource> >::Element *E=cached.front();E;E=E->next()) {
-
- if (!E->get()->editor_can_reload_from_file())
- continue;
- if (!E->get()->get_path().is_resource_file() && !E->get()->get_path().is_abs_path())
- continue;
- if (!FileAccess::exists(E->get()->get_path()))
- continue;
- uint64_t mt = FileAccess::get_modified_time(E->get()->get_path());
- if (mt!=E->get()->get_last_modified_time()) {
- E->get()->reload_from_file();
- }
-
- }
-
} break;
case DEPENDENCY_UPDATE_IMPORTED: {
@@ -2935,16 +2835,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
default: {
- if (p_option>=TOOL_MENU_BASE) {
- int idx = p_option - TOOL_MENU_BASE;
-
- if (tool_menu_items[idx].submenu != "")
- break;
-
- Object *handler = ObjectDB::get_instance(tool_menu_items[idx].handler);
- ERR_FAIL_COND(!handler);
- handler->call(tool_menu_items[idx].callback, tool_menu_items[idx].ud);
- } else if (p_option>=OBJECT_METHOD_BASE) {
+ if (p_option>=OBJECT_METHOD_BASE) {
ERR_FAIL_COND(!current);
@@ -2960,10 +2851,6 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
current->call(name);
} else if (p_option>=IMPORT_PLUGIN_BASE) {
- Ref<EditorImportPlugin> p = editor_import_export->get_import_plugin(p_option-IMPORT_PLUGIN_BASE);
- if (p.is_valid()) {
- p->import_dialog();
- }
}
}
@@ -3064,20 +2951,6 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor) {
}
-void EditorNode::add_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import) {
-
- ERR_FAIL_COND( p_editor_import.is_null() );
- editor_import_export->add_import_plugin(p_editor_import);
- _rebuild_import_menu();
-}
-
-void EditorNode::remove_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import) {
- ERR_FAIL_COND( p_editor_import.is_null() );
-
- editor_import_export->remove_import_plugin(p_editor_import);
- _rebuild_import_menu();
-}
-
void EditorNode::_update_addon_config() {
@@ -3237,232 +3110,6 @@ void EditorNode::set_edited_scene(Node *p_scene) {
}
-void EditorNode::_fetch_translatable_strings(const Object *p_object,Set<StringName>& strings) {
-
-
- List<String> tstrings;
- p_object->get_translatable_strings(&tstrings);
- for(List<String>::Element *E=tstrings.front();E;E=E->next())
- strings.insert(E->get());
-
-
-
- const Node * node = p_object->cast_to<Node>();
-
- if (!node)
- return;
-
- Ref<Script> script = node->get_script();
- if (script.is_valid())
- _fetch_translatable_strings(script.ptr(),strings);
-
- for(int i=0;i<node->get_child_count();i++) {
-
- Node *c=node->get_child(i);
- if (c->get_owner()!=get_edited_scene())
- continue;
-
- _fetch_translatable_strings(c,strings);
- }
-
-}
-
-
-Error EditorNode::save_translatable_strings(const String& p_to_file) {
-
- if (!is_inside_tree()) {
- defer_translatable=p_to_file;
- return OK;
- }
-
- ERR_FAIL_COND_V(!get_edited_scene(),ERR_INVALID_DATA);
-
- Set<StringName> strings;
- _fetch_translatable_strings(get_edited_scene(),strings);
-
- Error err;
- FileAccess *f = FileAccess::open(p_to_file,FileAccess::WRITE,&err);
- ERR_FAIL_COND_V(err,err);
-
- OS::Date date = OS::get_singleton()->get_date();
- OS::Time time = OS::get_singleton()->get_time();
- f->store_line("# Translation Strings Dump.");
- f->store_line("# Created By.");
- f->store_line("# \t" VERSION_FULL_NAME " (c) 2008-2017 Juan Linietsky, Ariel Manzur.");
- f->store_line("# From Scene: ");
- f->store_line("# \t"+get_edited_scene()->get_filename());
- f->store_line("");
- f->store_line("msgid \"\"");
- f->store_line("msgstr \"\"");
- f->store_line("\"Report-Msgid-Bugs-To: <define>\\n\"");
- f->store_line("\"POT-Creation-Date: "+itos(date.year)+"-"+itos(date.month)+"-"+itos(date.day)+" "+itos(time.hour)+":"+itos(time.min)+"0000\\n\"");
- //f->store_line("\"PO-Revision-Date: 2006-08-30 13:56-0700\\n\"");
- //f->store_line("\"Last-Translator: Rubén C. Díaz Alonso <outime@gmail.com>\\n\"");
- f->store_line("\"Language-Team: <define>\\n\"");
- f->store_line("\"MIME-Version: 1.0\\n\"");
- f->store_line("\"Content-Type: text/plain; charset=UTF-8\\n\"");
- f->store_line("\"Content-Transfer-Encoding: 8bit\\n\"");
- f->store_line("");
-
- for(Set<StringName>::Element *E=strings.front();E;E=E->next()) {
-
- String s = E->get();
- if (s=="" || s.strip_edges()=="")
- continue;
- Vector<String> substr = s.split("\n");
- ERR_CONTINUE(substr.size()==0);
-
- f->store_line("");
-
- if (substr.size()==1) {
-
- f->store_line("msgid \""+substr[0].c_escape()+"\"");
- } else {
-
- f->store_line("msgid \"\"");
- for(int i=0;i<substr.size();i++) {
-
- String s = substr[i];
- if (i!=substr.size()-1)
- s+="\n";
- f->store_line("\""+s.c_escape()+"\"");
- }
- }
-
- f->store_line("msgstr \"\"");
-
- }
-
-
- f->close();
- memdelete(f);
-
- return OK;
-
-}
-
-Error EditorNode::save_optimized_copy(const String& p_scene,const String& p_preset) {
-
-#if 0
-
- if (!is_inside_scene()) {
- defer_optimize=p_scene;
- defer_optimize_preset=p_preset;
- return OK;
- }
-
-
- if (!get_edited_scene()) {
-
- get_scene()->quit();
- ERR_EXPLAIN("No scene to optimize (loading failed?)");
- ERR_FAIL_V(ERR_FILE_NOT_FOUND);
- }
-
-
- String src_scene=GlobalConfig::get_singleton()->localize_path(get_edited_scene()->get_filename());
-
-
- String path=p_scene;
- print_line("p_path: "+p_scene);
- print_line("src_scene: "+p_scene);
-
- if (path.is_rel_path()) {
- print_line("rel path!?");
- path=src_scene.get_base_dir()+"/"+path;
- }
- path = GlobalConfig::get_singleton()->localize_path(path);
-
- print_line("path: "+path);
-
-
- String preset = "optimizer_presets/"+p_preset;
- if (!GlobalConfig::get_singleton()->has(preset)) {
-
- //accept->"()->hide();
- accept->get_ok()->set_text("I see..");
- accept->set_text("Optimizer preset not found: "+p_preset);
- accept->popup_centered(Size2(300,70));
- ERR_EXPLAIN("Optimizer preset not found: "+p_preset);
- ERR_FAIL_V(ERR_INVALID_PARAMETER);
-
- }
-
- Dictionary d = GlobalConfig::get_singleton()->get(preset);
-
- ERR_FAIL_COND_V(!d.has("__type__"),ERR_INVALID_DATA);
- String type=d["__type__"];
-
- Ref<EditorOptimizedSaver> saver;
-
- for(int i=0;i<editor_data.get_optimized_saver_count();i++) {
-
- print_line(type+" vs "+editor_data.get_optimized_saver(i)->get_target_name());
- if (editor_data.get_optimized_saver(i)->get_target_name()==type) {
- saver=editor_data.get_optimized_saver(i);
- }
- }
-
- ERR_EXPLAIN("Preset '"+p_preset+"' references nonexistent saver: "+type);
- ERR_FAIL_COND_V(saver.is_null(),ERR_INVALID_DATA);
-
- List<Variant> keys;
- d.get_key_list(&keys);
-
- saver->clear();
-
- for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
-
- saver->set(E->get(),d[E->get()]);
- }
-
- uint32_t flags=0;
-
- /*
- if (saver->is_bundle_scenes_enabled())
- flags|=ResourceSaver::FLAG_BUNDLE_INSTANCED_SCENES;
- */
- if (saver->is_bundle_resources_enabled())
- flags|=ResourceSaver::FLAG_BUNDLE_RESOURCES;
- if (saver->is_remove_editor_data_enabled())
- flags|=ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
- if (saver->is_big_endian_data_enabled())
- flags|=ResourceSaver::FLAG_SAVE_BIG_ENDIAN;
-
- String platform=saver->get_target_platform();
- if (platform=="")
- platform="all";
-
- Ref<PackedScene> sdata = memnew( PackedScene );
- Error err = sdata->pack(get_edited_scene());
-
- if (err) {
-
- current_option=-1;
- //accept->get_cancel()->hide();
- accept->get_ok()->set_text("I see..");
- accept->set_text("Couldn't save scene. Likely dependencies (instances) couldn't be satisfied.");
- accept->popup_centered(Size2(300,70));
- return ERR_INVALID_DATA;
-
- }
- err = ResourceSaver::save(path,sdata,flags); //todo, saverSceneSaver::save(path,get_edited_scene(),flags,saver);
-
- if (err) {
-
- //accept->"()->hide();
- accept->get_ok()->set_text("I see..");
- accept->set_text("Error saving optimized scene: "+path);
- accept->popup_centered(Size2(300,70));
-
- ERR_FAIL_COND_V(err,err);
-
- }
-
- project_settings->add_remapped_path(src_scene,path,platform);
-#endif
- return OK;
-}
int EditorNode::_get_current_main_editor() {
@@ -3821,7 +3468,6 @@ Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps,bo
property_editor->edit(new_scene);
editor_data.set_edited_scene_root(new_scene);
*/
- editor_data.set_edited_scene_import_metadata( sdata->get_import_metadata() );
//editor_data.get_undo_redo().clear_history();
saved_version=editor_data.get_undo_redo().get_version();
@@ -3861,9 +3507,13 @@ void EditorNode::request_instance_scenes(const Vector<String>& p_files) {
scene_tree_dock->instance_scenes(p_files);
}
-FileSystemDock *EditorNode::get_scenes_dock() {
+ImportDock *EditorNode::get_import_dock() {
+ return import_dock;
+}
+
+FileSystemDock *EditorNode::get_filesystem_dock() {
- return scenes_dock;
+ return filesystem_dock;
}
SceneTreeDock *EditorNode::get_scene_tree_dock() {
@@ -4164,9 +3814,9 @@ bool EditorNode::is_scene_in_use(const String& p_path) {
void EditorNode::register_editor_types() {
ClassDB::register_class<EditorPlugin>();
- ClassDB::register_class<EditorImportPlugin>();
- ClassDB::register_class<EditorExportPlugin>();
- ClassDB::register_class<EditorScenePostImport>();
+// ClassDB::register_class<EditorImportPlugin>();
+// ClassDB::register_class<EditorExportPlugin>();
+// ClassDB::register_class<EditorScenePostImport>();
ClassDB::register_class<EditorScript>();
ClassDB::register_class<EditorSelection>();
ClassDB::register_class<EditorFileDialog>();
@@ -4523,6 +4173,8 @@ void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String& p
}
}
+ p_layout->set_value(p_section,"dock_filesystem_split",filesystem_dock->get_split_offset());
+
VSplitContainer*splits[DOCK_SLOT_MAX/2]={
left_l_vsplit,
left_r_vsplit,
@@ -4699,6 +4351,12 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String&
}
}
+ int fs_split_ofs = 0;
+ if (p_layout->has_section_key(p_section,"dock_filesystem_split")) {
+ fs_split_ofs = p_layout->get_value(p_section,"dock_filesystem_split");
+ }
+ filesystem_dock->set_split_offset(fs_split_ofs);
+
VSplitContainer*splits[DOCK_SLOT_MAX/2]={
left_l_vsplit,
left_r_vsplit,
@@ -5082,7 +4740,6 @@ Variant EditorNode::drag_resource(const Ref<Resource>& p_res,Control* p_from) {
TextureRect *drag_preview = memnew( TextureRect );
Label* label=memnew( Label );
- waiting_for_sources_changed=true; //
Ref<Texture> preview;
{
@@ -5187,10 +4844,10 @@ Variant EditorNode::drag_files_and_dirs(const Vector<String>& p_files, Control *
void EditorNode::_dropped_files(const Vector<String>& p_files,int p_screen) {
- String cur_path = scenes_dock->get_current_path();
- for(int i=0;i<EditorImportExport::get_singleton()->get_import_plugin_count();i++) {
- EditorImportExport::get_singleton()->get_import_plugin(i)->import_from_drop(p_files,cur_path);
- }
+ String cur_path = filesystem_dock->get_current_path();
+// for(int i=0;i<EditorImportExport::get_singleton()->get_import_plugin_count();i++) {
+// EditorImportExport::get_singleton()->get_import_plugin(i)->import_from_drop(p_files,cur_path);
+// }
}
void EditorNode::_file_access_close_error_notify(const String& p_str) {
@@ -5279,100 +4936,6 @@ void EditorNode::add_plugin_init_callback(EditorPluginInitializeCallback p_callb
EditorPluginInitializeCallback EditorNode::plugin_init_callbacks[EditorNode::MAX_INIT_CALLBACKS];
-void EditorNode::_tool_menu_insert_item(const ToolMenuItem& p_item) {
-
- int idx = tool_menu_items.size();
-
- String cat;
- if (p_item.name.find("/") >= 0) {
- cat = p_item.name.get_slice("/", 0);
- } else {
- idx = 0;
- cat = "";
- }
-
- for (int i = tool_menu_items.size() - 1; i >= 0; i--) {
- String name = tool_menu_items[i].name;
-
- if (name.begins_with(cat) && (cat != "" || name.find("/") < 0)) {
- idx = i + 1;
- break;
- }
- }
-
- tool_menu_items.insert(idx, p_item);
-}
-
-void EditorNode::_rebuild_tool_menu() const {
-
- if (_initializing_tool_menu)
- return;
-
- PopupMenu *menu = tool_menu->get_popup();
- menu->clear();
-
- for (int i = 0; i < tool_menu_items.size(); i++) {
- menu->add_item(tool_menu_items[i].name.get_slice("/", 1), TOOL_MENU_BASE + i);
-
- if (tool_menu_items[i].submenu != "")
- menu->set_item_submenu(i, tool_menu_items[i].submenu);
- }
-}
-
-void EditorNode::add_tool_menu_item(const String& p_name, Object *p_handler, const String& p_callback, const Variant& p_ud) {
-
- ERR_FAIL_COND(!p_handler);
-
- ToolMenuItem tmi;
- tmi.name = p_name;
- tmi.submenu = "";
- tmi.ud = p_ud;
- tmi.handler = p_handler->get_instance_ID();
- tmi.callback = p_callback;
- _tool_menu_insert_item(tmi);
-
- _rebuild_tool_menu();
-}
-
-void EditorNode::add_tool_submenu_item(const String& p_name, PopupMenu *p_submenu) {
-
- ERR_FAIL_COND(!p_submenu);
- ERR_FAIL_COND(p_submenu->get_parent() != NULL);
-
- ToolMenuItem tmi;
- tmi.name = p_name;
- tmi.submenu = p_submenu->get_name();
- tmi.ud = Variant();
- tmi.handler = -1;
- tmi.callback = "";
- _tool_menu_insert_item(tmi);
-
- tool_menu->get_popup()->add_child(p_submenu);
-
- _rebuild_tool_menu();
-}
-
-void EditorNode::remove_tool_menu_item(const String& p_name) {
-
- for (int i = 0; i < tool_menu_items.size(); i++) {
- if (tool_menu_items[i].name == p_name) {
- String submenu = tool_menu_items[i].submenu;
-
- if (submenu != "") {
- Node *n = tool_menu->get_popup()->get_node(submenu);
-
- if (n) {
- tool_menu->get_popup()->remove_child(n);
- memdelete(n);
- }
- }
-
- tool_menu_items.remove(i);
- }
- }
-
- _rebuild_tool_menu();
-}
int EditorNode::build_callback_count=0;
@@ -5464,8 +5027,8 @@ void EditorNode::_bind_methods() {
- ClassDB::bind_method(_MD("add_editor_import_plugin", "plugin"), &EditorNode::add_editor_import_plugin);
- ClassDB::bind_method(_MD("remove_editor_import_plugin", "plugin"), &EditorNode::remove_editor_import_plugin);
+// ClassDB::bind_method(_MD("add_editor_import_plugin", "plugin"), &EditorNode::add_editor_import_plugin);
+ //ClassDB::bind_method(_MD("remove_editor_import_plugin", "plugin"), &EditorNode::remove_editor_import_plugin);
ClassDB::bind_method(_MD("get_gui_base"), &EditorNode::get_gui_base);
ClassDB::bind_method(_MD("_bottom_panel_switch"), &EditorNode::_bottom_panel_switch);
@@ -5516,11 +5079,8 @@ EditorNode::EditorNode() {
docks_visible = true;
- _initializing_tool_menu = true;
-
FileAccess::set_backup_save(true);
- PathRemap::get_singleton()->clear_remaps(); //editor uses no remaps
TranslationServer::get_singleton()->set_enabled(false);
// load settings
if (!EditorSettings::get_singleton())
@@ -5556,6 +5116,18 @@ EditorNode::EditorNode() {
ResourceLoader::set_timestamp_on_load(true);
ResourceSaver::set_timestamp_on_save(true);
+
+ { //register importers at the begining, so dialogs are created with the right extensions
+ Ref<ResourceImporterTexture> import_texture;
+ import_texture.instance();
+ ResourceFormatImporter::get_singleton()->add_importer(import_texture);
+
+ Ref<ResourceImporterCSVTranslation> import_csv_translation;
+ import_csv_translation.instance();
+ ResourceFormatImporter::get_singleton()->add_importer(import_csv_translation);
+
+ }
+
_pvrtc_register_compressors();
editor_selection = memnew( EditorSelection );
@@ -5573,13 +5145,8 @@ EditorNode::EditorNode() {
EditorFileDialog::unregister_func=_editor_file_dialog_unregister;
- editor_import_export = memnew( EditorImportExport );
- add_child(editor_import_export);
-
register_exporters();
- editor_import_export->load_config();
-
GLOBAL_DEF("editor/main_run_args","$scene");
ClassDB::set_class_enabled("CollisionShape",true);
@@ -5860,6 +5427,7 @@ EditorNode::EditorNode() {
ED_SHORTCUT("editor/next_tab", TTR("Next tab"), KEY_MASK_CMD+KEY_TAB);
ED_SHORTCUT("editor/prev_tab", TTR("Previous tab"), KEY_MASK_CMD+KEY_MASK_SHIFT+KEY_TAB);
+ ED_SHORTCUT("editor/filter_files", TTR("Filter Files.."), KEY_MASK_ALT+KEY_MASK_CMD+KEY_P);
file_menu->set_tooltip(TTR("Operations with scene files."));
@@ -5879,14 +5447,12 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_shortcut(ED_SHORTCUT("editor/quick_open_scene",TTR("Quick Open Scene.."),KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_O),FILE_QUICK_OPEN_SCENE);
p->add_shortcut(ED_SHORTCUT("editor/quick_open_script",TTR("Quick Open Script.."),KEY_MASK_ALT+KEY_MASK_CMD+KEY_O),FILE_QUICK_OPEN_SCRIPT);
- p->add_shortcut(ED_SHORTCUT("editor/quick_filter_files",TTR("Quick Filter Files.."),KEY_MASK_ALT+KEY_MASK_CMD+KEY_P),FILE_QUICK_OPEN_FILE);
p->add_separator();
PopupMenu *pm_export = memnew(PopupMenu );
pm_export->set_name("Export");
p->add_child(pm_export);
p->add_submenu_item(TTR("Convert To.."),"Export");
- pm_export->add_item(TTR("Translatable Strings.."),FILE_DUMP_STRINGS);
pm_export->add_separator();
pm_export->add_shortcut(ED_SHORTCUT("editor/convert_to_MeshLibrary", TTR("MeshLibrary..")), FILE_EXPORT_MESH_LIBRARY);
pm_export->add_shortcut(ED_SHORTCUT("editor/convert_to_TileSet", TTR("TileSet..")), FILE_EXPORT_TILESET);
@@ -5977,9 +5543,10 @@ EditorNode::EditorNode() {
//tool_menu->set_icon(gui_base->get_icon("Save","EditorIcons"));
left_menu_hb->add_child( tool_menu );
- tool_menu->get_popup()->connect("id_pressed", this, "_menu_option");
- add_tool_menu_item(TTR("Orphan Resource Explorer"), this, "_menu_option", TOOLS_ORPHAN_RESOURCES);
+ p=tool_menu->get_popup();
+ p->connect("id_pressed",this,"_menu_option");
+ p->add_item(TTR("Orphan Resource Explorer"),TOOLS_ORPHAN_RESOURCES);
export_button = memnew( ToolButton );
export_button->set_tooltip(TTR("Export the project to many platforms."));
@@ -6368,6 +5935,11 @@ EditorNode::EditorNode() {
property_editor->set_undo_redo(&editor_data.get_undo_redo());
+ import_dock = memnew( ImportDock );
+ dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(import_dock);
+ import_dock->set_name(TTR("Import"));
+
+
node_dock = memnew( NodeDock );
//node_dock->set_undoredo(&editor_data.get_undo_redo());
if (use_single_dock_column) {
@@ -6376,21 +5948,21 @@ EditorNode::EditorNode() {
dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(node_dock);
}
- scenes_dock = memnew( FileSystemDock(this) );
- scenes_dock->set_name(TTR("FileSystem"));
- scenes_dock->set_display_mode(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")));
+ filesystem_dock = memnew( FileSystemDock(this) );
+ filesystem_dock->set_name(TTR("FileSystem"));
+ filesystem_dock->set_display_mode(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")));
if (use_single_dock_column) {
- dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(scenes_dock);
+ dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(filesystem_dock);
left_r_vsplit->hide();
dock_slot[DOCK_SLOT_LEFT_UR]->hide();
dock_slot[DOCK_SLOT_LEFT_BR]->hide();
} else {
- dock_slot[DOCK_SLOT_LEFT_UR]->add_child(scenes_dock);
+ dock_slot[DOCK_SLOT_LEFT_UR]->add_child(filesystem_dock);
}
- //prop_pallete->add_child(scenes_dock);
- scenes_dock->connect("open",this,"open_request");
- scenes_dock->connect("instance",this,"_instance_request");
+ //prop_pallete->add_child(filesystem_dock);
+ filesystem_dock->connect("open",this,"open_request");
+ filesystem_dock->connect("instance",this,"_instance_request");
const String docks_section = "docks";
@@ -6492,11 +6064,11 @@ EditorNode::EditorNode() {
//gui_base->add_child(optimized_save);
//optimized_save->connect("confirmed",this,"_save_optimized");
- project_export = memnew( ProjectExport(&editor_data) );
- gui_base->add_child(project_export);
+ //project_export = memnew( ProjectExport(&editor_data) );
+ //gui_base->add_child(project_export);
- project_export_settings = memnew( ProjectExportDialog(this) );
- gui_base->add_child(project_export_settings);
+ //project_export_settings = memnew( ProjectExportDialog(this) );
+ //gui_base->add_child(project_export_settings);
//optimized_presets = memnew( OptimizedPresetsDialog(&editor_data) );
//gui_base->add_child(optimized_presets);
@@ -6610,8 +6182,8 @@ EditorNode::EditorNode() {
gui_base->add_child(file_script);
file_script->connect("file_selected",this,"_dialog_action");
- reimport_dialog = memnew( EditorReImportDialog );
- gui_base->add_child(reimport_dialog);
+ //reimport_dialog = memnew( EditorReImportDialog );
+ //gui_base->add_child(reimport_dialog);
@@ -6637,32 +6209,15 @@ EditorNode::EditorNode() {
file_server = memnew( EditorFileServer );
- editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this) )));
- Ref<EditorSceneImportPlugin> _scene_import = memnew(EditorSceneImportPlugin(this) );
- Ref<EditorSceneImporterCollada> _collada_import = memnew( EditorSceneImporterCollada);
- _scene_import->add_importer(_collada_import);
- //Ref<EditorSceneImporterFBXConv> _fbxconv_import = memnew( EditorSceneImporterFBXConv);
- //_scene_import->add_importer(_fbxconv_import);
- editor_import_export->add_import_plugin( _scene_import);
- // TODO: This plugin has no code, it should be either implemented or dropped (GH-3667)
- // editor_import_export->add_import_plugin( Ref<EditorSceneAnimationImportPlugin>( memnew(EditorSceneAnimationImportPlugin(this))));
- editor_import_export->add_import_plugin( Ref<EditorMeshImportPlugin>( memnew(EditorMeshImportPlugin(this))));
- editor_import_export->add_import_plugin( Ref<EditorFontImportPlugin>( memnew(EditorFontImportPlugin(this))));
-// editor_import_export->add_import_plugin( Ref<EditorSampleImportPlugin>( memnew(EditorSampleImportPlugin(this))));
- editor_import_export->add_import_plugin( Ref<EditorTranslationImportPlugin>( memnew(EditorTranslationImportPlugin(this))));
- editor_import_export->add_import_plugin( Ref<EditorBitMaskImportPlugin>( memnew(EditorBitMaskImportPlugin(this))));
-
-
- editor_import_export->add_export_plugin( Ref<EditorTextureExportPlugin>( memnew(EditorTextureExportPlugin)));
-// editor_import_export->add_export_plugin( Ref<EditorSampleExportPlugin>( memnew(EditorSampleExportPlugin)));
- editor_import_export->add_export_plugin( Ref<EditorSceneExportPlugin>( memnew(EditorSceneExportPlugin)));
-
add_editor_plugin( memnew( AnimationPlayerEditorPlugin(this) ) );
add_editor_plugin( memnew( CanvasItemEditorPlugin(this) ) );
add_editor_plugin( memnew( SpatialEditorPlugin(this) ) );
add_editor_plugin( memnew( ScriptEditorPlugin(this) ) );
+
+ EditorAudioBuses *audio_bus_editor = EditorAudioBuses::register_editor();
+
ScriptTextEditor::register_editor(); //register one for text scripts
if (StreamPeerSSL::is_available()) {
@@ -6710,6 +6265,7 @@ EditorNode::EditorNode() {
add_editor_plugin( memnew( ColorRampEditorPlugin(this) ) );
add_editor_plugin( memnew( CollisionShape2DEditorPlugin(this) ) );
add_editor_plugin( memnew( TextureEditorPlugin(this) ) );
+ add_editor_plugin( memnew( AudioBusesEditorPlugin(audio_bus_editor) ) );
//add_editor_plugin( memnew( MaterialEditorPlugin(this) ) );
//add_editor_plugin( memnew( MeshEditorPlugin(this) ) );
@@ -6720,6 +6276,9 @@ EditorNode::EditorNode() {
plugin_init_callbacks[i]();
}
+
+
+
/*resource_preview->add_preview_generator( Ref<EditorTexturePreviewPlugin>( memnew(EditorTexturePreviewPlugin )));
resource_preview->add_preview_generator( Ref<EditorPackedScenePreviewPlugin>( memnew(EditorPackedScenePreviewPlugin )));
resource_preview->add_preview_generator( Ref<EditorMaterialPreviewPlugin>( memnew(EditorMaterialPreviewPlugin )));
@@ -6860,13 +6419,13 @@ EditorNode::EditorNode() {
_initializing_addons=false;
}
- _initializing_tool_menu = false;
- _rebuild_tool_menu();
+
_load_docks();
FileAccess::set_file_close_fail_notify_callback(_file_access_close_error_notify);
+ waiting_for_first_scan=true;
}
diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h
index 2baa9091ff..785136a968 100644
--- a/tools/editor/editor_node.h
+++ b/tools/editor/editor_node.h
@@ -50,6 +50,7 @@
#include "tools/editor/reparent_dialog.h"
#include "tools/editor/connections_dialog.h"
#include "tools/editor/node_dock.h"
+#include "tools/editor/import_dock.h"
#include "tools/editor/settings_config_dialog.h"
#include "tools/editor/groups_editor.h"
#include "tools/editor/editor_data.h"
@@ -134,12 +135,10 @@ private:
FILE_EXPORT_MESH_LIBRARY,
FILE_EXPORT_TILESET,
FILE_SAVE_OPTIMIZED,
- FILE_DUMP_STRINGS,
FILE_OPEN_RECENT,
FILE_OPEN_OLD_SCENE,
FILE_QUICK_OPEN_SCENE,
FILE_QUICK_OPEN_SCRIPT,
- FILE_QUICK_OPEN_FILE,
FILE_RUN_SCRIPT,
FILE_OPEN_PREV,
FILE_CLOSE,
@@ -279,8 +278,9 @@ private:
//ResourcesDock *resources_dock;
PropertyEditor *property_editor;
NodeDock *node_dock;
+ ImportDock *import_dock;
VBoxContainer *prop_editor_vb;
- FileSystemDock *scenes_dock;
+ FileSystemDock *filesystem_dock;
EditorRunNative *run_native;
HBoxContainer *search_bar;
@@ -319,9 +319,6 @@ private:
//TabContainer *prop_pallete;
//TabContainer *top_pallete;
String defer_load_scene;
- String defer_translatable;
- String defer_optimize;
- String defer_optimize_preset;
String defer_export;
String defer_export_platform;
bool defer_export_debug;
@@ -341,7 +338,7 @@ private:
Vector<ToolButton*> main_editor_buttons;
Vector<EditorPlugin*> editor_table;
- EditorReImportDialog *reimport_dialog;
+// EditorReImportDialog *reimport_dialog;
ProgressDialog *progress_dialog;
BackgroundProgress *progress_hb;
@@ -377,6 +374,7 @@ private:
bool unsaved_cache;
String open_navigate;
bool changing_scene;
+ bool waiting_for_first_scan;
bool waiting_for_sources_changed;
@@ -392,8 +390,8 @@ private:
EditorData editor_data;
EditorRun editor_run;
EditorSelection *editor_selection;
- ProjectExport *project_export;
- ProjectExportDialog *project_export_settings;
+// ProjectExport *project_export;
+// ProjectExportDialog *project_export_settings;
EditorResourcePreview *resource_preview;
EditorFileServer *file_server;
@@ -489,7 +487,6 @@ private:
static void _load_error_notify(void* p_ud,const String& p_text);
bool has_main_screen() const { return true; }
- void _fetch_translatable_strings(const Object *p_object,Set<StringName>& strings);
bool _find_editing_changed_scene(Node *p_from);
@@ -648,9 +645,6 @@ public:
void add_control_to_dock(DockSlot p_slot,Control* p_control);
void remove_control_from_dock(Control* p_control);
- void add_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import);
- void remove_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import);
-
void set_addon_plugin_enabled(const String& p_addon,bool p_enabled);
bool is_addon_plugin_enabled(const String &p_addon) const;
@@ -687,7 +681,6 @@ public:
Node *get_edited_scene() { return editor_data.get_edited_scene_root(); }
Viewport *get_scene_root() { return scene_root; } //root of the scene being edited
- Error save_optimized_copy(const String& p_scene,const String& p_preset);
void fix_dependencies(const String& p_for_file);
void clear_scene() { _cleanup_scene(); }
@@ -706,14 +699,13 @@ public:
void request_instance_scene(const String &p_path);
void request_instance_scenes(const Vector<String>& p_files);
- FileSystemDock *get_scenes_dock();
+ FileSystemDock *get_filesystem_dock();
+ ImportDock *get_import_dock();
SceneTreeDock *get_scene_tree_dock();
static UndoRedo* get_undo_redo() { return &singleton->editor_data.get_undo_redo(); }
EditorSelection *get_editor_selection() { return editor_selection; }
- Error save_translatable_strings(const String& p_to_file);
-
void set_convert_old_scene(bool p_old) { convert_old=p_old; }
void notify_child_process_exited();
@@ -788,7 +780,6 @@ public:
};
-
struct EditorProgress {
String task;
diff --git a/tools/editor/editor_plugin.cpp b/tools/editor/editor_plugin.cpp
index 69be7f8a4d..2f44b5558c 100644
--- a/tools/editor/editor_plugin.cpp
+++ b/tools/editor/editor_plugin.cpp
@@ -136,7 +136,7 @@ void EditorPlugin::add_control_to_container(CustomControlContainer p_location,Co
void EditorPlugin::add_tool_menu_item(const String& p_name, Object *p_handler, const String& p_callback, const Variant& p_ud) {
- EditorNode::get_singleton()->add_tool_menu_item(p_name, p_handler, p_callback, p_ud);
+ //EditorNode::get_singleton()->add_tool_menu_item(p_name, p_handler, p_callback, p_ud);
}
void EditorPlugin::add_tool_submenu_item(const String& p_name, Object *p_submenu) {
@@ -144,12 +144,12 @@ void EditorPlugin::add_tool_submenu_item(const String& p_name, Object *p_submenu
ERR_FAIL_NULL(p_submenu);
PopupMenu *submenu = p_submenu->cast_to<PopupMenu>();
ERR_FAIL_NULL(submenu);
- EditorNode::get_singleton()->add_tool_submenu_item(p_name, submenu);
+ //EditorNode::get_singleton()->add_tool_submenu_item(p_name, submenu);
}
void EditorPlugin::remove_tool_menu_item(const String& p_name) {
- EditorNode::get_singleton()->remove_tool_menu_item(p_name);
+ //EditorNode::get_singleton()->remove_tool_menu_item(p_name);
}
Ref<SpatialEditorGizmo> EditorPlugin::create_spatial_gizmo(Spatial* p_spatial) {
@@ -319,27 +319,6 @@ EditorResourcePreview *EditorPlugin::get_resource_previewer() {
return EditorResourcePreview::get_singleton();
}
-void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin>& p_editor_import) {
-
- EditorNode::get_singleton()->add_editor_import_plugin(p_editor_import);
-}
-
-void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin>& p_editor_import){
-
- EditorNode::get_singleton()->remove_editor_import_plugin(p_editor_import);
-
-}
-
-void EditorPlugin::add_export_plugin(const Ref<EditorExportPlugin>& p_editor_export){
-
- EditorImportExport::get_singleton()->add_export_plugin(p_editor_export);
-}
-void EditorPlugin::remove_export_plugin(const Ref<EditorExportPlugin>& p_editor_export){
-
- EditorImportExport::get_singleton()->remove_export_plugin(p_editor_export);
-
-}
-
Control *EditorPlugin::get_base_control() {
return EditorNode::get_singleton()->get_gui_base();
@@ -371,19 +350,13 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(_MD("add_control_to_dock","slot","control:Control"),&EditorPlugin::add_control_to_dock);
ClassDB::bind_method(_MD("remove_control_from_docks","control:Control"),&EditorPlugin::remove_control_from_docks);
ClassDB::bind_method(_MD("remove_control_from_bottom_panel","control:Control"),&EditorPlugin::remove_control_from_bottom_panel);
- ClassDB::bind_method(_MD("add_tool_menu_item", "name", "handler", "callback", "ud"),&EditorPlugin::add_tool_menu_item,DEFVAL(Variant()));
+ //ClassDB::bind_method(_MD("add_tool_menu_item", "name", "handler", "callback", "ud"),&EditorPlugin::add_tool_menu_item,DEFVAL(Variant()));
ClassDB::bind_method(_MD("add_tool_submenu_item", "name", "submenu:PopupMenu"),&EditorPlugin::add_tool_submenu_item);
- ClassDB::bind_method(_MD("remove_tool_menu_item", "name"),&EditorPlugin::remove_tool_menu_item);
+ //ClassDB::bind_method(_MD("remove_tool_menu_item", "name"),&EditorPlugin::remove_tool_menu_item);
ClassDB::bind_method(_MD("add_custom_type","type","base","script:Script","icon:Texture"),&EditorPlugin::add_custom_type);
ClassDB::bind_method(_MD("remove_custom_type","type"),&EditorPlugin::remove_custom_type);
ClassDB::bind_method(_MD("get_editor_viewport:Control"), &EditorPlugin::get_editor_viewport);
- ClassDB::bind_method(_MD("add_import_plugin","plugin:EditorImportPlugin"),&EditorPlugin::add_import_plugin);
- ClassDB::bind_method(_MD("remove_import_plugin","plugin:EditorImportPlugin"),&EditorPlugin::remove_import_plugin);
-
- ClassDB::bind_method(_MD("add_export_plugin","plugin:EditorExportPlugin"),&EditorPlugin::add_export_plugin);
- ClassDB::bind_method(_MD("remove_export_plugin","plugin:EditorExportPlugin"),&EditorPlugin::remove_export_plugin);
-
ClassDB::bind_method(_MD("get_resource_previewer:EditorResourcePreview"),&EditorPlugin::get_resource_previewer);
ClassDB::bind_method(_MD("get_resource_filesystem:EditorFileSystem"),&EditorPlugin::get_resource_file_system);
diff --git a/tools/editor/editor_plugin.h b/tools/editor/editor_plugin.h
index 928b096859..cf998dd55b 100644
--- a/tools/editor/editor_plugin.h
+++ b/tools/editor/editor_plugin.h
@@ -139,12 +139,6 @@ public:
void make_bottom_panel_item_visible(Control *p_item);
void hide_bottom_panel();
- void add_import_plugin(const Ref<EditorImportPlugin>& p_editor_import);
- void remove_import_plugin(const Ref<EditorImportPlugin>& p_editor_import);
-
- void add_export_plugin(const Ref<EditorExportPlugin>& p_editor_export);
- void remove_export_plugin(const Ref<EditorExportPlugin>& p_editor_export);
-
EditorSelection* get_selection();
//EditorImportExport *get_import_export();
EditorSettings *get_editor_settings();
diff --git a/tools/editor/editor_reimport_dialog.cpp b/tools/editor/editor_reimport_dialog.cpp
index e5ae33e919..5904070230 100644
--- a/tools/editor/editor_reimport_dialog.cpp
+++ b/tools/editor/editor_reimport_dialog.cpp
@@ -31,6 +31,7 @@
#include "editor_file_system.h"
#include "editor_node.h"
+#if 0
void EditorReImportDialog::popup_reimport() {
if (EditorFileSystem::get_singleton()->is_scanning()) {
@@ -144,3 +145,4 @@ EditorReImportDialog::EditorReImportDialog() {
scene_must_save=false;
}
+#endif
diff --git a/tools/editor/editor_reimport_dialog.h b/tools/editor/editor_reimport_dialog.h
index 68e1ca0597..7379c70c5e 100644
--- a/tools/editor/editor_reimport_dialog.h
+++ b/tools/editor/editor_reimport_dialog.h
@@ -29,6 +29,7 @@
#ifndef EDITOR_REIMPORT_DIALOG_H
#define EDITOR_REIMPORT_DIALOG_H
+#if 0
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
@@ -49,3 +50,4 @@ public:
};
#endif // EDITOR_REIMPORT_DIALOG_H
+#endif
diff --git a/tools/editor/editor_run_native.cpp b/tools/editor/editor_run_native.cpp
index 12b7b761ed..25cb41befc 100644
--- a/tools/editor/editor_run_native.cpp
+++ b/tools/editor/editor_run_native.cpp
@@ -32,7 +32,7 @@
void EditorRunNative::_notification(int p_what) {
-
+#if 0
if (p_what==NOTIFICATION_ENTER_TREE) {
List<StringName> ep;
@@ -97,11 +97,12 @@ void EditorRunNative::_notification(int p_what) {
first=false;
}
}
-
+#endif
}
void EditorRunNative::_run_native(int p_idx,const String& p_platform) {
+#if 0
Ref<EditorExportPlatform> eep = EditorImportExport::get_singleton()->get_export_platform(p_platform);
ERR_FAIL_COND(eep.is_null());
if (p_idx == -1) {
@@ -125,6 +126,8 @@ void EditorRunNative::_run_native(int p_idx,const String& p_platform) {
flags|=EditorExportPlatform::EXPORT_VIEW_NAVIGATION;
eep->run(p_idx,flags);
+
+#endif
}
void EditorRunNative::_bind_methods() {
diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp
index 27aeaeb5b6..1cdc426541 100644
--- a/tools/editor/editor_settings.cpp
+++ b/tools/editor/editor_settings.cpp
@@ -653,6 +653,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
set("run/auto_save/save_before_running",true);
+ set("run/output/always_clear_output_on_play",true);
+ set("run/output/always_open_output_on_play",true);
set("filesystem/resources/save_compressed_resources",true);
set("filesystem/resources/auto_reload_modified_images",true);
@@ -713,6 +715,7 @@ void EditorSettings::_load_default_text_editor_theme() {
set("text_editor/highlighting/selection_color",Color::html("7b5dbe"));
set("text_editor/highlighting/brace_mismatch_color",Color(1,0.2,0.2));
set("text_editor/highlighting/current_line_color",Color(0.3,0.5,0.8,0.15));
+ set("text_editor/highlighting/line_length_guideline_color",Color(0.3,0.5,0.8,0.1));
set("text_editor/highlighting/mark_color", Color(1.0,0.4,0.4,0.4));
set("text_editor/highlighting/breakpoint_color", Color(0.8,0.8,0.4,0.2));
set("text_editor/highlighting/word_highlighted_color",Color(0.8,0.9,0.9,0.15));
@@ -970,6 +973,7 @@ bool EditorSettings::_save_text_editor_theme(String p_file) {
cf->set_value(theme_section, "selection_color", ((Color)get("text_editor/highlighting/selection_color")).to_html());
cf->set_value(theme_section, "brace_mismatch_color", ((Color)get("text_editor/highlighting/brace_mismatch_color")).to_html());
cf->set_value(theme_section, "current_line_color", ((Color)get("text_editor/highlighting/current_line_color")).to_html());
+ cf->set_value(theme_section, "line_length_guideline_color", ((Color)get("text_editor/highlighting/line_length_guideline_color")).to_html());
cf->set_value(theme_section, "mark_color", ((Color)get("text_editor/highlighting/mark_color")).to_html());
cf->set_value(theme_section, "breakpoint_color", ((Color)get("text_editor/highlighting/breakpoint_color")).to_html());
cf->set_value(theme_section, "word_highlighted_color", ((Color)get("text_editor/highlighting/word_highlighted_color")).to_html());
diff --git a/tools/editor/filesystem_dock.cpp b/tools/editor/filesystem_dock.cpp
index b85bd6dfdb..08b8307eb4 100644
--- a/tools/editor/filesystem_dock.cpp
+++ b/tools/editor/filesystem_dock.cpp
@@ -170,7 +170,7 @@ void FileSystemDock::_notification(int p_what) {
_update_tree(); //maybe it finished already
if (EditorFileSystem::get_singleton()->is_scanning()) {
- _set_scannig_mode();
+ _set_scanning_mode();
}
} break;
@@ -350,25 +350,9 @@ void FileSystemDock::_search(EditorFileSystemDirectory *p_path,List<FileInfo>* m
FileInfo fi;
fi.name=file;
fi.type=p_path->get_file_type(i);
- fi.path=p_path->get_file_path(i);
- if (p_path->get_file_meta(i)) {
- if (p_path->is_missing_sources(i)) {
- fi.import_status=3;
- } else if (p_path->have_sources_changed(i)) {
- fi.import_status=2;
- } else {
- fi.import_status=1;
- }
- } else {
- fi.import_status=0;
- }
- for(int j=0;j<p_path->get_source_count(i);j++) {
- String s = EditorImportPlugin::expand_source_path(p_path->get_source_file(i,j));
- if (p_path->is_source_file_missing(i,j)) {
- s+=" (Missing)";
- }
- fi.sources.push_back(s);
- }
+ fi.path=p_path->get_file_path(i);
+ fi.import_status=0;
+
matches->push_back(fi);
if (matches->size()>p_max_items)
@@ -500,25 +484,7 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
fi.name=efd->get_file(i);
fi.path=path.plus_file(fi.name);
fi.type=efd->get_file_type(i);
- if (efd->get_file_meta(i)) {
- if (efd->is_missing_sources(i)) {
- fi.import_status=3;
- } else if (efd->have_sources_changed(i)) {
- fi.import_status=2;
- } else {
- fi.import_status=1;
- }
-
- for(int j=0;j<efd->get_source_count(i);j++) {
- String s = EditorImportPlugin::expand_source_path(efd->get_source_file(i,j));
- if (efd->is_source_file_missing(i,j)) {
- s+=" (Missing)";
- }
- fi.sources.push_back(s);
- }
- } else {
- fi.import_status=0;
- }
+ fi.import_status=0;
@@ -662,7 +628,7 @@ void FileSystemDock::_fs_changed() {
set_process(false);
}
-void FileSystemDock::_set_scannig_mode() {
+void FileSystemDock::_set_scanning_mode() {
split_box->hide();
button_hist_prev->set_disabled(true);
@@ -1068,7 +1034,7 @@ void FileSystemDock::_file_option(int p_option) {
}
ERR_FAIL_COND(reimport.size()==0);
-
+/*
Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(reimport[0]);
ERR_FAIL_COND(!rimd.is_valid());
String editor=rimd->get_editor();
@@ -1086,6 +1052,7 @@ void FileSystemDock::_file_option(int p_option) {
rimp->reimport_multiple_files(reimport);
}
+ */
} break;
case FILE_COPY_PATH:
@@ -1174,7 +1141,7 @@ void FileSystemDock::_search_changed(const String& p_text) {
void FileSystemDock::_rescan() {
- _set_scannig_mode();
+ _set_scanning_mode();
EditorFileSystem::get_singleton()->scan();
}
@@ -1186,6 +1153,14 @@ void FileSystemDock::fix_dependencies(const String& p_for_file) {
void FileSystemDock::focus_on_filter() {
+ if (!search_box->is_visible_in_tree()) {
+ // Tree mode, switch to files list with search box
+ tree->hide();
+ file_list_vb->show();
+ button_favorite->hide();
+ }
+
+ search_box->grab_focus();
}
void FileSystemDock::set_display_mode(int p_mode) {
@@ -1529,25 +1504,6 @@ void FileSystemDock::_files_list_rmb_select(int p_item,const Vector2& p_pos) {
if (efsd) {
- if (!efsd->get_file_meta(pos)) {
- all_can_reimport=false;
-
-
- } else {
- Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(path);
- if (rimd.is_valid()) {
-
- String editor=rimd->get_editor();
- if (editor.begins_with("texture_")) { //compatibility fix for old texture format
- editor="texture";
- }
- types.insert(editor);
-
- } else {
- all_can_reimport=false;
-
- }
- }
} else {
all_can_reimport=false;
@@ -1595,7 +1551,7 @@ void FileSystemDock::_files_list_rmb_select(int p_item,const Vector2& p_pos) {
if (all_can_reimport && types.size()==1) { //all can reimport and are of the same type
-
+/*
bool valid=true;
Ref<EditorImportPlugin> rimp = EditorImportExport::get_singleton()->get_import_plugin_by_name(types.front()->get());
if (rimp.is_valid()) {
@@ -1611,6 +1567,7 @@ void FileSystemDock::_files_list_rmb_select(int p_item,const Vector2& p_pos) {
file_options->add_separator();
file_options->add_item(TTR("Re-Import.."),FILE_REIMPORT);
}
+ */
}
file_options->set_pos(files->get_global_pos() + p_pos);
@@ -1618,6 +1575,70 @@ void FileSystemDock::_files_list_rmb_select(int p_item,const Vector2& p_pos) {
}
+void FileSystemDock::select_file(const String& p_file) {
+
+ _go_to_dir(p_file.get_base_dir());
+ for(int i=0;i<files->get_item_count();i++) {
+ if (files->get_item_metadata(i)==p_file) {
+ files->select(i);
+ files->ensure_current_is_visible();
+ break;
+ }
+ }
+
+}
+
+void FileSystemDock::_file_multi_selected(int p_index,bool p_selected) {
+
+
+ _file_selected();
+}
+
+void FileSystemDock::_file_selected() {
+
+ //check import
+ Vector<String> imports;
+ String import_type;
+
+ for(int i=0;i<files->get_item_count();i++) {
+ if (!files->is_selected(i))
+ continue;
+
+ String p = files->get_item_metadata(i);
+ if (!FileAccess::exists(p+".import")) {
+ imports.clear();
+ break;
+ }
+ Ref<ConfigFile> cf;
+ cf.instance();
+ Error err = cf->load(p+".import");
+ if (err!=OK) {
+ imports.clear();
+ break;
+ }
+
+ String type = cf->get_value("remap","type");
+ if (import_type=="") {
+ import_type=type;
+ } else if (import_type!=type) {
+ //all should be the same type
+ imports.clear();
+ break;
+ }
+ imports.push_back(p);
+ }
+
+
+ if (imports.size()==0) {
+ EditorNode::get_singleton()->get_import_dock()->clear();
+ } else if (imports.size()==1) {
+ EditorNode::get_singleton()->get_import_dock()->set_edit_path(imports[0]);
+ } else {
+ EditorNode::get_singleton()->get_import_dock()->set_edit_multiple_paths(imports);
+ }
+}
+
+
void FileSystemDock::_bind_methods() {
ClassDB::bind_method(_MD("_update_tree"),&FileSystemDock::_update_tree);
@@ -1649,6 +1670,8 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(_MD("_files_list_rmb_select"),&FileSystemDock::_files_list_rmb_select);
ClassDB::bind_method(_MD("_preview_invalidated"),&FileSystemDock::_preview_invalidated);
+ ClassDB::bind_method(_MD("_file_selected"),&FileSystemDock::_file_selected);
+ ClassDB::bind_method(_MD("_file_multi_selected"),&FileSystemDock::_file_multi_selected);
ADD_SIGNAL(MethodInfo("instance", PropertyInfo(Variant::POOL_STRING_ARRAY, "files")));
@@ -1753,6 +1776,8 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
files->set_select_mode(ItemList::SELECT_MULTI);
files->set_drag_forwarding(this);
files->connect("item_rmb_selected",this,"_files_list_rmb_select");
+ files->connect("item_selected",this,"_file_selected");
+ files->connect("multi_selected",this,"_file_multi_selected");
files->set_allow_rmb_select(true);
file_list_vb = memnew( VBoxContainer );
diff --git a/tools/editor/filesystem_dock.h b/tools/editor/filesystem_dock.h
index ccd43847d6..224efe0f28 100644
--- a/tools/editor/filesystem_dock.h
+++ b/tools/editor/filesystem_dock.h
@@ -126,6 +126,11 @@ private:
Tree * tree; //directories
ItemList *files;
+
+ void _file_multi_selected(int p_index, bool p_selected);
+ void _file_selected();
+
+
void _go_to_tree();
void _go_to_dir(const String& p_dir);
void _select_file(int p_idx);
@@ -153,7 +158,7 @@ private:
void _dir_selected();
void _update_tree();
void _rescan();
- void _set_scannig_mode();
+ void _set_scanning_mode();
void _favorites_pressed();
@@ -199,6 +204,10 @@ public:
void set_display_mode(int p_mode);
+ int get_split_offset() { return split_box->get_split_offset(); }
+ void set_split_offset(int p_offset) { split_box->set_split_offset(p_offset); }
+ void select_file(const String& p_file);
+
FileSystemDock(EditorNode *p_editor);
~FileSystemDock();
};
diff --git a/tools/editor/icons/2x/icon_transparent.png b/tools/editor/icons/2x/icon_transparent.png
new file mode 100644
index 0000000000..627607039b
--- /dev/null
+++ b/tools/editor/icons/2x/icon_transparent.png
Binary files differ
diff --git a/tools/editor/icons/icon_audio_effect_amplify.png b/tools/editor/icons/icon_audio_effect_amplify.png
new file mode 100644
index 0000000000..9af3227d40
--- /dev/null
+++ b/tools/editor/icons/icon_audio_effect_amplify.png
Binary files differ
diff --git a/tools/editor/icons/icon_bus_vu_db.png b/tools/editor/icons/icon_bus_vu_db.png
new file mode 100644
index 0000000000..52507cae52
--- /dev/null
+++ b/tools/editor/icons/icon_bus_vu_db.png
Binary files differ
diff --git a/tools/editor/icons/icon_bus_vu_empty.png b/tools/editor/icons/icon_bus_vu_empty.png
new file mode 100644
index 0000000000..6fc3143a55
--- /dev/null
+++ b/tools/editor/icons/icon_bus_vu_empty.png
Binary files differ
diff --git a/tools/editor/icons/icon_bus_vu_frozen.png b/tools/editor/icons/icon_bus_vu_frozen.png
new file mode 100644
index 0000000000..cf128afa91
--- /dev/null
+++ b/tools/editor/icons/icon_bus_vu_frozen.png
Binary files differ
diff --git a/tools/editor/icons/icon_bus_vu_full.png b/tools/editor/icons/icon_bus_vu_full.png
new file mode 100644
index 0000000000..9e3d7a93e3
--- /dev/null
+++ b/tools/editor/icons/icon_bus_vu_full.png
Binary files differ
diff --git a/tools/editor/icons/icon_transparent.png b/tools/editor/icons/icon_transparent.png
new file mode 100644
index 0000000000..07e9b52b5c
--- /dev/null
+++ b/tools/editor/icons/icon_transparent.png
Binary files differ
diff --git a/tools/editor/icons/icon_vu_db.png b/tools/editor/icons/icon_vu_db.png
new file mode 100644
index 0000000000..405a929e2a
--- /dev/null
+++ b/tools/editor/icons/icon_vu_db.png
Binary files differ
diff --git a/tools/editor/import/SCsub b/tools/editor/import/SCsub
new file mode 100644
index 0000000000..4bf55189cc
--- /dev/null
+++ b/tools/editor/import/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import('env')
+Export('env')
+env.add_source_files(env.tool_sources, "*.cpp")
diff --git a/tools/editor/import/resource_import_texture.cpp b/tools/editor/import/resource_import_texture.cpp
new file mode 100644
index 0000000000..940b932e54
--- /dev/null
+++ b/tools/editor/import/resource_import_texture.cpp
@@ -0,0 +1,274 @@
+#include "resource_import_texture.h"
+#include "io/image_loader.h"
+#include "scene/resources/texture.h"
+
+String ResourceImporterTexture::get_importer_name() const {
+
+ return "texture";
+}
+
+String ResourceImporterTexture::get_visible_name() const{
+
+ return "Texture";
+}
+void ResourceImporterTexture::get_recognized_extensions(List<String> *p_extensions) const{
+
+ ImageLoader::get_recognized_extensions(p_extensions);
+}
+String ResourceImporterTexture::get_save_extension() const {
+ return "stex";
+}
+
+String ResourceImporterTexture::get_resource_type() const{
+
+ return "StreamTexture";
+}
+
+bool ResourceImporterTexture::get_option_visibility(const String& p_option,const Map<StringName,Variant>& p_options) const {
+
+ if (p_option=="compress/lossy_quality" && int(p_options["compress/mode"])!=COMPRESS_LOSSY)
+ return false;
+
+ return true;
+}
+
+int ResourceImporterTexture::get_preset_count() const {
+ return 4;
+}
+String ResourceImporterTexture::get_preset_name(int p_idx) const {
+
+ static const char* preset_names[]={
+ "2D, Detect 3D",
+ "2D",
+ "2D Pixel",
+ "3D"
+ };
+
+ return preset_names[p_idx];
+}
+
+
+void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options,int p_preset) const {
+
+
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT,"compress/mode",PROPERTY_HINT_ENUM,"Lossless,Lossy,Video RAM,Uncompressed",PROPERTY_USAGE_DEFAULT|PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED),p_preset==PRESET_3D?2:0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::REAL,"compress/lossy_quality",PROPERTY_HINT_RANGE,"0,1,0.01"),0.7));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT,"flags/repeat",PROPERTY_HINT_ENUM,"Disabled,Enabled,Mirrored"),p_preset==PRESET_3D?1:0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"flags/filter"),p_preset==PRESET_2D_PIXEL?false:true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"flags/mipmaps"),p_preset==PRESET_3D?true:false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"flags/anisotropic"),false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"flags/srgb",PROPERTY_HINT_ENUM,"Disable,Enable,Detect"),2));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"process/fix_alpha_border"),p_preset!=PRESET_3D?true:false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"process/premult_alpha"),true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT,"stream"),false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT,"size_limit",PROPERTY_HINT_RANGE,"0,4096,1"),0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"detect_3d"),p_preset==PRESET_DETECT));
+
+}
+
+
+void ResourceImporterTexture::_save_stex(const Image& p_image,const String& p_to_path,int p_compress_mode,float p_lossy_quality,Image::CompressMode p_vram_compression,bool p_mipmaps,int p_texture_flags,bool p_streamable) {
+
+
+ FileAccess *f = FileAccess::open(p_to_path,FileAccess::WRITE);
+ f->store_8('G');
+ f->store_8('D');
+ f->store_8('S');
+ f->store_8('T'); //godot streamable texture
+
+ f->store_32(p_image.get_width());
+ f->store_32(p_image.get_height());
+ f->store_32(p_texture_flags);
+
+ uint32_t format=0;
+
+ if (p_streamable)
+ format|=StreamTexture::FORMAT_BIT_STREAM;
+ if (p_mipmaps || p_compress_mode==COMPRESS_VIDEO_RAM) //VRAM always uses mipmaps
+ format|=StreamTexture::FORMAT_BIT_HAS_MIPMAPS; //mipmaps bit
+
+ switch (p_compress_mode) {
+ case COMPRESS_LOSSLESS: {
+
+ Image image = p_image;
+ if (p_mipmaps) {
+ image.generate_mipmaps();
+ } else {
+ image.clear_mipmaps();
+ }
+
+ int mmc = image.get_mipmap_count() + 1;
+
+ format=StreamTexture::FORMAT_BIT_LOSSLESS;
+ f->store_32(format);
+ f->store_32(mmc);
+
+ for(int i=0;i<mmc;i++) {
+
+ if (i>0) {
+ image.shrink_x2();
+ }
+
+ PoolVector<uint8_t> data = Image::lossless_packer(image);
+ int data_len = data.size();
+ f->store_32(data_len);
+
+ PoolVector<uint8_t>::Read r= data.read();
+ f->store_buffer(r.ptr(),data_len);
+
+ }
+
+
+ } break;
+ case COMPRESS_LOSSY: {
+ Image image = p_image;
+ if (p_mipmaps) {
+ image.generate_mipmaps();
+ } else {
+ image.clear_mipmaps();
+ }
+
+ int mmc = image.get_mipmap_count() + 1;
+
+ format=StreamTexture::FORMAT_BIT_LOSSY;
+ f->store_32(format);
+ f->store_32(mmc);
+
+ for(int i=0;i<mmc;i++) {
+
+ if (i>0) {
+ image.shrink_x2();
+ }
+
+ PoolVector<uint8_t> data = Image::lossy_packer(image,p_lossy_quality);
+ int data_len = data.size();
+ f->store_32(data_len);
+
+ PoolVector<uint8_t>::Read r = data.read();
+ f->store_buffer(r.ptr(),data_len);
+
+ }
+ } break;
+ case COMPRESS_VIDEO_RAM: {
+
+ Image image = p_image;
+ image.generate_mipmaps();
+ image.compress(p_vram_compression);
+
+ format |= image.get_format();
+
+ f->store_32(format);
+
+ PoolVector<uint8_t> data=image.get_data();
+ int dl = data.size();
+ PoolVector<uint8_t>::Read r = data.read();
+
+ f->store_buffer(r.ptr(),dl);
+
+ } break;
+ case COMPRESS_UNCOMPRESSED: {
+
+ Image image = p_image;
+ if (p_mipmaps) {
+ image.generate_mipmaps();
+ } else {
+ image.clear_mipmaps();
+ }
+
+ format |= image.get_format();
+ f->store_32(format);
+
+ PoolVector<uint8_t> data=image.get_data();
+ int dl = data.size();
+ PoolVector<uint8_t>::Read r = data.read();
+
+ f->store_buffer(r.ptr(),dl);
+
+ } break;
+ }
+
+ memdelete(f);
+}
+
+Error ResourceImporterTexture::import(const String& p_source_file, const String& p_save_path, const Map<StringName,Variant>& p_options, List<String>* r_platform_variants, List<String> *r_gen_files) {
+
+ int compress_mode = p_options["compress/mode"];
+ float lossy= p_options["compress/lossy_quality"];
+ int repeat= p_options["flags/repeat"];
+ bool filter= p_options["flags/filter"];
+ bool mipmaps= p_options["flags/mipmaps"];
+ bool anisotropic= p_options["flags/anisotropic"];
+ bool srgb= p_options["flags/srgb"];
+ bool fix_alpha_border= p_options["process/fix_alpha_border"];
+ bool premult_alpha= p_options["process/premult_alpha"];
+ bool stream = p_options["stream"];
+ int size_limit = p_options["size_limit"];
+
+
+ Image image;
+ Error err = ImageLoader::load_image(p_source_file,&image);
+ if (err!=OK)
+ return err;
+
+
+ int tex_flags=0;
+ if (repeat>0)
+ tex_flags|=Texture::FLAG_REPEAT;
+ if (repeat==2)
+ tex_flags|=Texture::FLAG_MIRRORED_REPEAT;
+ if (filter)
+ tex_flags|=Texture::FLAG_FILTER;
+ if (mipmaps || compress_mode==COMPRESS_VIDEO_RAM)
+ tex_flags|=Texture::FLAG_MIPMAPS;
+ if (anisotropic)
+ tex_flags|=Texture::FLAG_ANISOTROPIC_FILTER;
+ if (srgb)
+ tex_flags|=Texture::FLAG_CONVERT_TO_LINEAR;
+
+ if (size_limit >0 && (image.get_width()>size_limit || image.get_height()>size_limit )) {
+ //limit size
+ if (image.get_width() >= image.get_height()) {
+ int new_width = size_limit;
+ int new_height = image.get_height() * new_width / image.get_width();
+
+ image.resize(new_width,new_height,Image::INTERPOLATE_CUBIC);
+ } else {
+
+ int new_height = size_limit;
+ int new_width = image.get_width() * new_height / image.get_height();
+
+ image.resize(new_width,new_height,Image::INTERPOLATE_CUBIC);
+ }
+ }
+
+ if (fix_alpha_border) {
+ image.fix_alpha_edges();
+ }
+
+ if (premult_alpha) {
+ image.premultiply_alpha();
+ }
+
+
+ if (compress_mode==COMPRESS_VIDEO_RAM) {
+ //must import in all formats
+ //Android, GLES 2.x
+ _save_stex(image,p_save_path+".etc.stex",compress_mode,lossy,Image::COMPRESS_ETC,mipmaps,tex_flags,stream);
+ r_platform_variants->push_back("etc");
+ //_save_stex(image,p_save_path+".etc2.stex",compress_mode,lossy,Image::COMPRESS_ETC2,mipmaps,tex_flags,stream);
+ //r_platform_variants->push_back("etc2");
+ _save_stex(image,p_save_path+".s3tc.stex",compress_mode,lossy,Image::COMPRESS_S3TC,mipmaps,tex_flags,stream);
+ r_platform_variants->push_back("s3tc");
+
+ } else {
+ //import normally
+ _save_stex(image,p_save_path+".stex",compress_mode,lossy,Image::COMPRESS_16BIT /*this is ignored */,mipmaps,tex_flags,stream);
+ }
+
+ return OK;
+}
+
+ResourceImporterTexture::ResourceImporterTexture()
+{
+
+}
diff --git a/tools/editor/import/resource_import_texture.h b/tools/editor/import/resource_import_texture.h
new file mode 100644
index 0000000000..84f7b77838
--- /dev/null
+++ b/tools/editor/import/resource_import_texture.h
@@ -0,0 +1,43 @@
+#ifndef RESOURCEIMPORTTEXTURE_H
+#define RESOURCEIMPORTTEXTURE_H
+
+#include "io/resource_import.h"
+
+class ResourceImporterTexture : public ResourceImporter {
+ GDCLASS(ResourceImporterTexture,ResourceImporter)
+public:
+ virtual String get_importer_name() const;
+ virtual String get_visible_name() const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual String get_save_extension() const;
+ virtual String get_resource_type() const;
+
+
+ enum Preset {
+ PRESET_DETECT,
+ PRESET_2D,
+ PRESET_2D_PIXEL,
+ PRESET_3D,
+ };
+
+ enum CompressMode {
+ COMPRESS_LOSSLESS,
+ COMPRESS_LOSSY,
+ COMPRESS_VIDEO_RAM,
+ COMPRESS_UNCOMPRESSED
+ };
+
+ virtual int get_preset_count() const;
+ virtual String get_preset_name(int p_idx) const;
+
+ virtual void get_import_options(List<ImportOption> *r_options,int p_preset=0) const;
+ virtual bool get_option_visibility(const String& p_option,const Map<StringName,Variant>& p_options) const;
+
+ void _save_stex(const Image& p_image, const String& p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable);
+
+ virtual Error import(const String& p_source_file,const String& p_save_path,const Map<StringName,Variant>& p_options,List<String>* r_platform_variants,List<String>* r_gen_files=NULL);
+
+ ResourceImporterTexture();
+};
+
+#endif // RESOURCEIMPORTTEXTURE_H
diff --git a/tools/editor/import/resource_importer_csv_translation.cpp b/tools/editor/import/resource_importer_csv_translation.cpp
new file mode 100644
index 0000000000..f14c10fb99
--- /dev/null
+++ b/tools/editor/import/resource_importer_csv_translation.cpp
@@ -0,0 +1,126 @@
+
+#include "resource_importer_csv_translation.h"
+#include "os/file_access.h"
+#include "translation.h"
+#include "io/resource_saver.h"
+#include "compressed_translation.h"
+
+String ResourceImporterCSVTranslation::get_importer_name() const {
+
+ return "csv_translation";
+}
+
+String ResourceImporterCSVTranslation::get_visible_name() const{
+
+ return "CSV Translation";
+}
+void ResourceImporterCSVTranslation::get_recognized_extensions(List<String> *p_extensions) const{
+
+ p_extensions->push_back("csv");
+}
+
+String ResourceImporterCSVTranslation::get_save_extension() const {
+ return ""; //does not save a single resoure
+}
+
+String ResourceImporterCSVTranslation::get_resource_type() const{
+
+ return "StreamCSVTranslation";
+}
+
+bool ResourceImporterCSVTranslation::get_option_visibility(const String& p_option,const Map<StringName,Variant>& p_options) const {
+
+ return true;
+}
+
+int ResourceImporterCSVTranslation::get_preset_count() const {
+ return 0;
+}
+String ResourceImporterCSVTranslation::get_preset_name(int p_idx) const {
+
+ return "";
+}
+
+
+void ResourceImporterCSVTranslation::get_import_options(List<ImportOption> *r_options,int p_preset) const {
+
+
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"compress"),true));
+
+}
+
+
+
+Error ResourceImporterCSVTranslation::import(const String& p_source_file, const String& p_save_path, const Map<StringName,Variant>& p_options, List<String>* r_platform_variants, List<String> *r_gen_files) {
+
+
+ bool compress = p_options["compress"];
+ FileAccessRef f = FileAccess::open(p_source_file,FileAccess::READ);
+
+ ERR_FAIL_COND_V( !f, ERR_INVALID_PARAMETER );
+
+ Vector<String> line = f->get_csv_line();
+ if (line.size()<=1) {
+ return ERR_PARSE_ERROR;
+ }
+
+ Vector<String> locales;
+ Vector<Ref<Translation> > translations;
+
+ for(int i=1;i<line.size();i++) {
+
+ String locale = line[i];
+ if (!TranslationServer::is_locale_valid(locale)) {
+ return ERR_PARSE_ERROR;
+ }
+
+ locales.push_back(locale);
+ Ref<Translation> translation;
+ translation.instance();
+ translation->set_locale(locale);
+ translations.push_back(translation);
+ }
+
+ line = f->get_csv_line();
+
+ while(line.size()==locales.size()+1) {
+
+ String key = line[0];
+ if (key!="") {
+
+ for(int i=1;i<line.size();i++) {
+ translations[i-1]->add_message(key,line[i]);
+ }
+ }
+
+ line = f->get_csv_line();
+ }
+
+
+ for(int i=0;i<translations.size();i++) {
+ Ref<Translation> xlt = translations[i];
+
+ if (compress) {
+ Ref<PHashTranslation> cxl = memnew( PHashTranslation );
+ cxl->generate( xlt );
+ xlt=cxl;
+ }
+
+ String save_path = p_source_file.get_basename()+"."+translations[i]->get_locale()+".xl";
+
+ ResourceSaver::save(save_path,xlt);
+ if (r_gen_files) {
+ r_gen_files->push_back(save_path);
+ }
+ }
+
+
+
+ return OK;
+
+}
+
+ResourceImporterCSVTranslation::ResourceImporterCSVTranslation()
+{
+
+}
diff --git a/tools/editor/import/resource_importer_csv_translation.h b/tools/editor/import/resource_importer_csv_translation.h
new file mode 100644
index 0000000000..d08218e7d9
--- /dev/null
+++ b/tools/editor/import/resource_importer_csv_translation.h
@@ -0,0 +1,27 @@
+#ifndef RESOURCEIMPORTERCSVTRANSLATION_H
+#define RESOURCEIMPORTERCSVTRANSLATION_H
+
+#include "io/resource_import.h"
+
+
+class ResourceImporterCSVTranslation : public ResourceImporter {
+ GDCLASS(ResourceImporterCSVTranslation,ResourceImporter)
+public:
+ virtual String get_importer_name() const;
+ virtual String get_visible_name() const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual String get_save_extension() const;
+ virtual String get_resource_type() const;
+
+ virtual int get_preset_count() const;
+ virtual String get_preset_name(int p_idx) const;
+
+ virtual void get_import_options(List<ImportOption> *r_options,int p_preset=0) const;
+ virtual bool get_option_visibility(const String& p_option,const Map<StringName,Variant>& p_options) const;
+
+ virtual Error import(const String& p_source_file,const String& p_save_path,const Map<StringName,Variant>& p_options,List<String>* r_platform_variants,List<String>* r_gen_files=NULL);
+
+ ResourceImporterCSVTranslation();
+};
+
+#endif // RESOURCEIMPORTERCSVTRANSLATION_H
diff --git a/tools/editor/import_dock.cpp b/tools/editor/import_dock.cpp
new file mode 100644
index 0000000000..b1bd698239
--- /dev/null
+++ b/tools/editor/import_dock.cpp
@@ -0,0 +1,331 @@
+#include "import_dock.h"
+
+class ImportDockParameters : public Object {
+ GDCLASS(ImportDockParameters,Object)
+public:
+ Map<StringName,Variant> values;
+ List<PropertyInfo> properties;
+ Ref<ResourceImporter> importer;
+ Vector<String> paths;
+
+
+ bool _set(const StringName& p_name, const Variant& p_value) {
+
+ if (values.has(p_name)) {
+ values[p_name]=p_value;
+ return true;
+ }
+
+ return false;
+ }
+
+ bool _get(const StringName& p_name,Variant &r_ret) const {
+
+ if (values.has(p_name)) {
+ r_ret=values[p_name];
+ return true;
+ }
+
+ return false;
+
+ }
+ void _get_property_list( List<PropertyInfo> *p_list) const {
+
+ for (const List<PropertyInfo>::Element *E=properties.front();E;E=E->next()) {
+ if (!importer->get_option_visibility(E->get().name,values))
+ continue;
+ p_list->push_back(E->get());
+ }
+ }
+
+ void update() {
+ _change_notify();
+ }
+};
+
+void ImportDock::set_edit_path(const String& p_path) {
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(p_path+".import");
+ if (err!=OK) {
+ clear();
+ return;
+ }
+
+
+ params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(config->get_value("remap","importer"));
+ if (params->importer.is_null()) {
+ clear();
+ return;
+ }
+
+ List<ResourceImporter::ImportOption> options;
+ params->importer->get_import_options(&options);
+
+ params->properties.clear();
+ params->values.clear();
+
+ for (List<ResourceImporter::ImportOption>::Element *E=options.front();E;E=E->next()) {
+
+ params->properties.push_back(E->get().option);
+ if (config->has_section_key("params",E->get().option.name)) {
+ params->values[E->get().option.name]=config->get_value("params",E->get().option.name);
+ } else {
+ params->values[E->get().option.name]=E->get().default_value;
+ }
+ }
+
+ params->update();
+
+ List<Ref<ResourceImporter> > importers;
+ ResourceFormatImporter::get_singleton()->get_importers_for_extension(p_path.get_extension(),&importers);
+ List<Pair<String,String> > importer_names;
+
+ for (List<Ref<ResourceImporter> > ::Element *E=importers.front();E;E=E->next()) {
+ importer_names.push_back(Pair<String,String>(E->get()->get_visible_name(),E->get()->get_importer_name()));
+ }
+
+ importer_names.sort_custom<PairSort<String,String> >();
+
+ import_as->clear();
+
+ for (List<Pair<String,String> >::Element *E=importer_names.front();E;E=E->next()) {
+ import_as->add_item(E->get().first);
+ import_as->set_item_metadata(import_as->get_item_count()-1,E->get().second);
+ if (E->get().second==params->importer->get_importer_name()) {
+ import_as->select(import_as->get_item_count()-1);
+ }
+ }
+
+ preset->get_popup()->clear();
+
+ if (params->importer->get_preset_count()==0) {
+ preset->get_popup()->add_item(TTR("Default"));
+ } else {
+ for (int i=0;i<params->importer->get_preset_count();i++) {
+ preset->get_popup()->add_item(params->importer->get_preset_name(i));
+ }
+ }
+
+ params->paths.clear();
+ params->paths.push_back(p_path);
+ import->set_disabled(false);
+ import_as->set_disabled(false);
+
+ imported->set_text(p_path.get_file());
+}
+
+void ImportDock::set_edit_multiple_paths(const Vector<String>& p_paths) {
+
+ clear();
+
+ //use the value that is repeated the mot
+ Map<String,Dictionary> value_frequency;
+
+ for(int i=0;i<p_paths.size();i++) {
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(p_paths[i]+".import");
+ ERR_CONTINUE(err!=OK);
+
+ if (i==0) {
+ params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(config->get_value("remap","importer"));
+ if (params->importer.is_null()) {
+ clear();
+ return;
+ }
+ }
+
+ List<String> keys;
+ config->get_section_keys("params",&keys);
+
+
+ for (List<String>::Element *E=keys.front();E;E=E->next()) {
+
+ if (!value_frequency.has(E->get())) {
+ value_frequency[E->get()]=Dictionary();
+ }
+
+ Variant value = config->get_value("params",E->get());
+
+ if (value_frequency[E->get()].has(value)) {
+ value_frequency[E->get()][value]=int(value_frequency[E->get()][value])+1;
+ } else {
+ value_frequency[E->get()][value]=1;
+ }
+ }
+
+ }
+
+ ERR_FAIL_COND(params->importer.is_null());
+
+ List<ResourceImporter::ImportOption> options;
+ params->importer->get_import_options(&options);
+
+ params->properties.clear();
+ params->values.clear();
+
+ for (List<ResourceImporter::ImportOption>::Element *E=options.front();E;E=E->next()) {
+
+ params->properties.push_back(E->get().option);
+
+ if (value_frequency.has(E->get().option.name)) {
+
+ Dictionary d = value_frequency[E->get().option.name];
+ int freq=0;
+ List<Variant> v;
+ d.get_key_list(&v);
+ Variant value;
+ for (List<Variant>::Element *F=v.front();F;F=F->next()) {
+ int f = d[F->get()];
+ if (f>freq) {
+ value=F->get();
+ }
+ }
+
+ params->values[E->get().option.name]=value;
+ } else {
+ params->values[E->get().option.name]=E->get().default_value;
+ }
+ }
+
+ params->update();
+
+ List<Ref<ResourceImporter> > importers;
+ ResourceFormatImporter::get_singleton()->get_importers_for_extension(p_paths[0].get_extension(),&importers);
+ List<Pair<String,String> > importer_names;
+
+ for (List<Ref<ResourceImporter> > ::Element *E=importers.front();E;E=E->next()) {
+ importer_names.push_back(Pair<String,String>(E->get()->get_visible_name(),E->get()->get_importer_name()));
+ }
+
+ importer_names.sort_custom<PairSort<String,String> >();
+
+ import_as->clear();
+
+ for (List<Pair<String,String> >::Element *E=importer_names.front();E;E=E->next()) {
+ import_as->add_item(E->get().first);
+ import_as->set_item_metadata(import_as->get_item_count()-1,E->get().second);
+ if (E->get().second==params->importer->get_importer_name()) {
+ import_as->select(import_as->get_item_count()-1);
+ }
+ }
+
+ preset->get_popup()->clear();
+
+ if (params->importer->get_preset_count()==0) {
+ preset->get_popup()->add_item(TTR("Default"));
+ } else {
+ for (int i=0;i<params->importer->get_preset_count();i++) {
+ preset->get_popup()->add_item(params->importer->get_preset_name(i));
+ }
+ }
+
+ params->paths=p_paths;
+ import->set_disabled(false);
+ import_as->set_disabled(false);
+
+ imported->set_text(itos(p_paths.size())+TTR(" Files"));
+}
+
+void ImportDock::_preset_selected(int p_idx) {
+
+ print_line("preset selected? "+p_idx);
+ List<ResourceImporter::ImportOption> options;
+
+ params->importer->get_import_options(&options,p_idx);
+
+ for (List<ResourceImporter::ImportOption>::Element *E=options.front();E;E=E->next()) {
+
+ params->values[E->get().option.name]=E->get().default_value;
+ }
+
+ params->update();
+
+}
+
+
+void ImportDock::clear() {
+
+ imported->set_text("");
+ import->set_disabled(true);
+ import_as->clear();
+ import_as->set_disabled(true);
+ params->values.clear();
+ params->properties.clear();
+ params->update();
+ preset->get_popup()->clear();
+
+}
+
+void ImportDock::_reimport() {
+
+ for(int i=0;i<params->paths.size();i++) {
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(params->paths[i]+".import");
+ ERR_CONTINUE(err!=OK);
+
+ config->erase_section("params");
+
+ for (List<PropertyInfo>::Element *E=params->properties.front();E;E=E->next()) {
+ config->set_value("params",E->get().name,params->values[E->get().name]);
+ }
+
+ config->save(params->paths[i]+".import");
+ }
+
+ EditorFileSystem::get_singleton()->reimport_files(params->paths);
+ EditorFileSystem::get_singleton()->emit_signal("filesystem_changed"); //it changed, so force emitting the signal
+
+}
+
+void ImportDock::_bind_methods() {
+
+ ClassDB::bind_method(_MD("_reimport"),&ImportDock::_reimport);
+ ClassDB::bind_method(_MD("_preset_selected"),&ImportDock::_preset_selected);
+}
+
+ImportDock::ImportDock() {
+
+
+ imported = memnew( LineEdit );
+ imported->set_editable(false);
+ add_child(imported);
+ HBoxContainer *hb = memnew(HBoxContainer);
+ add_margin_child(TTR("Import As:"),hb);
+ import_as = memnew( OptionButton );
+ hb->add_child(import_as);
+ import_as->set_h_size_flags(SIZE_EXPAND_FILL);
+ preset = memnew( MenuButton );
+ preset->set_text(TTR("Preset.."));
+ preset->get_popup()->connect("index_pressed",this,"_preset_selected");
+ hb->add_child(preset);
+
+ import_opts = memnew( PropertyEditor );
+ add_child(import_opts);
+ import_opts->set_v_size_flags(SIZE_EXPAND_FILL);
+ import_opts->hide_top_label();
+ import_opts->set_hide_script(true);
+
+ hb = memnew( HBoxContainer );
+ add_child(hb);
+ import = memnew( Button );
+ import->set_text(TTR("Reimport"));
+ import->connect("pressed",this,"_reimport");
+ hb->add_spacer();
+ hb->add_child(import);
+ hb->add_spacer();
+
+ params = memnew( ImportDockParameters );
+ import_opts->edit(params);
+
+}
+
+ImportDock::~ImportDock() {
+
+ memdelete(params);
+}
diff --git a/tools/editor/import_dock.h b/tools/editor/import_dock.h
new file mode 100644
index 0000000000..bddf5480b8
--- /dev/null
+++ b/tools/editor/import_dock.h
@@ -0,0 +1,42 @@
+#ifndef IMPORTDOCK_H
+#define IMPORTDOCK_H
+
+#include "io/resource_import.h"
+#include "editor_file_system.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/popup_menu.h"
+#include "property_editor.h"
+
+class ImportDockParameters;
+class ImportDock : public VBoxContainer {
+ GDCLASS(ImportDock,VBoxContainer)
+
+ LineEdit *imported;
+ OptionButton *import_as;
+ MenuButton *preset;
+ PropertyEditor *import_opts;
+
+ List<PropertyInfo> properties;
+ Map<StringName,Variant> property_values;
+
+ Button *import;
+
+ ImportDockParameters *params;
+
+ void _preset_selected(int p_idx);
+
+ void _reimport();
+protected:
+ static void _bind_methods();
+public:
+
+ void set_edit_path(const String& p_path);
+ void set_edit_multiple_paths(const Vector<String>& p_paths);
+ void clear();
+
+ ImportDock();
+ ~ImportDock();
+};
+
+#endif // IMPORTDOCK_H
diff --git a/tools/editor/io_plugins/editor_bitmask_import_plugin.cpp b/tools/editor/io_plugins/editor_bitmask_import_plugin.cpp
index 222a9d9517..587353fef8 100644
--- a/tools/editor/io_plugins/editor_bitmask_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_bitmask_import_plugin.cpp
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "editor_bitmask_import_plugin.h"
-
+#if 0
#include "io/image_loader.h"
#include "tools/editor/editor_file_dialog.h"
#include "tools/editor/editor_dir_dialog.h"
@@ -384,3 +384,4 @@ EditorBitMaskImportPlugin::EditorBitMaskImportPlugin(EditorNode* p_editor) {
EditorBitMaskExportPlugin::EditorBitMaskExportPlugin() {
}
+#endif
diff --git a/tools/editor/io_plugins/editor_bitmask_import_plugin.h b/tools/editor/io_plugins/editor_bitmask_import_plugin.h
index 3a6aababe2..89ff58ec93 100644
--- a/tools/editor/io_plugins/editor_bitmask_import_plugin.h
+++ b/tools/editor/io_plugins/editor_bitmask_import_plugin.h
@@ -28,7 +28,7 @@
/*************************************************************************/
#ifndef EDITOR_BITMASK_IMPORT_PLUGIN_H
#define EDITOR_BITMASK_IMPORT_PLUGIN_H
-
+#if 0
#include "tools/editor/editor_import_export.h"
#include "scene/resources/font.h"
@@ -66,4 +66,5 @@ public:
EditorBitMaskExportPlugin();
};
+#endif
#endif // EDITOR_SAMPLE_IMPORT_PLUGIN_H
diff --git a/tools/editor/io_plugins/editor_export_scene.cpp b/tools/editor/io_plugins/editor_export_scene.cpp
index 7d19258411..f4ab9880ff 100644
--- a/tools/editor/io_plugins/editor_export_scene.cpp
+++ b/tools/editor/io_plugins/editor_export_scene.cpp
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "editor_export_scene.h"
-
+#if 0
#include "io/resource_loader.h"
#include "io/resource_saver.h"
#include "os/dir_access.h"
@@ -139,3 +139,4 @@ Vector<uint8_t> EditorSceneExportPlugin::custom_export(String& p_path,const Ref<
EditorSceneExportPlugin::EditorSceneExportPlugin()
{
}
+#endif
diff --git a/tools/editor/io_plugins/editor_export_scene.h b/tools/editor/io_plugins/editor_export_scene.h
index 13493220cb..191029bd84 100644
--- a/tools/editor/io_plugins/editor_export_scene.h
+++ b/tools/editor/io_plugins/editor_export_scene.h
@@ -31,7 +31,7 @@
#include "tools/editor/editor_import_export.h"
-
+#if 0
class EditorSceneExportPlugin : public EditorExportPlugin {
GDCLASS( EditorSceneExportPlugin, EditorExportPlugin );
public:
@@ -40,5 +40,5 @@ public:
EditorSceneExportPlugin();
};
-
+#endif
#endif // EDITOR_EXPORT_SCENE_H
diff --git a/tools/editor/io_plugins/editor_font_import_plugin.cpp b/tools/editor/io_plugins/editor_font_import_plugin.cpp
index ada6000d82..417aad0db8 100644
--- a/tools/editor/io_plugins/editor_font_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_font_import_plugin.cpp
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "editor_font_import_plugin.h"
-
+#if 0
#include "scene/gui/dialogs.h"
#include "tools/editor/editor_file_dialog.h"
#include "tools/editor/editor_node.h"
@@ -1473,7 +1473,7 @@ Ref<BitmapFont> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMe
sum+=w2[ofs_l];
}
- wa[ofs]=Math::pow(float(sum/(r*2+1))/255.0,tr)*255.0;
+ wa[ofs]=Math::pow(float(sum/(r*2+1))/255.0f,tr)*255.0f;
}
}
@@ -1701,3 +1701,4 @@ EditorFontImportPlugin::EditorFontImportPlugin(EditorNode* p_editor) {
dialog = memnew( EditorFontImportDialog(this) );
p_editor->get_gui_base()->add_child(dialog);
}
+#endif
diff --git a/tools/editor/io_plugins/editor_font_import_plugin.h b/tools/editor/io_plugins/editor_font_import_plugin.h
index 73c699c090..a5b265736f 100644
--- a/tools/editor/io_plugins/editor_font_import_plugin.h
+++ b/tools/editor/io_plugins/editor_font_import_plugin.h
@@ -31,7 +31,7 @@
#include "tools/editor/editor_import_export.h"
#include "scene/resources/font.h"
-
+#if 0
class EditorNode;
class EditorFontImportDialog;
@@ -55,3 +55,4 @@ public:
};
#endif // EDITOR_FONT_IMPORT_PLUGIN_H
+#endif
diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp
index a910b9c3ab..963347f18b 100644
--- a/tools/editor/io_plugins/editor_import_collada.cpp
+++ b/tools/editor/io_plugins/editor_import_collada.cpp
@@ -28,6 +28,7 @@
/*************************************************************************/
#include "editor_import_collada.h"
+#if 0
#include "collada/collada.h"
#include "scene/3d/spatial.h"
#include "scene/3d/skeleton.h"
@@ -2464,3 +2465,4 @@ EditorSceneImporterCollada::EditorSceneImporterCollada() {
}
+#endif
diff --git a/tools/editor/io_plugins/editor_import_collada.h b/tools/editor/io_plugins/editor_import_collada.h
index f6642778ed..c325b58e32 100644
--- a/tools/editor/io_plugins/editor_import_collada.h
+++ b/tools/editor/io_plugins/editor_import_collada.h
@@ -31,7 +31,7 @@
#include "tools/editor/io_plugins/editor_scene_import_plugin.h"
-
+#if 0
class EditorSceneImporterCollada : public EditorSceneImporter {
@@ -46,6 +46,6 @@ public:
EditorSceneImporterCollada();
};
-
+#endif
#endif
diff --git a/tools/editor/io_plugins/editor_mesh_import_plugin.cpp b/tools/editor/io_plugins/editor_mesh_import_plugin.cpp
index d07a21fc7d..fc3f8fd8c9 100644
--- a/tools/editor/io_plugins/editor_mesh_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_mesh_import_plugin.cpp
@@ -28,6 +28,8 @@
/*************************************************************************/
#include "editor_mesh_import_plugin.h"
+#if 0
+
#include "tools/editor/editor_file_dialog.h"
#include "tools/editor/editor_dir_dialog.h"
#include "tools/editor/editor_node.h"
@@ -588,3 +590,4 @@ EditorMeshImportPlugin::EditorMeshImportPlugin(EditorNode* p_editor) {
dialog = memnew( EditorMeshImportDialog(this));
p_editor->get_gui_base()->add_child(dialog);
}
+#endif
diff --git a/tools/editor/io_plugins/editor_mesh_import_plugin.h b/tools/editor/io_plugins/editor_mesh_import_plugin.h
index 1f15fee3a7..ba8ec58191 100644
--- a/tools/editor/io_plugins/editor_mesh_import_plugin.h
+++ b/tools/editor/io_plugins/editor_mesh_import_plugin.h
@@ -29,7 +29,7 @@
#ifndef EDITOR_MESH_IMPORT_PLUGIN_H
#define EDITOR_MESH_IMPORT_PLUGIN_H
-
+#if 0
#include "tools/editor/editor_import_export.h"
#include "scene/resources/font.h"
@@ -55,4 +55,5 @@ public:
EditorMeshImportPlugin(EditorNode* p_editor);
};
+#endif
#endif // EDITOR_MESH_IMPORT_PLUGIN_H
diff --git a/tools/editor/io_plugins/editor_sample_import_plugin.cpp b/tools/editor/io_plugins/editor_sample_import_plugin.cpp
index ca873cab72..631291ec1b 100644
--- a/tools/editor/io_plugins/editor_sample_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_sample_import_plugin.cpp
@@ -541,7 +541,7 @@ Error EditorSampleImportPlugin::import(const String& p_path, const Ref<ResourceI
int first=0;
int last=(len*chans)-1;
bool found=false;
- float limit = Math::db2linear(-30);
+ float limit = Math::db2linear((float)-30);
for(int i=0;i<data.size();i++) {
float amp = Math::abs(data[i]);
diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.cpp b/tools/editor/io_plugins/editor_scene_import_plugin.cpp
index ce6c49fcba..bffccb9072 100644
--- a/tools/editor/io_plugins/editor_scene_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_scene_import_plugin.cpp
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "editor_scene_import_plugin.h"
-
+#if 0
#include "globals.h"
#include "tools/editor/editor_node.h"
#include "scene/resources/packed_scene.h"
@@ -2989,3 +2989,4 @@ EditorSceneAnimationImportPlugin::EditorSceneAnimationImportPlugin(EditorNode* p
}
+#endif
diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.h b/tools/editor/io_plugins/editor_scene_import_plugin.h
index 61153e3654..bbafc126bb 100644
--- a/tools/editor/io_plugins/editor_scene_import_plugin.h
+++ b/tools/editor/io_plugins/editor_scene_import_plugin.h
@@ -28,7 +28,7 @@
/*************************************************************************/
#ifndef EDITOR_SCENE_IMPORT_PLUGIN_H
#define EDITOR_SCENE_IMPORT_PLUGIN_H
-
+#if 0
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
#include "scene/gui/label.h"
@@ -196,5 +196,5 @@ public:
};
-
+#endif
#endif // EDITOR_SCENE_IMPORT_PLUGIN_H
diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp
index 8e1bcb8e4b..c41199f291 100644
--- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "editor_texture_import_plugin.h"
-
+#if 0
#include "io/image_loader.h"
#include "tools/editor/editor_node.h"
#include "io/resource_saver.h"
@@ -1890,3 +1890,4 @@ EditorTextureExportPlugin::EditorTextureExportPlugin() {
}
+#endif
diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.h b/tools/editor/io_plugins/editor_texture_import_plugin.h
index b2117f1475..ce15df0f18 100644
--- a/tools/editor/io_plugins/editor_texture_import_plugin.h
+++ b/tools/editor/io_plugins/editor_texture_import_plugin.h
@@ -29,6 +29,12 @@
#ifndef EDITOR_TEXTURE_IMPORT_PLUGIN_H
#define EDITOR_TEXTURE_IMPORT_PLUGIN_H
+
+
+
+
+
+#if 0
#include "tools/editor/editor_import_export.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
@@ -170,3 +176,4 @@ public:
};
#endif // EDITOR_TEXTURE_IMPORT_PLUGIN_H
+#endif
diff --git a/tools/editor/io_plugins/editor_translation_import_plugin.cpp b/tools/editor/io_plugins/editor_translation_import_plugin.cpp
index 7079120feb..9438af9072 100644
--- a/tools/editor/io_plugins/editor_translation_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_translation_import_plugin.cpp
@@ -28,6 +28,7 @@
/*************************************************************************/
#include "editor_translation_import_plugin.h"
+#if 0
#include "scene/gui/file_dialog.h"
#include "tools/editor/editor_dir_dialog.h"
#include "tools/editor/editor_node.h"
@@ -474,3 +475,5 @@ EditorTranslationImportPlugin::EditorTranslationImportPlugin(EditorNode* p_edito
dialog = memnew(EditorTranslationImportDialog(this));
p_editor->get_gui_base()->add_child(dialog);
}
+
+#endif
diff --git a/tools/editor/io_plugins/editor_translation_import_plugin.h b/tools/editor/io_plugins/editor_translation_import_plugin.h
index 38727bd778..4884ea71c5 100644
--- a/tools/editor/io_plugins/editor_translation_import_plugin.h
+++ b/tools/editor/io_plugins/editor_translation_import_plugin.h
@@ -31,7 +31,7 @@
#include "tools/editor/editor_import_export.h"
#include "scene/resources/font.h"
-
+#if 0
class EditorNode;
class EditorTranslationImportDialog;
@@ -52,4 +52,5 @@ public:
EditorTranslationImportPlugin(EditorNode* p_editor);
};
+#endif
#endif // EDITOR_TRANSLATION_IMPORT_PLUGIN_H
diff --git a/tools/editor/plugins/animation_player_editor_plugin.cpp b/tools/editor/plugins/animation_player_editor_plugin.cpp
index b3d16bb660..f10526fb77 100644
--- a/tools/editor/plugins/animation_player_editor_plugin.cpp
+++ b/tools/editor/plugins/animation_player_editor_plugin.cpp
@@ -448,22 +448,27 @@ void AnimationPlayerEditor::_animation_save_as(const Ref<Resource>& p_resource)
file->set_title(TTR("Save Resource As.."));
current_option = RESOURCE_SAVE;
}
+
void AnimationPlayerEditor::_animation_remove() {
- if (animation->get_item_count()==0)
+ if (animation->get_item_count() == 0)
return;
- String current = animation->get_item_text(animation->get_selected());
- Ref<Animation> anim = player->get_animation(current);
+ delete_dialog->set_text(TTR("Delete Animation?"));
+ delete_dialog->popup_centered_minsize();
+}
+
+void AnimationPlayerEditor::_animation_remove_confirmed() {
+ String current = animation->get_item_text(animation->get_selected());
+ Ref<Animation> anim = player->get_animation(current);
undo_redo->create_action(TTR("Remove Animation"));
- undo_redo->add_do_method(player,"remove_animation",current);
- undo_redo->add_undo_method(player,"add_animation",current,anim);
- undo_redo->add_do_method(this,"_animation_player_changed",player);
- undo_redo->add_undo_method(this,"_animation_player_changed",player);
+ undo_redo->add_do_method(player, "remove_animation", current);
+ undo_redo->add_undo_method(player, "add_animation", current, anim);
+ undo_redo->add_do_method(this, "_animation_player_changed", player);
+ undo_redo->add_undo_method(this, "_animation_player_changed", player);
undo_redo->commit_action();
-
}
void AnimationPlayerEditor::_select_anim_by_name(const String& p_anim) {
@@ -1268,6 +1273,7 @@ void AnimationPlayerEditor::_bind_methods() {
ClassDB::bind_method(_MD("_animation_rename"),&AnimationPlayerEditor::_animation_rename);
ClassDB::bind_method(_MD("_animation_load"),&AnimationPlayerEditor::_animation_load);
ClassDB::bind_method(_MD("_animation_remove"),&AnimationPlayerEditor::_animation_remove);
+ ClassDB::bind_method(_MD("_animation_remove_confirmed"),&AnimationPlayerEditor::_animation_remove_confirmed);
ClassDB::bind_method(_MD("_animation_blend"),&AnimationPlayerEditor::_animation_blend);
ClassDB::bind_method(_MD("_animation_edit"),&AnimationPlayerEditor::_animation_edit);
ClassDB::bind_method(_MD("_animation_resource_edit"),&AnimationPlayerEditor::_animation_resource_edit);
@@ -1392,6 +1398,10 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
add_child(accept);
accept->connect("confirmed", this, "_menu_confirm_current");
+ delete_dialog = memnew(ConfirmationDialog);
+ add_child(delete_dialog);
+ delete_dialog->connect("confirmed", this, "_animation_remove_confirmed");
+
duplicate_anim = memnew( ToolButton );
hb->add_child(duplicate_anim);
ED_SHORTCUT("animation_player_editor/duplicate_animation", TTR("Duplicate Animation"));
@@ -1405,7 +1415,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
rename_anim->set_tooltip(TTR("Rename Animation"));
remove_anim = memnew( ToolButton );
-
hb->add_child(remove_anim);
ED_SHORTCUT("animation_player_editor/remove_animation", TTR("Remove Animation"));
remove_anim->set_shortcut(ED_GET_SHORTCUT("animation_player_editor/remove_animation"));
diff --git a/tools/editor/plugins/animation_player_editor_plugin.h b/tools/editor/plugins/animation_player_editor_plugin.h
index 840c39ba49..e28600a7ab 100644
--- a/tools/editor/plugins/animation_player_editor_plugin.h
+++ b/tools/editor/plugins/animation_player_editor_plugin.h
@@ -97,6 +97,7 @@ class AnimationPlayerEditor : public VBoxContainer {
EditorFileDialog *file;
AcceptDialog *accept;
+ ConfirmationDialog* delete_dialog;
int current_option;
struct BlendEditor {
@@ -138,6 +139,7 @@ class AnimationPlayerEditor : public VBoxContainer {
void _animation_save_as(const Ref<Resource>& p_resource);
void _animation_remove();
+ void _animation_remove_confirmed();
void _animation_blend();
void _animation_edit();
void _animation_duplicate();
diff --git a/tools/editor/plugins/canvas_item_editor_plugin.cpp b/tools/editor/plugins/canvas_item_editor_plugin.cpp
index 9dbd2513a0..bec7956b8c 100644
--- a/tools/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/tools/editor/plugins/canvas_item_editor_plugin.cpp
@@ -2354,7 +2354,7 @@ void CanvasItemEditor::_find_canvas_items_span(Node *p_node, Rect2& r_rect, cons
- if (c) {
+ if (c && c->is_visible_in_tree()) {
Rect2 rect = c->get_item_rect();
Transform2D xform = p_xform * c->get_transform();
diff --git a/tools/editor/plugins/canvas_item_editor_plugin.h b/tools/editor/plugins/canvas_item_editor_plugin.h
index f4f628fe28..dac8af5ae9 100644
--- a/tools/editor/plugins/canvas_item_editor_plugin.h
+++ b/tools/editor/plugins/canvas_item_editor_plugin.h
@@ -454,8 +454,8 @@ public:
};
-class CanvasItemEditorViewport : public VBoxContainer {
- GDCLASS( CanvasItemEditorViewport, VBoxContainer );
+class CanvasItemEditorViewport : public Control {
+ GDCLASS( CanvasItemEditorViewport, Control );
String default_type;
Vector<String> types;
diff --git a/tools/editor/plugins/multimesh_editor_plugin.cpp b/tools/editor/plugins/multimesh_editor_plugin.cpp
index 80765be6c0..6259ddf473 100644
--- a/tools/editor/plugins/multimesh_editor_plugin.cpp
+++ b/tools/editor/plugins/multimesh_editor_plugin.cpp
@@ -216,7 +216,7 @@ void MultiMeshEditor::_populate() {
for(int i=0;i<instance_count;i++) {
- float areapos = Math::random(0,area_accum);
+ float areapos = Math::random(0.0f,area_accum);
Map<float,int>::Element *E = triangle_area_map.find_closest(areapos);
ERR_FAIL_COND(!E)
diff --git a/tools/editor/plugins/script_text_editor.cpp b/tools/editor/plugins/script_text_editor.cpp
index e26a3b23bc..9ec6266419 100644
--- a/tools/editor/plugins/script_text_editor.cpp
+++ b/tools/editor/plugins/script_text_editor.cpp
@@ -115,6 +115,7 @@ void ScriptTextEditor::_load_theme_settings() {
text_edit->add_color_override("selection_color",EDITOR_DEF("text_editor/highlighting/selection_color",Color(0.2,0.2,1)));
text_edit->add_color_override("brace_mismatch_color",EDITOR_DEF("text_editor/highlighting/brace_mismatch_color",Color(1,0.2,0.2)));
text_edit->add_color_override("current_line_color",EDITOR_DEF("text_editor/highlighting/current_line_color",Color(0.3,0.5,0.8,0.15)));
+ text_edit->add_color_override("line_length_guideline_color", EDITOR_DEF("text_editor/highlighting/line_length_guideline_color", Color(0,0,0)));
text_edit->add_color_override("word_highlighted_color",EDITOR_DEF("text_editor/highlighting/word_highlighted_color",Color(0.8,0.9,0.9,0.15)));
text_edit->add_color_override("number_color",EDITOR_DEF("text_editor/highlighting/number_color",Color(0.9,0.6,0.0,2)));
text_edit->add_color_override("function_color",EDITOR_DEF("text_editor/highlighting/function_color",Color(0.4,0.6,0.8)));
diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp
index 4b67df3a98..9f8367ff1d 100644
--- a/tools/editor/plugins/spatial_editor_plugin.cpp
+++ b/tools/editor/plugins/spatial_editor_plugin.cpp
@@ -3437,7 +3437,7 @@ void SpatialEditor::_instance_scene() {
#if 0
EditorNode *en = get_scene()->get_root_node()->cast_to<EditorNode>();
ERR_FAIL_COND(!en);
- String path = en->get_scenes_dock()->get_selected_path();
+ String path = en->get_filesystem_dock()->get_selected_path();
if (path=="") {
set_message(TTR("No scene selected to instance!"));
return;
diff --git a/tools/editor/project_export.cpp b/tools/editor/project_export.cpp
index cacefaa1a2..4472cff9cc 100644
--- a/tools/editor/project_export.cpp
+++ b/tools/editor/project_export.cpp
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "project_export.h"
-
+#if 0
#include "os/dir_access.h"
#include "os/file_access.h"
#include "globals.h"
@@ -2127,3 +2127,4 @@ ProjectExport::ProjectExport(EditorData* p_data) {
}
+#endif
diff --git a/tools/editor/project_export.h b/tools/editor/project_export.h
index 06992a7e34..c528a23121 100644
--- a/tools/editor/project_export.h
+++ b/tools/editor/project_export.h
@@ -46,6 +46,7 @@
#include "property_editor.h"
#include "editor_import_export.h"
+#if 0
class EditorNode;
class ProjectExportDialog : public ConfirmationDialog {
@@ -242,3 +243,4 @@ public:
#endif // PROJECT_EXPORT_SETTINGS_H
+#endif
diff --git a/tools/editor/project_settings.cpp b/tools/editor/project_settings.cpp
index 15d03b8a2b..764d1e4546 100644
--- a/tools/editor/project_settings.cpp
+++ b/tools/editor/project_settings.cpp
@@ -1342,7 +1342,7 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
hbc->add_spacer();
- List<StringName> ep;
+ /*List<StringName> ep;
EditorImportExport::get_singleton()->get_export_platforms(&ep);
ep.sort_custom<StringName::AlphCompare>();
@@ -1350,7 +1350,7 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
popup_platform->get_popup()->add_item( E->get() );
- }
+ }*/
popup_platform->get_popup()->connect("id_pressed",this,"_copy_to_platform");
get_ok()->set_text(TTR("Close"));
diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp
index 5326671f41..8e3791eb8d 100644
--- a/tools/editor/property_editor.cpp
+++ b/tools/editor/property_editor.cpp
@@ -118,7 +118,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
Set<String> valid_extensions;
for (List<String>::Element *E=extensions.front();E;E=E->next()) {
-
+ print_line("found: "+E->get());
valid_extensions.insert(E->get());
}
@@ -208,13 +208,13 @@ void CustomPropertyEditor::_menu_option(int p_which) {
case OBJ_MENU_REIMPORT: {
RES r=v;
- if (r.is_valid() && r->get_import_metadata().is_valid()) {
+/* if (r.is_valid() && r->get_import_metadata().is_valid()) {
Ref<ResourceImportMetadata> rimd = r->get_import_metadata();
Ref<EditorImportPlugin> eip = EditorImportExport::get_singleton()->get_import_plugin_by_name(rimd->get_editor());
if (eip.is_valid()) {
eip->import_dialog(r->get_path());
}
- }
+ }*/
} break;
case OBJ_MENU_NEW_SCRIPT: {
@@ -945,11 +945,11 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
menu->add_icon_item(get_icon("EditResource","EditorIcons"),"Edit",OBJ_MENU_EDIT);
menu->add_icon_item(get_icon("Del","EditorIcons"),"Clear",OBJ_MENU_CLEAR);
menu->add_icon_item(get_icon("Duplicate","EditorIcons"),"Make Unique",OBJ_MENU_MAKE_UNIQUE);
- RES r = v;
+ /*RES r = v;
if (r.is_valid() && r->get_path().is_resource_file() && r->get_import_metadata().is_valid()) {
menu->add_separator();
menu->add_icon_item(get_icon("ReloadSmall","EditorIcons"),"Re-Import",OBJ_MENU_REIMPORT);
- }
+ }*/
/*if (r.is_valid() && r->get_path().is_resource_file()) {
menu->set_item_tooltip(1,r->get_path());
} else if (r.is_valid()) {
@@ -1503,12 +1503,12 @@ void CustomPropertyEditor::_drag_easing(const InputEvent& p_ev) {
bool sg = val < 0;
val = Math::absf(val);
- val = Math::log(val)/Math::log(2);
+ val = Math::log(val)/Math::log((float)2.0);
//logspace
val+=rel*0.05;
//
- val = Math::pow(2,val);
+ val = Math::pow(2.0f,val);
if (sg)
val=-val;
@@ -2431,7 +2431,7 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p
} break;
case Variant::COLOR: {
- p_item->set_custom_bg_color(1,obj->get(p_name));
+ tree->update();
//p_item->set_text(1,obj->get(p_name));
} break;
@@ -3140,6 +3140,10 @@ void PropertyEditor::update_tree() {
} else if ( ! (p.usage&PROPERTY_USAGE_EDITOR ) )
continue;
+
+ if (hide_script && p.name=="script/script")
+ continue;
+
String basename=p.name;
if (group!="") {
if (group_base!="") {
@@ -3708,7 +3712,7 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
item->set_editable( 1, !read_only );
//item->set_text(1,obj->get(p.name));
- item->set_custom_bg_color(1,obj->get(p.name));
+ item->set_custom_draw(1,this,"_draw_transparency");
if (show_type_icons)
item->set_icon( 0,get_icon("Color","EditorIcons") );
@@ -3856,6 +3860,25 @@ void PropertyEditor::update_tree() {
}
}
+void PropertyEditor::_draw_transparency(Object *t, const Rect2& p_rect) {
+
+ TreeItem *ti=t->cast_to<TreeItem>();
+ if (!ti)
+ return;
+
+ Color color=obj->get(ti->get_metadata(1));
+ Ref<Texture> arrow=tree->get_icon("select_arrow");
+
+ // make a little space between consecutive color fields
+ Rect2 area=p_rect;
+ area.pos.y+=1;
+ area.size.height-=2;
+ area.size.width-=arrow->get_size().width+5;
+ tree->draw_texture_rect(get_icon("Transparent", "EditorIcons"), area, true);
+ tree->draw_rect(area, color);
+
+}
+
void PropertyEditor::_item_selected() {
@@ -3867,7 +3890,7 @@ void PropertyEditor::_item_selected() {
}
-void PropertyEditor::_edit_set(const String& p_name, const Variant& p_value) {
+void PropertyEditor::_edit_set(const String& p_name, const Variant& p_value, bool p_refresh_all) {
if (autoclear) {
TreeItem *item = tree->get_selected();
@@ -3880,7 +3903,11 @@ void PropertyEditor::_edit_set(const String& p_name, const Variant& p_value) {
if (!undo_redo || obj->cast_to<MultiNodeEdit>() || obj->cast_to<ArrayPropertyEdit>()) { //kind of hacky
obj->set(p_name,p_value);
- _changed_callbacks(obj,p_name);
+ if (p_refresh_all)
+ _changed_callbacks(obj,"");
+ else
+ _changed_callbacks(obj,p_name);
+
emit_signal(_prop_edited,p_name);
@@ -3890,9 +3917,14 @@ void PropertyEditor::_edit_set(const String& p_name, const Variant& p_value) {
undo_redo->add_do_property(obj,p_name,p_value);
undo_redo->add_undo_property(obj,p_name,obj->get(p_name));
+ if (p_refresh_all) {
+ undo_redo->add_do_method(this,"_changed_callback",obj,"");
+ undo_redo->add_undo_method(this,"_changed_callback",obj,"");
+ } else {
- undo_redo->add_do_method(this,"_changed_callback",obj,p_name);
- undo_redo->add_undo_method(this,"_changed_callback",obj,p_name);
+ undo_redo->add_do_method(this,"_changed_callback",obj,p_name);
+ undo_redo->add_undo_method(this,"_changed_callback",obj,p_name);
+ }
Resource *r = obj->cast_to<Resource>();
if (r) {
@@ -3954,6 +3986,9 @@ void PropertyEditor::_item_edited() {
int type=d["type"];
int hint= d["hint"];
+ int usage = d["usage"];
+ bool refresh_all = usage&PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED;
+
String hint_text=d["hint_text"];
switch(type) {
@@ -3962,7 +3997,7 @@ void PropertyEditor::_item_edited() {
} break;
case Variant::BOOL: {
- _edit_set(name,item->is_checked(1));
+ _edit_set(name,item->is_checked(1),refresh_all);
item->set_tooltip(1, item->is_checked(1) ? "True" : "False");
} break;
case Variant::INT:
@@ -3976,9 +4011,9 @@ void PropertyEditor::_item_edited() {
break;
if (type==Variant::INT)
- _edit_set(name,int(item->get_range(1)));
+ _edit_set(name,int(item->get_range(1)),refresh_all);
else
- _edit_set(name,item->get_range(1));
+ _edit_set(name,item->get_range(1),refresh_all);
} break;
case Variant::STRING: {
@@ -3993,9 +4028,9 @@ void PropertyEditor::_item_edited() {
txt=strings[idx];
}
- _edit_set(name,txt);
+ _edit_set(name,txt,refresh_all);
} else {
- _edit_set(name,item->get_text(1));
+ _edit_set(name,item->get_text(1),refresh_all);
}
} break;
// math types
@@ -4026,7 +4061,7 @@ void PropertyEditor::_item_edited() {
} break;
case Variant::NODE_PATH: {
- _edit_set(name, NodePath(item->get_text(1)));
+ _edit_set(name, NodePath(item->get_text(1)),refresh_all);
} break;
@@ -4366,6 +4401,7 @@ void PropertyEditor::_bind_methods() {
ClassDB::bind_method( "update_tree",&PropertyEditor::update_tree);
ClassDB::bind_method( "_resource_preview_done",&PropertyEditor::_resource_preview_done);
ClassDB::bind_method( "refresh",&PropertyEditor::refresh);
+ ClassDB::bind_method( "_draw_transparency",&PropertyEditor::_draw_transparency);
ClassDB::bind_method(_MD("get_drag_data_fw"), &PropertyEditor::get_drag_data_fw);
ClassDB::bind_method(_MD("can_drop_data_fw"), &PropertyEditor::can_drop_data_fw);
@@ -4456,6 +4492,8 @@ PropertyEditor::PropertyEditor() {
_prop_edited="property_edited";
+ hide_script=false;
+
undo_redo=NULL;
obj=NULL;
search_box=NULL;
diff --git a/tools/editor/property_editor.h b/tools/editor/property_editor.h
index 900d06497f..969340d5a2 100644
--- a/tools/editor/property_editor.h
+++ b/tools/editor/property_editor.h
@@ -192,6 +192,7 @@ class PropertyEditor : public Control {
bool use_doc_hints;
bool use_filter;
bool subsection_selectable;
+ bool hide_script;
HashMap<String,String> pending;
String selected_property;
@@ -224,7 +225,7 @@ class PropertyEditor : public Control {
void _node_removed(Node *p_node);
friend class ProjectExportDialog;
- void _edit_set(const String& p_name, const Variant& p_value);
+ void _edit_set(const String& p_name, const Variant& p_value,bool p_refresh_all=false);
void _draw_flags(Object *ti,const Rect2& p_rect);
bool _might_be_in_instance();
@@ -245,6 +246,7 @@ friend class ProjectExportDialog;
void drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from);
void _resource_preview_done(const String& p_path,const Ref<Texture>& p_preview,Variant p_ud);
+ void _draw_transparency(Object *t, const Rect2& p_rect);
UndoRedo *undo_redo;
protected:
@@ -275,6 +277,7 @@ public:
void set_show_categories(bool p_show);
void set_use_doc_hints(bool p_enable) { use_doc_hints=p_enable; }
+ void set_hide_script(bool p_hide) { hide_script=p_hide; }
void set_use_filter(bool p_use);
void register_text_enter(Node *p_line_edit);
diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp
index b3e4c8ed70..ea1de29d0f 100644
--- a/tools/editor/scene_tree_dock.cpp
+++ b/tools/editor/scene_tree_dock.cpp
@@ -768,6 +768,7 @@ Node *SceneTreeDock::_duplicate(Node *p_node, Map<Node*,Node*> &duplimap) {
ERR_FAIL_COND_V(!sd.is_valid(),NULL);
node = sd->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
ERR_FAIL_COND_V(!node,NULL);
+ node->set_scene_instance_load_placeholder(p_node->get_scene_instance_load_placeholder());
//node->generate_instance_state();
} else {
Object *obj = ClassDB::instance(p_node->get_class());
@@ -1760,7 +1761,9 @@ void SceneTreeDock::_nodes_dragged(Array p_nodes,NodePath p_to,int p_type) {
for(int i=0;i<p_nodes.size();i++) {
Node *n=get_node((p_nodes[i]));
- nodes.push_back(n);
+ if (n) {
+ nodes.push_back(n);
+ }
}
if (nodes.size()==0)
diff --git a/tools/editor/scene_tree_editor.cpp b/tools/editor/scene_tree_editor.cpp
index 77640b9c80..dd1fdeb400 100644
--- a/tools/editor/scene_tree_editor.cpp
+++ b/tools/editor/scene_tree_editor.cpp
@@ -208,14 +208,15 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id)
if (n->is_class("Spatial")) {
- bool v = !bool(n->call("is_hidden"));
+ bool v = bool(n->call("is_visible"));
undo_redo->create_action(TTR("Toggle Spatial Visible"));
- undo_redo->add_do_method(n,"_set_visible_",!v);
- undo_redo->add_undo_method(n,"_set_visible_",v);
+ undo_redo->add_do_method(n,"set_visible",!v);
+ undo_redo->add_undo_method(n,"set_visible",v);
undo_redo->commit_action();
+
} else if (n->is_class("CanvasItem")) {
- bool v = !bool(n->call("is_hidden"));
+ bool v = bool(n->call("is_visible"));
undo_redo->create_action(TTR("Toggle CanvasItem Visible"));
undo_redo->add_do_method(n,v?"hide":"show");
undo_redo->add_undo_method(n,v?"show":"hide");
@@ -393,11 +394,11 @@ bool SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
if (is_grouped)
item->add_button(0,get_icon("Group", "EditorIcons"), BUTTON_GROUP);
- bool h = p_node->call("is_hidden");
- if (h)
- item->add_button(0,get_icon("Hidden","EditorIcons"),BUTTON_VISIBILITY);
- else
+ bool v = p_node->call("is_visible");
+ if (v)
item->add_button(0,get_icon("Visible","EditorIcons"),BUTTON_VISIBILITY);
+ else
+ item->add_button(0,get_icon("Hidden","EditorIcons"),BUTTON_VISIBILITY);
if (!p_node->is_connected("visibility_changed",this,"_node_visibility_changed"))
p_node->connect("visibility_changed",this,"_node_visibility_changed",varray(p_node));
@@ -405,11 +406,11 @@ bool SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
_update_visibility_color(p_node, item);
} else if (p_node->is_class("Spatial")) {
- bool h = p_node->call("is_hidden");
- if (h)
- item->add_button(0,get_icon("Hidden","EditorIcons"),BUTTON_VISIBILITY);
- else
+ bool v = p_node->call("is_visible");
+ if (v)
item->add_button(0,get_icon("Visible","EditorIcons"),BUTTON_VISIBILITY);
+ else
+ item->add_button(0,get_icon("Hidden","EditorIcons"),BUTTON_VISIBILITY);
if (!p_node->is_connected("visibility_changed",this,"_node_visibility_changed"))
p_node->connect("visibility_changed",this,"_node_visibility_changed",varray(p_node));
@@ -470,15 +471,16 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
bool visible=false;
if (p_node->is_class("CanvasItem")) {
- visible = !p_node->call("is_hidden");
+ visible = p_node->call("is_visible");
+ CanvasItemEditor::get_singleton()->get_viewport_control()->update();
} else if (p_node->is_class("Spatial")) {
- visible = !p_node->call("is_hidden");
+ visible = p_node->call("is_visible");
}
- if (!visible)
- item->set_button(0,idx,get_icon("Hidden","EditorIcons"));
- else
+ if (visible)
item->set_button(0,idx,get_icon("Visible","EditorIcons"));
+ else
+ item->set_button(0,idx,get_icon("Hidden","EditorIcons"));
_update_visibility_color(p_node, item);
}
diff --git a/tools/editor/script_editor_debugger.cpp b/tools/editor/script_editor_debugger.cpp
index 42ab234d4b..d5cca06820 100644
--- a/tools/editor/script_editor_debugger.cpp
+++ b/tools/editor/script_editor_debugger.cpp
@@ -826,7 +826,7 @@ void ScriptEditorDebugger::_performance_draw() {
Ref<StyleBox> graph_sb = get_stylebox("normal","TextEdit");
Ref<Font> graph_font = get_font("font","TextEdit");
- int cols = Math::ceil(Math::sqrt(which.size()));
+ int cols = Math::ceil(Math::sqrt((float)which.size()));
int rows = (which.size()+1)/cols;
if (which.size()==1)
rows=1;
diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp
index adbac4b12b..c670245282 100644
--- a/tools/editor/spatial_editor_gizmos.cpp
+++ b/tools/editor/spatial_editor_gizmos.cpp
@@ -839,8 +839,8 @@ void LightSpatialGizmo::redraw() {
for(int i=0;i<=360;i++) {
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+1);
+ float ra=Math::deg2rad((float)i);
+ float rb=Math::deg2rad((float)i+1);
Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
@@ -881,8 +881,8 @@ void LightSpatialGizmo::redraw() {
for(int i=0;i<360;i++) {
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+1);
+ float ra=Math::deg2rad((float)i);
+ float rb=Math::deg2rad((float)i+1);
Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*w;
Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*w;
@@ -1519,8 +1519,8 @@ void VehicleWheelSpatialGizmo::redraw() {
const int skip=10;
for(int i=0;i<=360;i+=skip) {
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+skip);
+ float ra=Math::deg2rad((float)i);
+ float rb=Math::deg2rad((float)i+skip);
Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
@@ -1826,8 +1826,8 @@ void CollisionShapeSpatialGizmo::redraw(){
for(int i=0;i<=360;i++) {
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+1);
+ float ra=Math::deg2rad((float)i);
+ float rb=Math::deg2rad((float)i+1);
Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
@@ -1907,8 +1907,8 @@ void CollisionShapeSpatialGizmo::redraw(){
Vector3 d(0,0,height*0.5);
for(int i=0;i<360;i++) {
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+1);
+ float ra=Math::deg2rad((float)i);
+ float rb=Math::deg2rad((float)i+1);
Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*radius;
Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*radius;
@@ -2844,8 +2844,8 @@ void ConeTwistJointSpatialGizmo::redraw() {
//swing
for(int i=0;i<360;i+=10) {
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+10);
+ float ra=Math::deg2rad((float)i);
+ float rb=Math::deg2rad((float)i+10);
Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*w;
Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*w;
@@ -2876,8 +2876,8 @@ void ConeTwistJointSpatialGizmo::redraw() {
for(int i=0;i<int(ts);i+=5) {
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+5);
+ float ra=Math::deg2rad((float)i);
+ float rb=Math::deg2rad((float)i+5);
float c = i/720.0;
float cn = (i+5)/720.0;
Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*w*c;