diff options
-rw-r--r-- | doc/base/classes.xml | 34 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.cpp | 65 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.h | 10 | ||||
-rw-r--r-- | modules/gdscript/gd_editor.cpp | 23 | ||||
-rw-r--r-- | modules/gdscript/gd_script.cpp | 7 | ||||
-rw-r--r-- | modules/stb_vorbis/audio_stream_ogg_vorbis.cpp | 10 |
6 files changed, 133 insertions, 16 deletions
diff --git a/doc/base/classes.xml b/doc/base/classes.xml index e0e88ef348..6f6a094927 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -43086,43 +43086,58 @@ Helper tool to create geometry. </brief_description> <description> - Helper tool to create geometry. + The [SurfaceTool] is used to construct a [Mesh] by specifying vertex attributes individually. It can be used to construct a [Mesh] from script. All properties except index need to be added before a call to [method add_vertex]. For example adding vertex colors and UVs looks like + [codeblock] + var st = SurfaceTool.new() + st.begin(Mesh.PRIMITIVE_TRIANGLES) + st.add_color(Color(1, 0, 0)) + st.add_uv(Vector2(0, 0)) + st.add_vertex(Vector3(0, 0, 0)) + [/codeblock] + The [SurfaceTool] now contains one vertex of a triangle which has a UV coordinate and a specified [Color]. If another vertex were added without calls to [method add_uv] or [method add_color] then the last values would be used. + It is very important that vertex attributes are passed [b]before[/b] the call to [method add_vertex], failure to do this will result in an error when committing the vertex information to a mesh. </description> <methods> <method name="add_bones"> <argument index="0" name="bones" type="PoolIntArray"> </argument> <description> + Add an array of bones for the next Vertex to use. </description> </method> <method name="add_color"> <argument index="0" name="color" type="Color"> </argument> <description> + Specify a [Color] for the next Vertex to use. </description> </method> <method name="add_index"> <argument index="0" name="index" type="int"> </argument> <description> + Adds an index to index array if you are using indexed Vertices. Does not need to be called before adding Vertex. </description> </method> <method name="add_normal"> <argument index="0" name="normal" type="Vector3"> </argument> <description> + Specify a normal for the next Vertex to use. </description> </method> <method name="add_smooth_group"> <argument index="0" name="smooth" type="bool"> </argument> <description> + Specify whether current Vertex (if using only Vertex arrays) or current index (if also using index arrays) should utilize smooth normals for normal calculation. </description> </method> <method name="add_tangent"> <argument index="0" name="tangent" type="Plane"> </argument> <description> + Specify a Tangent for the next Vertex to use. </description> </method> <method name="add_triangle_fan"> @@ -43139,40 +43154,47 @@ <argument index="5" name="tangents" type="Array" default="Array()"> </argument> <description> + Insert a triangle fan made of array data into [Mesh] being constructed. </description> </method> <method name="add_uv"> <argument index="0" name="uv" type="Vector2"> </argument> <description> + Specify UV Coordinate for next Vertex to use. </description> </method> <method name="add_uv2"> <argument index="0" name="uv2" type="Vector2"> </argument> <description> + Specify an optional second set of UV coordinates for next Vertex to use. </description> </method> <method name="add_vertex"> <argument index="0" name="vertex" type="Vector3"> </argument> <description> + Specify position of current Vertex. Should be called after specifying other vertex properties (e.g. Color, UV). </description> </method> <method name="add_weights"> <argument index="0" name="weights" type="PoolRealArray"> </argument> <description> + Specify weight value for next Vertex to use. </description> </method> <method name="begin"> <argument index="0" name="primitive" type="int"> </argument> <description> + Called before adding any Vertices. Takes the primitive type as an argument (e.g. Mesh.PRIMITIVE_TRIANGLES). </description> </method> <method name="clear"> <description> + Clear all information passed into the surface tool so far. </description> </method> <method name="commit"> @@ -43181,24 +43203,29 @@ <argument index="0" name="existing" type="Mesh" default="NULL"> </argument> <description> + Returns a constructed [Mesh] from current information passed in. If an existing [Mesh] is passed in as an argument, will add an extra surface to the existing [Mesh]. </description> </method> <method name="deindex"> <description> + Removes index array by expanding Vertex array. </description> </method> <method name="generate_normals"> <description> + Generates normals from Vertices so you do not have to do it manually. </description> </method> <method name="index"> <description> + Shrinks Vertex array by creating an index array. Avoids reusing Vertices. </description> </method> <method name="set_material"> <argument index="0" name="material" type="Material"> </argument> <description> + Sets [Material] to be used by the [Mesh] you are constructing. </description> </method> </methods> @@ -51969,20 +51996,24 @@ do_property]. </class> <class name="WorldEnvironment" inherits="Spatial" category="Core"> <brief_description> + Sets environment properties for the entire scene </brief_description> <description> + The [WorldEnvironment] node can be added to a scene in order to set default [Environment] variables for the scene. The [WorldEnvironment] can be overridden by an [Environment] node set on the current [Camera]. Additionally, only one [WorldEnvironment] may be instanced in a given scene at a time. The [WorldEnvironment] allows the user to specify default lighting parameters (e.g. ambient lighting), various post-processing effects (e.g. SSAO, DOF, Tonemapping), and how to draw the background (e.g. solid color, skybox). </description> <methods> <method name="get_environment" qualifiers="const"> <return type="Environment"> </return> <description> + Return the [Environment] currently bound. </description> </method> <method name="set_environment"> <argument index="0" name="env" type="Environment"> </argument> <description> + Set the currently bound [Environment] to the one specified. </description> </method> </methods> @@ -52307,3 +52338,4 @@ do_property]. </constants> </class> </doc> + diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index e942d6cebd..84aa4739ea 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -240,6 +240,48 @@ Variant ScriptTextEditor::get_edit_state() { return state; } +void ScriptTextEditor::_convert_case(CaseStyle p_case) { + TextEdit *te = code_editor->get_text_edit(); + Ref<Script> scr = get_edited_script(); + if (scr.is_null()) { + return; + } + + if (te->is_selection_active()) { + te->begin_complex_operation(); + + int begin = te->get_selection_from_line(); + int end = te->get_selection_to_line(); + int begin_col = te->get_selection_from_column(); + int end_col = te->get_selection_to_column(); + + for (int i = begin; i <= end; i++) { + String new_line = te->get_line(i); + + switch (p_case) { + case UPPER: { + new_line = new_line.to_upper(); + } break; + case LOWER: { + new_line = new_line.to_lower(); + } break; + case CAPITALIZE: { + new_line = new_line.capitalize(); + } break; + } + + if (i == begin) { + new_line = te->get_line(i).left(begin_col) + new_line.right(begin_col); + } + if (i == end) { + new_line = new_line.left(end_col) + te->get_line(i).right(end_col); + } + te->set_line(i, new_line); + } + te->end_complex_operation(); + } +} + void ScriptTextEditor::trim_trailing_whitespace() { TextEdit *tx = code_editor->get_text_edit(); @@ -919,7 +961,15 @@ void ScriptTextEditor::_edit_option(int p_op) { case EDIT_PICK_COLOR: { color_panel->popup(); } break; - + case EDIT_TO_UPPERCASE: { + _convert_case(UPPER); + } break; + case EDIT_TO_LOWERCASE: { + _convert_case(LOWER); + } break; + case EDIT_CAPITALIZE: { + _convert_case(CAPITALIZE); + } break; case SEARCH_FIND: { code_editor->get_find_replace_bar()->popup_search(); @@ -1335,6 +1385,15 @@ ScriptTextEditor::ScriptTextEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_breakpoints"), DEBUG_REMOVE_ALL_BREAKPOINTS); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_breakpoint"), DEBUG_GOTO_NEXT_BREAKPOINT); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_breakpoint"), DEBUG_GOTO_PREV_BREAKPOINT); + edit_menu->get_popup()->add_separator(); + PopupMenu *convert_case = memnew(PopupMenu); + convert_case->set_name("convert_case"); + edit_menu->get_popup()->add_child(convert_case); + edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case"); + convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase")), EDIT_TO_UPPERCASE); + convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase")), EDIT_TO_LOWERCASE); + convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize")), EDIT_CAPITALIZE); + convert_case->connect("id_pressed", this, "_edit_option"); search_menu = memnew(MenuButton); edit_hb->add_child(search_menu); @@ -1405,6 +1464,10 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/goto_next_breakpoint", TTR("Goto Next Breakpoint"), KEY_MASK_CTRL | KEY_PERIOD); ED_SHORTCUT("script_text_editor/goto_previous_breakpoint", TTR("Goto Previous Breakpoint"), KEY_MASK_CTRL | KEY_COMMA); + ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Convert To Uppercase"), KEY_MASK_SHIFT | KEY_F4); + ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Convert To Lowercase"), KEY_MASK_SHIFT | KEY_F3); + ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KEY_MASK_SHIFT | KEY_F2); + ED_SHORTCUT("script_text_editor/find", TTR("Find.."), KEY_MASK_CMD | KEY_F); ED_SHORTCUT("script_text_editor/find_next", TTR("Find Next"), KEY_F3); ED_SHORTCUT("script_text_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT | KEY_F3); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 8e089e1ebf..77bce59f2e 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -76,6 +76,9 @@ class ScriptTextEditor : public ScriptEditorBase { EDIT_INDENT_LEFT, EDIT_CLONE_DOWN, EDIT_PICK_COLOR, + EDIT_TO_UPPERCASE, + EDIT_TO_LOWERCASE, + EDIT_CAPITALIZE, SEARCH_FIND, SEARCH_FIND_NEXT, SEARCH_FIND_PREV, @@ -109,6 +112,13 @@ protected: void _goto_line(int p_line) { goto_line(p_line); } void _lookup_symbol(const String &p_symbol, int p_row, int p_column); + enum CaseStyle { + UPPER, + LOWER, + CAPITALIZE, + }; + void _convert_case(CaseStyle p_case); + 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); diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 2a3015c185..ba8df81c15 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -55,11 +55,12 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str "# var a = 2\n" + "# var b = \"textvar\"\n\n" + "func _ready():\n" + - "\t# Called every time the node is added to the scene.\n" + - "\t# Initialization here\n" + - "\tpass\n"; + "%TS%# Called every time the node is added to the scene.\n" + + "%TS%# Initialization here\n" + + "%TS%pass\n"; _template = _template.replace("%BASE%", p_base_class_name); + _template = _template.replace("%TS%", _get_indentation()); Ref<GDScript> script; script.instance(); @@ -2418,16 +2419,18 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base String GDScriptLanguage::_get_indentation() const { #ifdef TOOLS_ENABLED - bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", "Tabs") == "Tabs" ? 0 : 1; + if (SceneTree::get_singleton()->is_editor_hint()) { + bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", "Tabs") == "Tabs" ? 0 : 1; - if (use_space_indentation) { - int indent_size = EDITOR_DEF("text_editor/indent/size", 4); + if (use_space_indentation) { + int indent_size = EDITOR_DEF("text_editor/indent/size", 4); - String space_indent = ""; - for (int i = 0; i < indent_size; i++) { - space_indent += " "; + String space_indent = ""; + for (int i = 0; i < indent_size; i++) { + space_indent += " "; + } + return space_indent; } - return space_indent; } #endif return "\t"; diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index fe20a842cf..173014b138 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -1696,9 +1696,9 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so //same thing for placeholders #ifdef TOOLS_ENABLED - for (Set<PlaceHolderScriptInstance *>::Element *P = E->get()->placeholders.front(); P; P = P->next()) { + while (E->get()->placeholders.size()) { + Object *obj = E->get()->placeholders.front()->get()->get_owner(); - Object *obj = P->get()->get_owner(); //save instance info List<Pair<StringName, Variant> > state; if (obj->get_script_instance()) { @@ -1706,6 +1706,9 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so obj->get_script_instance()->get_property_state(state); map[obj->get_instance_ID()] = state; obj->set_script(RefPtr()); + } else { + // no instance found. Let's remove it so we don't loop forever + E->get()->placeholders.erase(E->get()->placeholders.front()->get()); } } #endif diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp index 227e5e61b6..b0870c9dc2 100644 --- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp @@ -42,6 +42,7 @@ void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_fra int mixed = stb_vorbis_get_samples_float_interleaved(ogg_stream, 2, (float *)p_buffer, todo * 2); todo -= mixed; + frames_mixed += mixed; if (todo) { //end of file! @@ -66,8 +67,8 @@ float AudioStreamPlaybackOGGVorbis::get_stream_sampling_rate() { void AudioStreamPlaybackOGGVorbis::start(float p_from_pos) { - seek_pos(p_from_pos); active = true; + seek_pos(p_from_pos); loops = 0; _begin_resample(); } @@ -95,7 +96,12 @@ void AudioStreamPlaybackOGGVorbis::seek_pos(float p_time) { if (!active) return; - stb_vorbis_seek(ogg_stream, uint32_t(p_time * vorbis_stream->sample_rate)); + if (p_time >= get_length()) { + p_time = 0; + } + frames_mixed = uint32_t(vorbis_stream->sample_rate * p_time); + + stb_vorbis_seek(ogg_stream, frames_mixed); } float AudioStreamPlaybackOGGVorbis::get_length() const { |