diff options
89 files changed, 2485 insertions, 1416 deletions
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index 9f594ba4fa..54b97ac38c 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -58,7 +58,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me for (int i = 0; i < p_points.size(); i++) { - Vector3 sp = p_points[i].snapped(0.0001); + Vector3 sp = p_points[i].snapped(Vector3(0.0001, 0.0001, 0.0001)); if (valid_cache.has(sp)) { valid_points[i] = false; //print_line("INVALIDATED: "+itos(i)); diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index 08ac08d776..1df3c8c298 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -117,7 +117,7 @@ void TriangleMesh::create(const PoolVector<Vector3> &p_faces) { for (int j = 0; j < 3; j++) { int vidx = -1; - Vector3 vs = v[j].snapped(0.0001); + Vector3 vs = v[j].snapped(Vector3(0.0001, 0.0001, 0.0001)); Map<Vector3, int>::Element *E = db.find(vs); if (E) { vidx = E->get(); diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index e413cc147d..efffacb36e 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -61,13 +61,13 @@ int Vector3::max_axis() const { return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0); } -void Vector3::snap(real_t p_val) { +void Vector3::snap(Vector3 p_val) { - x = Math::stepify(x, p_val); - y = Math::stepify(y, p_val); - z = Math::stepify(z, p_val); + x = Math::stepify(x, p_val.x); + y = Math::stepify(y, p_val.y); + z = Math::stepify(z, p_val.z); } -Vector3 Vector3::snapped(real_t p_val) const { +Vector3 Vector3::snapped(Vector3 p_val) const { Vector3 v = *this; v.snap(p_val); diff --git a/core/math/vector3.h b/core/math/vector3.h index 5f4390fbd1..7dfcedd0da 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -81,8 +81,8 @@ struct Vector3 { _FORCE_INLINE_ void zero(); - void snap(real_t p_val); - Vector3 snapped(real_t p_val) const; + void snap(Vector3 p_val); + Vector3 snapped(Vector3 p_val) const; void rotate(const Vector3 &p_axis, real_t p_phi); Vector3 rotated(const Vector3 &p_axis, real_t p_phi) const; diff --git a/core/variant_op.cpp b/core/variant_op.cpp index c4dee5c8a4..5fda6b1473 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -1109,11 +1109,11 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) const String *str = reinterpret_cast<const String *>(p_index._data._mem); Vector2 *v = reinterpret_cast<Vector2 *>(_data._mem); - if (*str == "x" || *str == "width") { + if (*str == "x") { valid = true; v->x = p_value; return; - } else if (*str == "y" || *str == "height") { + } else if (*str == "y") { valid = true; v->y = p_value; return; @@ -1177,7 +1177,7 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) valid = true; v->elements[1] = p_value; return; - } else if (*str == "o") { + } else if (*str == "origin") { valid = true; v->elements[2] = p_value; return; @@ -1572,10 +1572,10 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { const String *str = reinterpret_cast<const String *>(p_index._data._mem); const Vector2 *v = reinterpret_cast<const Vector2 *>(_data._mem); - if (*str == "x" || *str == "width") { + if (*str == "x") { valid = true; return v->x; - } else if (*str == "y" || *str == "height") { + } else if (*str == "y") { valid = true; return v->y; } @@ -1657,7 +1657,7 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { } else if (*str == "y") { valid = true; return v->elements[1]; - } else if (*str == "o") { + } else if (*str == "origin") { valid = true; return v->elements[2]; } @@ -2105,8 +2105,6 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::REAL, "x")); p_list->push_back(PropertyInfo(Variant::REAL, "y")); - p_list->push_back(PropertyInfo(Variant::REAL, "width")); - p_list->push_back(PropertyInfo(Variant::REAL, "height")); } break; // 5 case RECT2: { @@ -2127,7 +2125,7 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::VECTOR2, "x")); p_list->push_back(PropertyInfo(Variant::VECTOR2, "y")); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "o")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "origin")); } break; case PLANE: { diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 8c3569bec0..268d6b44c6 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -348,6 +348,53 @@ void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_coun glBindVertexArray(0); } +void RasterizerCanvasGLES3::_draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { + + glBindVertexArray(data.polygon_buffer_pointer_array); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + + uint32_t buffer_ofs = 0; + + //vertex + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices); + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + buffer_ofs += sizeof(Vector2) * p_vertex_count; + //color + + if (p_singlecolor) { + glDisableVertexAttribArray(VS::ARRAY_COLOR); + Color m = *p_colors; + glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a); + } else if (!p_colors) { + glDisableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + } else { + + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); + glEnableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), ((uint8_t *)0) + buffer_ofs); + buffer_ofs += sizeof(Color) * p_vertex_count; + } + + if (p_uvs) { + + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + buffer_ofs += sizeof(Vector2) * p_vertex_count; + + } else { + glDisableVertexAttribArray(VS::ARRAY_TEX_UV); + } + + glDrawArrays(p_primitive, 0, p_vertex_count); + + storage->frame.canvas_draw_commands++; + + glBindVertexArray(0); +} + void RasterizerCanvasGLES3::_draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs) { static const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN }; @@ -425,22 +472,83 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur glVertexAttrib4f(VS::ARRAY_COLOR, line->color.r, line->color.g, line->color.b, line->color.a); - Vector2 verts[2] = { - Vector2(line->from.x, line->from.y), - Vector2(line->to.x, line->to.y) - }; + if (line->width <= 1) { + Vector2 verts[2] = { + Vector2(line->from.x, line->from.y), + Vector2(line->to.x, line->to.y) + }; #ifdef GLES_OVER_GL - if (line->antialiased) - glEnable(GL_LINE_SMOOTH); + if (line->antialiased) + glEnable(GL_LINE_SMOOTH); #endif - //glLineWidth(line->width); - _draw_gui_primitive(2, verts, NULL, NULL); + //glLineWidth(line->width); + _draw_gui_primitive(2, verts, NULL, NULL); #ifdef GLES_OVER_GL - if (line->antialiased) + if (line->antialiased) + glDisable(GL_LINE_SMOOTH); +#endif + } else { + //thicker line + + Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; + + Vector2 verts[4] = { + line->from - t, + line->from + t, + line->to + t, + line->to - t, + }; + + //glLineWidth(line->width); + _draw_gui_primitive(4, verts, NULL, NULL); +#ifdef GLES_OVER_GL + if (line->antialiased) { + glEnable(GL_LINE_SMOOTH); + for (int i = 0; i < 4; i++) { + Vector2 vertsl[2] = { + verts[i], + verts[(i + 1) % 4], + }; + _draw_gui_primitive(2, vertsl, NULL, NULL); + } + glDisable(GL_LINE_SMOOTH); + } +#endif + } + + } break; + case Item::Command::TYPE_POLYLINE: { + + Item::CommandPolyLine *pline = static_cast<Item::CommandPolyLine *>(c); + _set_texture_rect_mode(false); + + _bind_canvas_texture(RID(), RID()); + + if (pline->triangles.size()) { + + _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1); +#ifdef GLES_OVER_GL + glEnable(GL_LINE_SMOOTH); + if (pline->lines.size()) { + _draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); + } glDisable(GL_LINE_SMOOTH); #endif + } else { + +#ifdef GLES_OVER_GL + if (pline->antialiased) + glEnable(GL_LINE_SMOOTH); +#endif + _draw_generic(GL_LINE_STRIP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); + +#ifdef GLES_OVER_GL + if (pline->antialiased) + glDisable(GL_LINE_SMOOTH); +#endif + } } break; case Item::Command::TYPE_RECT: { diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index ee018e15ea..c0af22b5e8 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -121,6 +121,8 @@ public: _FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs); _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); + _FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); + _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip); _FORCE_INLINE_ void _copy_texscreen(const Rect2 &p_rect); diff --git a/editor/SCsub b/editor/SCsub index ffdeed1523..a26f6bba77 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -143,6 +143,9 @@ def make_translations_header(target, source, env): def make_authors_header(target, source, env): + sections = ["Project Founders", "Lead Developer", "Project Manager", "Developers"] + sections_id = ["dev_founders", "dev_lead", "dev_manager", "dev_names"] + src = source[0].srcnode().abspath dst = target[0].srcnode().abspath f = open(src, "rb") @@ -151,19 +154,35 @@ def make_authors_header(target, source, env): g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") g.write("#ifndef _EDITOR_AUTHORS_H\n") g.write("#define _EDITOR_AUTHORS_H\n") - g.write("static const char *dev_names[] = {\n") + current_section = "" name_count = -1 + + def close_section(): + g.write("\t0\n") + g.write("};\n") + g.write("#define " + current_section.upper() + "_COUNT " + str(name_count) + "\n") + for line in f: if name_count >= 0: if line.startswith(" "): g.write("\t\"" + line.strip() + "\",\n") name_count += 1 - elif line.strip() == "## Developers": - name_count = 0 - g.write("\t0\n") - g.write("};\n") - g.write("#define AUTHORS_COUNT " + str(name_count) + "\n") + continue + if line.startswith("## "): + if name_count >= 0: + close_section() + name_count = -1 + for i in range(len(sections)): + if line.strip().endswith(sections[i]): + current_section = sections_id[i] + name_count = 0 + g.write("static const char *" + current_section + "[] = {\n") + break + + if name_count >= 0: + close_section() + g.write("#endif\n") if (env["tools"] == "yes"): diff --git a/editor/editor_name_dialog.cpp b/editor/editor_name_dialog.cpp index d4c418bfc9..7435e9a9f7 100644 --- a/editor/editor_name_dialog.cpp +++ b/editor/editor_name_dialog.cpp @@ -85,7 +85,6 @@ EditorNameDialog::EditorNameDialog() { add_child(makevb); name = memnew(LineEdit); makevb->add_child(name); - makevb->move_child(name, get_label()->get_index() + 1); name->set_margin(MARGIN_TOP, 5); name->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 5); name->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 5); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 3d119354e1..4525c8f8e5 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -416,6 +416,8 @@ void EditorNode::_fs_changed() { } } } + + _mark_unsaved_scenes(); } void EditorNode::_sources_changed(bool p_exist) { @@ -978,6 +980,29 @@ void EditorNode::_save_all_scenes() { _save_default_environment(); } +void EditorNode::_mark_unsaved_scenes() { + + for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { + + Node *node = editor_data.get_edited_scene_root(i); + if (!node) + continue; + + String path = node->get_filename(); + if (!(path == String() || FileAccess::exists(path))) { + + node->set_filename(""); + if (i == editor_data.get_edited_scene()) + set_current_version(-1); + else + editor_data.set_edited_scene_version(-1, i); + } + } + + _update_title(); + _update_scene_tabs(); +} + void EditorNode::_import_action(const String &p_action) { #if 0 import_confirmation->hide(); @@ -2462,6 +2487,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { confirmation->popup_centered_minsize(); } else { _discard_changes(); + break; } } else { @@ -2488,6 +2514,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } } + if (OS::get_singleton()->is_window_minimized()) + OS::get_singleton()->request_attention(); break; } @@ -2643,7 +2671,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { OS::get_singleton()->shell_open("https://godotengine.org/community"); } break; case HELP_ABOUT: { - about->popup_centered_minsize(Size2(500, 130) * EDSCALE); + about->popup_centered_minsize(Size2(780, 500) * EDSCALE); } break; case SOURCES_REIMPORT: { @@ -4389,8 +4417,14 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) { Ref<InputEventMouseButton> mb = p_input; if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed() && scene_tabs->get_hovered_tab() >= 0) { - _scene_tab_closed(scene_tabs->get_hovered_tab()); + if (scene_tabs->get_hovered_tab() >= 0) { + if (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed()) { + _scene_tab_closed(scene_tabs->get_hovered_tab()); + } + } else { + if ((mb->get_button_index() == BUTTON_LEFT && mb->is_doubleclick()) || (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed())) { + _menu_option_confirm(FILE_NEW_SCENE, true); + } } } } @@ -6039,52 +6073,73 @@ EditorNode::EditorNode() { export_template_manager = memnew(ExportTemplateManager); gui_base->add_child(export_template_manager); - about = memnew(AcceptDialog); - about->set_title(TTR("Thanks from the Godot community!")); - about->get_ok()->set_text(TTR("Thanks!")); - about->set_hide_on_ok(true); - gui_base->add_child(about); - VBoxContainer *vbc = memnew(VBoxContainer); - HBoxContainer *hbc = memnew(HBoxContainer); - hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); - hbc->set_alignment(BoxContainer::ALIGN_CENTER); - about->add_child(vbc); - vbc->add_child(hbc); - Label *about_text = memnew(Label); - about_text->set_text(VERSION_FULL_NAME + String::utf8("\n\u00A9 2007-2017 Juan Linietsky, Ariel Manzur.\n\u00A9 2014-2017 ") + TTR("Godot Engine contributors") + "\n"); - TextureRect *logo = memnew(TextureRect); - logo->set_texture(gui_base->get_icon("Logo", "EditorIcons")); - hbc->add_child(logo); - hbc->add_child(about_text); - TabContainer *tc = memnew(TabContainer); - tc->set_custom_minimum_size(Vector2(740, 300)); - vbc->add_child(tc); - ScrollContainer *dev_base = memnew(ScrollContainer); - dev_base->set_name(TTR("Developers")); - tc->add_child(dev_base); - HBoxContainer *dev_hbc = memnew(HBoxContainer); - dev_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); - dev_base->add_child(dev_hbc); - for (int i = 0; i < 3; i++) { - Label *dev_label = memnew(Label); - dev_label->set_h_size_flags(Control::SIZE_EXPAND); - dev_label->set_v_size_flags(Control::SIZE_FILL); - dev_hbc->add_child(dev_label); - } - int dev_name_index = 0; - int dev_name_column = 0; - const int dev_index_max = AUTHORS_COUNT / 3 + (AUTHORS_COUNT % 3 == 0 ? 0 : 1); - String dev_name = ""; - const char **dev_names_ptr = dev_names; - while (*dev_names_ptr) { - dev_name += String::utf8(*dev_names_ptr++); - if (++dev_name_index == dev_index_max || !*dev_names_ptr) { - dev_hbc->get_child(dev_name_column)->cast_to<Label>()->set_text(dev_name); - dev_name_column++; - dev_name = ""; - dev_name_index = 0; - } else { - dev_name += "\n"; + { + + about = memnew(AcceptDialog); + about->set_title(TTR("Thanks from the Godot community!")); + about->get_ok()->set_text(TTR("Thanks!")); + about->set_hide_on_ok(true); + about->set_resizable(true); + gui_base->add_child(about); + + VBoxContainer *vbc = memnew(VBoxContainer); + HBoxContainer *hbc = memnew(HBoxContainer); + hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hbc->set_alignment(BoxContainer::ALIGN_CENTER); + hbc->add_constant_override("separation", 30 * EDSCALE); + about->add_child(vbc); + vbc->add_child(hbc); + + TextureRect *logo = memnew(TextureRect); + logo->set_texture(gui_base->get_icon("Logo", "EditorIcons")); + hbc->add_child(logo); + + Label *about_text = memnew(Label); + about_text->set_text(VERSION_FULL_NAME + String::utf8("\n\u00A9 2007-2017 Juan Linietsky, Ariel Manzur.\n\u00A9 2014-2017 ") + + TTR("Godot Engine contributors") + "\n"); + hbc->add_child(about_text); + + TabContainer *tc = memnew(TabContainer); + tc->set_custom_minimum_size(Size2(600, 240) * EDSCALE); + tc->set_v_size_flags(Control::SIZE_EXPAND_FILL); + vbc->add_child(tc); + + ScrollContainer *dev_base = memnew(ScrollContainer); + dev_base->set_name(TTR("Authors")); + dev_base->set_v_size_flags(Control::SIZE_EXPAND); + tc->add_child(dev_base); + + VBoxContainer *dev_vbc = memnew(VBoxContainer); + dev_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + dev_base->add_child(dev_vbc); + + List<String> dev_sections; + dev_sections.push_back(TTR("Project Founders")); + dev_sections.push_back(TTR("Lead Developer")); + dev_sections.push_back(TTR("Project Manager")); + dev_sections.push_back(TTR("Developers")); + + const char **dev_src[] = { dev_founders, dev_lead, dev_manager, dev_names }; + + for (int i = 0; i < dev_sections.size(); i++) { + + Label *lbl = memnew(Label); + lbl->set_text(dev_sections[i]); + dev_vbc->add_child(lbl); + + ItemList *il = memnew(ItemList); + il->set_max_columns(32); + il->set_h_size_flags(Control::SIZE_EXPAND_FILL); + il->set_custom_minimum_size(Size2(0, i == 3 ? DEV_NAMES_COUNT * 7.6 : 30) * EDSCALE); + const char **dev_names_ptr = dev_src[i]; + while (*dev_names_ptr) + il->add_item(String::utf8(*dev_names_ptr++), NULL, false); + dev_vbc->add_child(il); + il->set_fixed_column_width(240 * EDSCALE); + + HSeparator *hs = memnew(HSeparator); + hs->set_modulate(Color(0, 0, 0, 0)); + dev_vbc->add_child(hs); } } diff --git a/editor/editor_node.h b/editor/editor_node.h index 5e83cec4a3..24acedbf26 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -529,6 +529,7 @@ private: bool _find_and_save_resource(RES p_res, Map<RES, bool> &processed, int32_t flags); bool _find_and_save_edited_subresources(Object *obj, Map<RES, bool> &processed, int32_t flags); void _save_edited_subresources(Node *scene, Map<RES, bool> &processed, int32_t flags); + void _mark_unsaved_scenes(); void _find_node_types(Node *p_node, int &count_2d, int &count_3d); void _save_scene_with_preview(String p_file); diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index e0a2ea624e..7f91cc86cf 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -554,10 +554,10 @@ static void _generate_tangents_and_binormals(const PoolVector<int> &p_indices, c tangent = Vector3(); } else { tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, - (t2 * z1 - t1 * z2) * r) + (t2 * z1 - t1 * z2) * r) .normalized(); binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, - (s1 * z2 - s2 * z1) * r) + (s1 * z2 - s2 * z1) * r) .normalized(); } @@ -867,7 +867,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me int normal_pos = (normal_src->stride ? normal_src->stride : 3) * p.indices[src + normal_ofs]; ERR_FAIL_INDEX_V(normal_pos, normal_src->array.size(), ERR_INVALID_DATA); vertex.normal = Vector3(normal_src->array[normal_pos + 0], normal_src->array[normal_pos + 1], normal_src->array[normal_pos + 2]); - vertex.normal = vertex.normal.snapped(0.001); + vertex.normal.snap(Vector3(0.001, 0.001, 0.001)); if (tangent_src && binormal_src) { @@ -908,12 +908,20 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me #ifndef NO_UP_AXIS_SWAP if (collada.state.up_axis == Vector3::AXIS_Z) { + Vector3 bn = vertex.normal.cross(vertex.tangent.normal) * vertex.tangent.d; + SWAP(vertex.vertex.z, vertex.vertex.y); vertex.vertex.z = -vertex.vertex.z; SWAP(vertex.normal.z, vertex.normal.y); vertex.normal.z = -vertex.normal.z; SWAP(vertex.tangent.normal.z, vertex.tangent.normal.y); vertex.tangent.normal.z = -vertex.tangent.normal.z; + SWAP(bn.z, bn.y); + bn.z = -bn.z; + + vertex.tangent.d = vertex.normal.cross(vertex.tangent.normal).dot(bn) > 0 ? 1 : -1; + + print_line("Tangent " + itos(p_i) + ": " + vertex.tangent); } #endif diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 1c5aa95ff1..4a2f37e319 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -188,7 +188,7 @@ Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_s Vector3 vertex = vertices[vtx]; if (weld_vertices) - vertex = vertex.snapped(weld_tolerance); + vertex.snap(Vector3(weld_tolerance, weld_tolerance, weld_tolerance)); surf_tool->add_vertex(vertex); } diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 2409f6707d..2ccbd36e18 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -594,7 +594,7 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Array for (int i = 0; i < 3; i++) { - Vector3 v = f.vertex[i].snapped(0.01); + Vector3 v = f.vertex[i].snapped(Vector3(0.01, 0.01, 0.01)); if (!points.has(v)) { points.insert(v); center += v; diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 28c5b89741..c3e1f60ccc 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -254,6 +254,10 @@ void AnimationPlayerEditor::_play_bw_from_pressed() { } void AnimationPlayerEditor::_stop_pressed() { + if (!player) { + return; + } + player->stop(false); play->set_pressed(false); stop->set_pressed(true); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index d729bb7b76..c74eaf21a1 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -774,6 +774,8 @@ CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) { _toggle_button = _editor_node->add_bottom_panel_item(get_name(), _view); _toggle_button->hide(); + + get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator)); } CurveEditorPlugin::~CurveEditorPlugin() { @@ -845,3 +847,74 @@ void CurveEditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("_curve_texture_changed"), &CurveEditorPlugin::_curve_texture_changed); } + +//----------------------------------- +// Preview generator + +bool CurvePreviewGenerator::handles(const String &p_type) const { + return p_type == "Curve"; +} + +Ref<Texture> CurvePreviewGenerator::generate(const Ref<Resource> &p_from) { + + Ref<Curve> curve_ref = p_from; + ERR_FAIL_COND_V(curve_ref.is_null(), Ref<Texture>()); + Curve &curve = **curve_ref; + + int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); + thumbnail_size *= EDSCALE; + Ref<Image> img_ref; + img_ref.instance(); + Image &im = **img_ref; + + im.create(thumbnail_size, thumbnail_size, 0, Image::FORMAT_RGBA8); + + im.lock(); + + Color bg_color(0.1, 0.1, 0.1, 1.0); + for (int i = 0; i < thumbnail_size; i++) { + for (int j = 0; j < thumbnail_size; j++) { + im.put_pixel(i, j, bg_color); + } + } + + Color line_color(0.8, 0.8, 0.8, 1.0); + float range_y = curve.get_max_value() - curve.get_min_value(); + + int prev_y = 0; + for (int x = 0; x < im.get_width(); ++x) { + + float t = static_cast<float>(x) / im.get_width(); + float v = (curve.interpolate_baked(t) - curve.get_min_value()) / range_y; + int y = CLAMP(im.get_height() - v * im.get_height(), 0, im.get_height()); + + // Plot point + if (y >= 0 && y < im.get_height()) { + im.put_pixel(x, y, line_color); + } + + // Plot vertical line to fix discontinuity (not 100% correct but enough for a preview) + if (x != 0 && Math::abs(y - prev_y) > 1) { + int y0, y1; + if (y < prev_y) { + y0 = y; + y1 = prev_y; + } else { + y0 = prev_y; + y1 = y; + } + for (int ly = y0; ly < y1; ++ly) { + im.put_pixel(x, ly, line_color); + } + } + + prev_y = y; + } + + im.unlock(); + + Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); + + ptex->create_from_image(img_ref, 0); + return ptex; +} diff --git a/editor/plugins/curve_editor_plugin.h b/editor/plugins/curve_editor_plugin.h index a4952dfb28..040c298a92 100644 --- a/editor/plugins/curve_editor_plugin.h +++ b/editor/plugins/curve_editor_plugin.h @@ -143,4 +143,11 @@ private: ToolButton *_toggle_button; }; +class CurvePreviewGenerator : public EditorResourcePreviewGenerator { + GDCLASS(CurvePreviewGenerator, EditorResourcePreviewGenerator) +public: + bool handles(const String &p_type) const; + Ref<Texture> generate(const Ref<Resource> &p_from); +}; + #endif // CURVE_EDITOR_PLUGIN_H diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp index 877707d77b..3524c34d62 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_editor_plugin.cpp @@ -104,7 +104,7 @@ void PathSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_p if (SpatialEditor::get_singleton()->is_snap_enabled()) { float snap = SpatialEditor::get_singleton()->get_translate_snap(); - inters.snap(snap); + inters.snap(Vector3(snap, snap, snap)); } Vector3 local = gi.xform(inters); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 0024870665..aedc96d20e 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -509,9 +509,8 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save) { if (p_save) { apply_scripts(); } - if (current->get_edit_menu()) { - memdelete(current->get_edit_menu()); - } + current->clear_edit_menu(); + } else { EditorHelp *help = tab_container->get_child(selected)->cast_to<EditorHelp>(); _add_recent_script(help->get_class()); @@ -1885,6 +1884,9 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { for (int i = 0; i < helps.size(); i++) { String path = helps[i]; + if (path == "") { // invalid, skip + continue; + } _help_class_open(path); } @@ -2180,13 +2182,15 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { script_list = memnew(ItemList); list_split->add_child(script_list); - script_list->set_custom_minimum_size(Size2(0, 0)); + script_list->set_custom_minimum_size(Size2(150 * EDSCALE, 100)); //need to give a bit of limit to avoid it from disappearing + script_list->set_v_size_flags(SIZE_EXPAND_FILL); script_split->set_split_offset(140); - list_split->set_split_offset(500); + //list_split->set_split_offset(500); members_overview = memnew(ItemList); list_split->add_child(members_overview); - members_overview->set_custom_minimum_size(Size2(0, 0)); + members_overview->set_custom_minimum_size(Size2(0, 100)); //need to give a bit of limit to avoid it from disappearing + members_overview->set_v_size_flags(SIZE_EXPAND_FILL); tab_container = memnew(TabContainer); tab_container->add_style_override("panel", p_editor->get_gui_base()->get_stylebox("ScriptPanel", "EditorStyles")); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 3b444c0883..da8248a1a7 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -106,6 +106,7 @@ public: virtual void set_tooltip_request_func(String p_method, Object *p_obj) = 0; virtual Control *get_edit_menu() = 0; + virtual void clear_edit_menu() = 0; ScriptEditorBase() {} }; @@ -363,6 +364,8 @@ public: bool can_take_away_focus() const; + VSplitContainer *get_left_list_split() { return list_split; } + ScriptEditorDebugger *get_debugger() { return debugger; } void set_live_auto_reload_running_scripts(bool p_enabled); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 60fd9d8e30..83741c7fb8 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1093,6 +1093,10 @@ Control *ScriptTextEditor::get_edit_menu() { return edit_hb; } +void ScriptTextEditor::clear_edit_menu() { + memdelete(edit_hb); +} + void ScriptTextEditor::reload(bool p_soft) { TextEdit *te = code_editor->get_text_edit(); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index ba40645161..e55847832f 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -156,7 +156,7 @@ public: virtual void set_debugger_active(bool p_active); Control *get_edit_menu(); - + virtual void clear_edit_menu(); static void register_editor(); ScriptTextEditor(); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index c55bef1b03..995d13f6a8 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -1180,7 +1180,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (_edit.snap || spatial_editor->is_snap_enabled()) { snap = spatial_editor->get_translate_snap(); - motion.snap(snap); + motion.snap(Vector3(snap, snap, snap)); } //set_message("Translating: "+motion); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 70b6257bb2..3563f70d0b 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -90,9 +90,10 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { phys_offset += -s / 2; } - Vector<Ref<Shape2D> > collisions; + Vector<TileSet::ShapeData> collisions; Ref<NavigationPolygon> nav_poly; Ref<OccluderPolygon2D> occluder; + bool found_collisions = false; for (int j = 0; j < mi->get_child_count(); j++) { @@ -106,24 +107,38 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { if (!child2->cast_to<StaticBody2D>()) continue; + + found_collisions = true; + StaticBody2D *sb = child2->cast_to<StaticBody2D>(); List<uint32_t> shapes; sb->get_shape_owners(&shapes); for (List<uint32_t>::Element *E = shapes.front(); E; E = E->next()) { + if (sb->is_shape_owner_disabled(E->get())) continue; - Vector2 shape_offset = sb->shape_owner_get_transform(E->get()).get_origin(); + Transform2D shape_transform = sb->shape_owner_get_transform(E->get()); bool one_way = sb->is_shape_owner_one_way_collision_enabled(E->get()); + shape_transform.set_origin(shape_transform.get_origin() - phys_offset); + for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) { - Ref<Shape> shape = sb->shape_owner_get_shape(E->get(), k); - p_library->tile_add_shape(id, shape, shape_offset, one_way); + Ref<Shape2D> shape = sb->shape_owner_get_shape(E->get(), k); + TileSet::ShapeData shape_data; + shape_data.shape = shape; + shape_data.shape_transform = shape_transform; + shape_data.one_way_collision = one_way; + collisions.push_back(shape_data); } } } + if (found_collisions) { + p_library->tile_set_shapes(id, collisions); + } + p_library->tile_set_texture_offset(id, mi->get_offset()); p_library->tile_set_navigation_polygon(id, nav_poly); p_library->tile_set_light_occluder(id, occluder); diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp index 47e5994e3f..c6af993676 100644 --- a/editor/property_selector.cpp +++ b/editor/property_selector.cpp @@ -167,7 +167,7 @@ void PropertySelector::_update_search() { continue; } - if (!(E->get().usage & PROPERTY_USAGE_EDITOR)) + if (!(E->get().usage & PROPERTY_USAGE_EDITOR) && !(E->get().usage & PROPERTY_USAGE_SCRIPT_VARIABLE)) continue; if (search_box->get_text() != String() && E->get().name.find(search_box->get_text()) == -1) diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index da2d22b900..e8fa3f78cc 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -658,7 +658,91 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } } break; - + case TOOL_SCENE_EDITABLE_CHILDREN: { + List<Node *> selection = editor_selection->get_selected_node_list(); + if (List<Node *>::Element *e = selection.front()) { + if (Node *node = e->get()) { + bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node); + editable = !editable; + + EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, editable); + menu->set_item_checked(18, editable); + if (editable) { + node->set_scene_instance_load_placeholder(false); + menu->set_item_checked(19, false); + } + scene_tree->update_tree(); + } + } + } break; + case TOOL_SCENE_USE_PLACEHOLDER: { + List<Node *> selection = editor_selection->get_selected_node_list(); + if (List<Node *>::Element *e = selection.front()) { + if (Node *node = e->get()) { + bool placeholder = node->get_scene_instance_load_placeholder(); + placeholder = !placeholder; + if (placeholder) + EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, false); + + node->set_scene_instance_load_placeholder(placeholder); + menu->set_item_checked(18, false); + menu->set_item_checked(19, placeholder); + scene_tree->update_tree(); + } + } + } break; + case TOOL_SCENE_CLEAR_INSTANCING: { + List<Node *> selection = editor_selection->get_selected_node_list(); + if (List<Node *>::Element *e = selection.front()) { + if (Node *node = e->get()) { + Node *root = EditorNode::get_singleton()->get_edited_scene(); + UndoRedo *undo_redo = &editor_data->get_undo_redo(); + if (!root) + break; + + ERR_FAIL_COND(node->get_filename() == String()); + + undo_redo->create_action("Discard Instancing"); + undo_redo->add_do_method(node, "set_filename", ""); + undo_redo->add_undo_method(node, "set_filename", node->get_filename()); + _node_replace_owner(node, node, root); + undo_redo->add_do_method(scene_tree, "update_tree"); + undo_redo->add_undo_method(scene_tree, "update_tree"); + undo_redo->commit_action(); + } + } + } break; + case TOOL_SCENE_OPEN: { + List<Node *> selection = editor_selection->get_selected_node_list(); + if (List<Node *>::Element *e = selection.front()) { + if (Node *node = e->get()) { + scene_tree->emit_signal("open", node->get_filename()); + } + } + } break; + case TOOL_SCENE_CLEAR_INHERITANCE: { + clear_inherit_confirm->popup_centered_minsize(); + } break; + case TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM: { + List<Node *> selection = editor_selection->get_selected_node_list(); + if (List<Node *>::Element *e = selection.front()) { + if (Node *node = e->get()) { + node->set_scene_inherited_state(Ref<SceneState>()); + scene_tree->update_tree(); + EditorNode::get_singleton()->get_property_editor()->update_tree(); + } + } + } break; + case TOOL_SCENE_OPEN_INHERITED: { + List<Node *> selection = editor_selection->get_selected_node_list(); + if (List<Node *>::Element *e = selection.front()) { + if (Node *node = e->get()) { + if (node && node->get_scene_inherited_state().is_valid()) { + scene_tree->emit_signal("open", node->get_scene_inherited_state()->get_path()); + } + } + } + } break; default: { if (p_tool >= EDIT_SUBRESOURCE_BASE) { @@ -702,6 +786,29 @@ void SceneTreeDock::_notification(int p_what) { EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", this, "_selection_changed"); } break; + + case NOTIFICATION_ENTER_TREE: { + clear_inherit_confirm->connect("confirmed", this, "_tool_selected", varray(TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM)); + } break; + + case NOTIFICATION_EXIT_TREE: { + clear_inherit_confirm->disconnect("confirmed", this, "_tool_selected"); + } break; + } +} + +void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root) { + + if (p_base != p_node) { + if (p_node->get_owner() == p_base) { + UndoRedo *undo_redo = &editor_data->get_undo_redo(); + undo_redo->add_do_method(p_node, "set_owner", p_root); + undo_redo->add_undo_method(p_node, "set_owner", p_base); + } + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + _node_replace_owner(p_base, p_node->get_child(i), p_root); } } @@ -1769,6 +1876,24 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_icon_shortcut(get_icon("CreateNewSceneFrom", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/save_branch_as_scene"), TOOL_NEW_SCENE_FROM); menu->add_separator(); menu->add_icon_shortcut(get_icon("CopyNodePath", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH); + bool is_external = (selection[0]->get_filename() != "") && (selection[0]->get_owner() != selection[0]); + if (is_external) { + bool is_inherited = selection[0]->get_scene_inherited_state() != NULL; + menu->add_separator(); + if (is_inherited) { + menu->add_item(TTR("Clear Inheritance"), TOOL_SCENE_CLEAR_INHERITANCE); + menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN_INHERITED); + } else { + bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(selection[0]); + bool placeholder = selection[0]->get_scene_instance_load_placeholder(); + menu->add_check_item(TTR("Editable Children"), TOOL_SCENE_EDITABLE_CHILDREN); + menu->add_check_item(TTR("Load As Placeholder"), TOOL_SCENE_USE_PLACEHOLDER); + menu->add_item(TTR("Discard Instancing"), TOOL_SCENE_CLEAR_INSTANCING); + menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN); + menu->set_item_checked(18, editable); + menu->set_item_checked(19, placeholder); + } + } } menu->add_separator(); menu->add_icon_shortcut(get_icon("Remove", "EditorIcons"), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), KEY_DELETE), TOOL_ERASE); @@ -1978,6 +2103,11 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel first_enter = true; restore_script_editor_on_drag = false; + clear_inherit_confirm = memnew(ConfirmationDialog); + clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)")); + clear_inherit_confirm->get_ok()->set_text(TTR("Clear!")); + add_child(clear_inherit_confirm); + vbc->add_constant_override("separation", 4); set_process_input(true); } diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 79e01e7571..5872c5a25d 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -70,7 +70,14 @@ class SceneTreeDock : public VBoxContainer { TOOL_MULTI_EDIT, TOOL_ERASE, TOOL_COPY_NODE_PATH, - TOOL_BUTTON_MAX + TOOL_BUTTON_MAX, + TOOL_SCENE_EDITABLE_CHILDREN, + TOOL_SCENE_USE_PLACEHOLDER, + TOOL_SCENE_CLEAR_INSTANCING, + TOOL_SCENE_OPEN, + TOOL_SCENE_CLEAR_INHERITANCE, + TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM, + TOOL_SCENE_OPEN_INHERITED }; enum { @@ -112,6 +119,7 @@ class SceneTreeDock : public VBoxContainer { TextureRect *filter_icon; PopupMenu *menu; + ConfirmationDialog *clear_inherit_confirm; bool first_enter; @@ -127,6 +135,7 @@ class SceneTreeDock : public VBoxContainer { void _do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform); void _set_owners(Node *p_owner, const Array &p_nodes); + void _node_replace_owner(Node *p_base, Node *p_node, Node *p_root); void _load_request(const String &p_path); void _script_open_request(const Ref<Script> &p_script); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index d4e5714c0d..d12d8b5528 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -44,110 +44,6 @@ Node *SceneTreeEditor::get_scene_node() { return get_tree()->get_edited_scene_root(); } -void SceneTreeEditor::_subscene_option(int p_idx) { - - Object *obj = ObjectDB::get_instance(instance_node); - if (!obj) - return; - Node *node = obj->cast_to<Node>(); - if (!node) - return; - - switch (p_idx) { - - case SCENE_MENU_EDITABLE_CHILDREN: { - - bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node); - editable = !editable; - - //node->set_instance_children_editable(editable); - EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, editable); - instance_menu->set_item_checked(0, editable); - if (editable) { - node->set_scene_instance_load_placeholder(false); - instance_menu->set_item_checked(1, false); - } - - _update_tree(); - - } break; - case SCENE_MENU_USE_PLACEHOLDER: { - - bool placeholder = node->get_scene_instance_load_placeholder(); - placeholder = !placeholder; - - //node->set_instance_children_editable(editable); - if (placeholder) { - EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, false); - } - node->set_scene_instance_load_placeholder(placeholder); - instance_menu->set_item_checked(0, false); - instance_menu->set_item_checked(1, placeholder); - - _update_tree(); - - } break; - case SCENE_MENU_OPEN: { - - emit_signal("open", node->get_filename()); - } break; - case SCENE_MENU_CLEAR_INHERITANCE: { - clear_inherit_confirm->popup_centered_minsize(); - } break; - case SCENE_MENU_CLEAR_INSTANCING: { - - Node *root = EditorNode::get_singleton()->get_edited_scene(); - if (!root) - break; - - ERR_FAIL_COND(node->get_filename() == String()); - - undo_redo->create_action("Discard Instancing"); - - undo_redo->add_do_method(node, "set_filename", ""); - undo_redo->add_undo_method(node, "set_filename", node->get_filename()); - - _node_replace_owner(node, node, root); - - undo_redo->add_do_method(this, "update_tree"); - undo_redo->add_undo_method(this, "update_tree"); - - undo_redo->commit_action(); - - } break; - case SCENE_MENU_OPEN_INHERITED: { - if (node && node->get_scene_inherited_state().is_valid()) { - emit_signal("open", node->get_scene_inherited_state()->get_path()); - } - } break; - case SCENE_MENU_CLEAR_INHERITANCE_CONFIRM: { - if (node && node->get_scene_inherited_state().is_valid()) { - node->set_scene_inherited_state(Ref<SceneState>()); - update_tree(); - EditorNode::get_singleton()->get_property_editor()->update_tree(); - } - - } break; - } -} - -void SceneTreeEditor::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root) { - - if (p_base != p_node) { - - if (p_node->get_owner() == p_base) { - - undo_redo->add_do_method(p_node, "set_owner", p_root); - undo_redo->add_undo_method(p_node, "set_owner", p_base); - } - } - - for (int i = 0; i < p_node->get_child_count(); i++) { - - _node_replace_owner(p_base, p_node->get_child(i), p_root); - } -} - void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_id) { TreeItem *item = p_item->cast_to<TreeItem>(); @@ -159,38 +55,13 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i ERR_FAIL_COND(!n); if (p_id == BUTTON_SUBSCENE) { - //open scene request - Rect2 item_rect = tree->get_item_rect(item, 0); - item_rect.position.y -= tree->get_scroll().y; - item_rect.position += tree->get_global_position(); - if (n == get_scene_node()) { - inheritance_menu->set_position(item_rect.position + Vector2(0, item_rect.size.y)); - inheritance_menu->set_size(Vector2(item_rect.size.x, 0)); - inheritance_menu->popup(); - instance_node = n->get_instance_ID(); - - } else { - instance_menu->set_position(item_rect.position + Vector2(0, item_rect.size.y)); - instance_menu->set_size(Vector2(item_rect.size.x, 0)); - if (EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(n)) - instance_menu->set_item_checked(0, true); - else - instance_menu->set_item_checked(0, false); - - if (n->get_owner() == get_scene_node()) { - instance_menu->set_item_checked(1, n->get_scene_instance_load_placeholder()); - instance_menu->set_item_disabled(1, false); - } else { - - instance_menu->set_item_checked(1, false); - instance_menu->set_item_disabled(1, true); + if (n && n->get_scene_inherited_state().is_valid()) { + emit_signal("open", n->get_scene_inherited_state()->get_path()); } - - instance_menu->popup(); - instance_node = n->get_instance_ID(); + } else { + emit_signal("open", n->get_filename()); } - //emit_signal("open",n->get_filename()); } else if (p_id == BUTTON_SCRIPT) { RefPtr script = n->get_script(); if (!script.is_null()) @@ -472,7 +343,7 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) { void SceneTreeEditor::_update_visibility_color(Node *p_node, TreeItem *p_item) { if (p_node->is_class("CanvasItem") || p_node->is_class("Spatial")) { Color color(1, 1, 1, 1); - bool visible_on_screen = p_node->call("is_visible"); + bool visible_on_screen = p_node->call("is_visible_in_tree"); if (!visible_on_screen) { color = Color(0.6, 0.6, 0.6, 1); } @@ -633,10 +504,7 @@ void SceneTreeEditor::_notification(int p_what) { get_tree()->connect("node_removed", this, "_node_removed"); get_tree()->connect("node_configuration_warning_changed", this, "_warning_changed"); - instance_menu->set_item_icon(5, get_icon("Load", "EditorIcons")); tree->connect("item_collapsed", this, "_cell_collapsed"); - inheritance_menu->set_item_icon(2, get_icon("Load", "EditorIcons")); - clear_inherit_confirm->connect("confirmed", this, "_subscene_option", varray(SCENE_MENU_CLEAR_INHERITANCE_CONFIRM)); EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed"); @@ -649,7 +517,6 @@ void SceneTreeEditor::_notification(int p_what) { get_tree()->disconnect("tree_changed", this, "_tree_changed"); get_tree()->disconnect("node_removed", this, "_node_removed"); tree->disconnect("item_collapsed", this, "_cell_collapsed"); - clear_inherit_confirm->disconnect("confirmed", this, "_subscene_option"); get_tree()->disconnect("node_configuration_warning_changed", this, "_warning_changed"); EditorSettings::get_singleton()->disconnect("settings_changed", this, "_editor_settings_changed"); } @@ -1059,7 +926,6 @@ void SceneTreeEditor::_bind_methods() { ClassDB::bind_method("_selection_changed", &SceneTreeEditor::_selection_changed); ClassDB::bind_method("_cell_button_pressed", &SceneTreeEditor::_cell_button_pressed); ClassDB::bind_method("_cell_collapsed", &SceneTreeEditor::_cell_collapsed); - ClassDB::bind_method("_subscene_option", &SceneTreeEditor::_subscene_option); ClassDB::bind_method("_rmb_select", &SceneTreeEditor::_rmb_select); ClassDB::bind_method("_warning_changed", &SceneTreeEditor::_warning_changed); @@ -1145,29 +1011,6 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope updating_tree = false; blocked = 0; - instance_menu = memnew(PopupMenu); - instance_menu->add_check_item(TTR("Editable Children"), SCENE_MENU_EDITABLE_CHILDREN); - instance_menu->add_check_item(TTR("Load As Placeholder"), SCENE_MENU_USE_PLACEHOLDER); - instance_menu->add_separator(); - instance_menu->add_item(TTR("Discard Instancing"), SCENE_MENU_CLEAR_INSTANCING); - instance_menu->add_separator(); - instance_menu->add_item(TTR("Open in Editor"), SCENE_MENU_OPEN); - instance_menu->connect("id_pressed", this, "_subscene_option"); - add_child(instance_menu); - - inheritance_menu = memnew(PopupMenu); - inheritance_menu->add_item(TTR("Clear Inheritance"), SCENE_MENU_CLEAR_INHERITANCE); - inheritance_menu->add_separator(); - inheritance_menu->add_item(TTR("Open in Editor"), SCENE_MENU_OPEN_INHERITED); - inheritance_menu->connect("id_pressed", this, "_subscene_option"); - - add_child(inheritance_menu); - - clear_inherit_confirm = memnew(ConfirmationDialog); - clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)")); - clear_inherit_confirm->get_ok()->set_text(TTR("Clear!")); - add_child(clear_inherit_confirm); - update_timer = memnew(Timer); update_timer->connect("timeout", this, "_update_tree"); update_timer->set_one_shot(true); diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index ec7115afed..c6283af7b5 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -56,27 +56,14 @@ class SceneTreeEditor : public Control { BUTTON_GROUPS = 7, }; - enum { - SCENE_MENU_EDITABLE_CHILDREN, - SCENE_MENU_USE_PLACEHOLDER, - SCENE_MENU_OPEN, - SCENE_MENU_CLEAR_INHERITANCE, - SCENE_MENU_OPEN_INHERITED, - SCENE_MENU_CLEAR_INHERITANCE_CONFIRM, - SCENE_MENU_CLEAR_INSTANCING, - }; - Tree *tree; Node *selected; - PopupMenu *instance_menu; - PopupMenu *inheritance_menu; ObjectID instance_node; String filter; AcceptDialog *error; AcceptDialog *warning; - ConfirmationDialog *clear_inherit_confirm; int blocked; @@ -119,7 +106,6 @@ class SceneTreeEditor : public Control { void _node_script_changed(Node *p_node); void _node_visibility_changed(Node *p_node); void _update_visibility_color(Node *p_node, TreeItem *p_item); - void _subscene_option(int p_idx); void _node_replace_owner(Node *p_base, Node *p_node, Node *p_root); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 0f3f5500a8..00fdcb676b 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -271,10 +271,8 @@ void ScriptCreateDialog::_browse_path(bool browse_parent) { file_browse->clear_filters(); List<String> extensions; - // get all possible extensions for script - for (int l = 0; l < language_menu->get_item_count(); l++) { - ScriptServer::get_language(l)->get_recognized_extensions(&extensions); - } + int lang = language_menu->get_selected(); + ScriptServer::get_language(lang)->get_recognized_extensions(&extensions); for (List<String>::Element *E = extensions.front(); E; E = E->next()) { file_browse->add_filter("*." + E->get()); diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 76df9eb1ff..62fa93ac23 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -1279,8 +1279,8 @@ void RoomSpatialGizmo::redraw() { for (int j = 0; j < 3; j++) { _EdgeKey ek; - ek.from = r[i].vertex[j].snapped(CMP_EPSILON); - ek.to = r[i].vertex[(j + 1) % 3].snapped(CMP_EPSILON); + ek.from = r[i].vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); + ek.to = r[i].vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); if (ek.from < ek.to) SWAP(ek.from, ek.to); @@ -2463,8 +2463,8 @@ void NavigationMeshSpatialGizmo::redraw() { tw[tidx++] = f.vertex[j]; _EdgeKey ek; - ek.from = f.vertex[j].snapped(CMP_EPSILON); - ek.to = f.vertex[(j + 1) % 3].snapped(CMP_EPSILON); + ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); + ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); if (ek.from < ek.to) SWAP(ek.from, ek.to); diff --git a/modules/etc/config.py b/modules/etc/config.py index fb920482f5..4b0b01b78e 100644 --- a/modules/etc/config.py +++ b/modules/etc/config.py @@ -4,4 +4,8 @@ def can_build(platform): def configure(env): - pass + # Tools only, disabled for non-tools + # TODO: Find a cleaner way to achieve that + if (env["tools"] == "no"): + env["module_etc_enabled"] = "no" + env.disabled_modules.append("etc") diff --git a/modules/gdnative/godot/godot_vector3.cpp b/modules/gdnative/godot/godot_vector3.cpp index f9942af6e5..adca0d1e2a 100644 --- a/modules/gdnative/godot/godot_vector3.cpp +++ b/modules/gdnative/godot/godot_vector3.cpp @@ -90,11 +90,12 @@ godot_vector3 GDAPI godot_vector3_inverse(const godot_vector3 *p_self) { return dest; } -godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_real p_by) { +godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_vector3 *p_by) { godot_vector3 dest; const Vector3 *self = (const Vector3 *)p_self; + const Vector3 *snap_axis = (const Vector3 *)p_by; - *((Vector3 *)&dest) = self->snapped(p_by); + *((Vector3 *)&dest) = self->snapped(*snap_axis); return dest; } diff --git a/modules/gdnative/godot/godot_vector3.h b/modules/gdnative/godot/godot_vector3.h index 8e2aed8173..98d9ddf6ac 100644 --- a/modules/gdnative/godot/godot_vector3.h +++ b/modules/gdnative/godot/godot_vector3.h @@ -70,7 +70,7 @@ godot_vector3 GDAPI godot_vector3_normalized(const godot_vector3 *p_self); godot_vector3 GDAPI godot_vector3_inverse(const godot_vector3 *p_self); -godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_real p_by); +godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_vector3 *p_by); godot_vector3 GDAPI godot_vector3_rotated(const godot_vector3 *p_self, const godot_vector3 *p_axis, const godot_real p_phi); diff --git a/modules/tinyexr/config.py b/modules/tinyexr/config.py index fb920482f5..2e4b96a6b0 100644 --- a/modules/tinyexr/config.py +++ b/modules/tinyexr/config.py @@ -4,4 +4,8 @@ def can_build(platform): def configure(env): - pass + # Tools only, disabled for non-tools + # TODO: Find a cleaner way to achieve that + if (env["tools"] == "no"): + env["module_tinyexr_enabled"] = "no" + env.disabled_modules.append("tinyexr") diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp index c0467a901b..a54d306aff 100644 --- a/modules/visual_script/register_types.cpp +++ b/modules/visual_script/register_types.cpp @@ -90,6 +90,7 @@ void register_visual_script_types() { ClassDB::register_class<VisualScriptSequence>(); //ClassDB::register_class<VisualScriptInputFilter>(); ClassDB::register_class<VisualScriptSwitch>(); + ClassDB::register_class<VisualScriptSelect>(); ClassDB::register_class<VisualScriptYield>(); ClassDB::register_class<VisualScriptYieldSignal>(); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index bb8111ce99..a922fdf354 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -140,7 +140,7 @@ VisualScriptNode::TypeGuess VisualScriptNode::guess_output_type(TypeGuess *p_inp tg.type = pinfo.type; if (pinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { - tg.GDCLASS = pinfo.hint_string; + tg.gdclass = pinfo.hint_string; } return tg; @@ -660,6 +660,9 @@ void VisualScript::set_variable_export(const StringName &p_name, bool p_export) ERR_FAIL_COND(!variables.has(p_name)); variables[p_name]._export = p_export; +#ifdef TOOLS_ENABLED + _update_placeholders(); +#endif } bool VisualScript::get_variable_export(const StringName &p_name) const { @@ -1067,9 +1070,11 @@ void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const { get_variable_list(&vars); for (List<StringName>::Element *E = vars.front(); E; E = E->next()) { - if (!variables[E->get()]._export) - continue; - p_list->push_back(variables[E->get()].info); + //if (!variables[E->get()]._export) + // continue; + PropertyInfo pi = variables[E->get()].info; + pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; + p_list->push_back(pi); } } @@ -1358,6 +1363,7 @@ void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) c continue; PropertyInfo p = E->get().info; p.name = String(E->key()); + p.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; p_properties->push_back(p); } } diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index 20a1cf49c5..cdd7eded18 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -89,7 +89,7 @@ public: struct TypeGuess { Variant::Type type; - StringName GDCLASS; + StringName gdclass; Ref<Script> script; TypeGuess() { diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 941668d474..a6b53b67fa 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -52,11 +52,13 @@ public: protected: static void _bind_methods() { ClassDB::bind_method("_sig_changed", &VisualScriptEditorSignalEdit::_sig_changed); + ADD_SIGNAL(MethodInfo("changed")); } void _sig_changed() { _change_notify(); + emit_signal("changed"); } bool _set(const StringName &p_name, const Variant &p_value) { @@ -191,15 +193,18 @@ protected: static void _bind_methods() { ClassDB::bind_method("_var_changed", &VisualScriptEditorVariableEdit::_var_changed); ClassDB::bind_method("_var_value_changed", &VisualScriptEditorVariableEdit::_var_value_changed); + ADD_SIGNAL(MethodInfo("changed")); } void _var_changed() { _change_notify(); + emit_signal("changed"); } void _var_value_changed() { _change_notify("value"); //so the whole tree is not redrawn, makes editing smoother in general + emit_signal("changed"); } bool _set(const StringName &p_name, const Variant &p_value) { @@ -261,6 +266,7 @@ protected: if (String(p_name) == "export") { script->set_variable_export(var, p_value); + EditorNode::get_singleton()->get_property_editor()->update_tree(); return true; } @@ -699,7 +705,7 @@ void VisualScriptEditor::_update_members() { ti->set_selectable(0, true); ti->set_editable(0, true); //ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0); function arguments are in the node now - ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); + //ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); ti->set_metadata(0, E->get()); if (E->get() == edited_func) { ti->set_custom_bg_color(0, get_color("prop_category", "Editor")); @@ -757,8 +763,8 @@ void VisualScriptEditor::_update_members() { ti->set_selectable(0, true); ti->set_editable(0, true); - ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0); - ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); + //ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0); + //ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); ti->set_metadata(0, E->get()); if (selected == E->get()) ti->select(0); @@ -777,8 +783,8 @@ void VisualScriptEditor::_update_members() { ti->set_text(0, E->get()); ti->set_selectable(0, true); ti->set_editable(0, true); - ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0); - ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); + //ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0); + //ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1); ti->set_metadata(0, E->get()); if (selected == E->get()) ti->select(0); @@ -1068,105 +1074,6 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt undo_redo->commit_action(); return; //or crash because it will become invalid } - - } else { - - if (ti->get_parent() == root->get_children()) { - //edit/remove function - String name = ti->get_metadata(0); - - if (p_button == 1) { - //delete the function - undo_redo->create_action(TTR("Remove Function")); - undo_redo->add_do_method(script.ptr(), "remove_function", name); - undo_redo->add_undo_method(script.ptr(), "add_function", name); - List<int> nodes; - script->get_node_list(name, &nodes); - for (List<int>::Element *E = nodes.front(); E; E = E->next()) { - undo_redo->add_undo_method(script.ptr(), "add_node", name, E->get(), script->get_node(name, E->get()), script->get_node_pos(name, E->get())); - } - - List<VisualScript::SequenceConnection> seq_connections; - - script->get_sequence_connection_list(name, &seq_connections); - - for (List<VisualScript::SequenceConnection>::Element *E = seq_connections.front(); E; E = E->next()) { - undo_redo->add_undo_method(script.ptr(), "sequence_connect", name, E->get().from_node, E->get().from_output, E->get().to_node); - } - - List<VisualScript::DataConnection> data_connections; - - script->get_data_connection_list(name, &data_connections); - - for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) { - undo_redo->add_undo_method(script.ptr(), "data_connect", name, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); - } - - /* - for(int i=0;i<script->function_get_argument_count(name);i++) { - undo_redo->add_undo_method(script.ptr(),"function_add_argument",name,script->function_get_argument_name(name,i),script->function_get_argument_type(name,i)); - } - */ - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - - } else if (p_button == 0) { - } - return; //or crash because it will become invalid - } - - if (ti->get_parent() == root->get_children()->get_next()) { - //edit/remove variable - - String name = ti->get_metadata(0); - - if (p_button == 1) { - - undo_redo->create_action(TTR("Remove Variable")); - undo_redo->add_do_method(script.ptr(), "remove_variable", name); - undo_redo->add_undo_method(script.ptr(), "add_variable", name, script->get_variable_default_value(name)); - undo_redo->add_undo_method(script.ptr(), "set_variable_info", name, script->call("get_variable_info", name)); //return as dict - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->commit_action(); - return; //or crash because it will become invalid - } else if (p_button == 0) { - - variable_editor->edit(name); - edit_variable_dialog->set_title(TTR("Editing Variable:") + " " + name); - edit_variable_dialog->popup_centered_minsize(Size2(400, 200) * EDSCALE); - } - } - - if (ti->get_parent() == root->get_children()->get_next()->get_next()) { - //edit/remove variable - String name = ti->get_metadata(0); - - if (p_button == 1) { - - undo_redo->create_action(TTR("Remove Signal")); - undo_redo->add_do_method(script.ptr(), "remove_custom_signal", name); - undo_redo->add_undo_method(script.ptr(), "add_custom_signal", name); - - for (int i = 0; i < script->custom_signal_get_argument_count(name); i++) { - undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", name, script->custom_signal_get_argument_name(name, i), script->custom_signal_get_argument_type(name, i)); - } - - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->commit_action(); - } else if (p_button == 0) { - - signal_editor->edit(name); - edit_signal_dialog->set_title(TTR("Editing Signal:") + " " + name); - edit_signal_dialog->popup_centered_minsize(Size2(400, 300) * EDSCALE); - } - - return; //or crash because it will become invalid - } } } @@ -2269,6 +2176,11 @@ void VisualScriptEditor::_change_base_type() { select_base_type->popup_create(true); } +void VisualScriptEditor::clear_edit_menu() { + memdelete(edit_menu); + memdelete(left_vsplit); +} + void VisualScriptEditor::_change_base_type_callback() { String bt = select_base_type->get_selected_type(); @@ -2556,7 +2468,7 @@ VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_node, i if (obj) { g.type = Variant::OBJECT; - g.GDCLASS = obj->get_class(); + g.gdclass = obj->get_class(); g.script = obj->get_script(); } } @@ -2596,8 +2508,8 @@ void VisualScriptEditor::_port_action_menu(int p_option) { if (tg.type == Variant::OBJECT) { n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); - if (tg.GDCLASS != StringName()) { - n->set_base_type(tg.GDCLASS); + if (tg.gdclass != StringName()) { + n->set_base_type(tg.gdclass); } else { n->set_base_type("Object"); } @@ -2627,8 +2539,8 @@ void VisualScriptEditor::_port_action_menu(int p_option) { if (tg.type == Variant::OBJECT) { n->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); - if (tg.GDCLASS != StringName()) { - n->set_base_type(tg.GDCLASS); + if (tg.gdclass != StringName()) { + n->set_base_type(tg.gdclass); } else { n->set_base_type("Object"); } @@ -2657,8 +2569,8 @@ void VisualScriptEditor::_port_action_menu(int p_option) { if (tg.type == Variant::OBJECT) { n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); - if (tg.GDCLASS != StringName()) { - n->set_base_type(tg.GDCLASS); + if (tg.gdclass != StringName()) { + n->set_base_type(tg.gdclass); } else { n->set_base_type("Object"); } @@ -2834,12 +2746,17 @@ void VisualScriptEditor::_notification(int p_what) { if (p_what == NOTIFICATION_READY) { node_filter_icon->set_texture(Control::get_icon("Zoom", "EditorIcons")); + variable_editor->connect("changed", this, "_update_members"); + signal_editor->connect("changed", this, "_update_members"); + } + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + left_vsplit->set_visible(is_visible_in_tree()); } } void VisualScriptEditor::_graph_ofs_changed(const Vector2 &p_ofs) { - if (updating_graph) + if (updating_graph || !script.is_valid()) return; updating_graph = true; @@ -3053,6 +2970,142 @@ void VisualScriptEditor::_menu_option(int p_what) { } } +void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) { + + TreeItem *ti = members->get_selected(); + ERR_FAIL_COND(!ti); + + member_popup->clear(); + member_popup->set_position(members->get_global_position() + p_pos); + member_popup->set_size(Vector2()); + + TreeItem *root = members->get_root(); + + Ref<Texture> del_icon = Control::get_icon("Del", "EditorIcons"); + + Ref<Texture> edit_icon = Control::get_icon("Edit", "EditorIcons"); + + if (ti->get_parent() == root->get_children()) { + + member_type = MEMBER_FUNCTION; + member_name = ti->get_text(0); + member_popup->add_icon_item(del_icon, TTR("Remove Function"), MEMBER_REMOVE); + member_popup->popup(); + return; + } + + if (ti->get_parent() == root->get_children()->get_next()) { + + member_type = MEMBER_VARIABLE; + member_name = ti->get_text(0); + member_popup->add_icon_item(edit_icon, TTR("Edit Variable"), MEMBER_EDIT); + member_popup->add_separator(); + member_popup->add_icon_item(del_icon, TTR("Remove Variable"), MEMBER_REMOVE); + member_popup->popup(); + return; + } + + if (ti->get_parent() == root->get_children()->get_next()->get_next()) { + + member_type = MEMBER_SIGNAL; + member_name = ti->get_text(0); + member_popup->add_icon_item(edit_icon, TTR("Edit Signal"), MEMBER_EDIT); + member_popup->add_separator(); + member_popup->add_icon_item(del_icon, TTR("Remove Signal"), MEMBER_REMOVE); + member_popup->popup(); + return; + } +} + +void VisualScriptEditor::_member_option(int p_option) { + + switch (member_type) { + case MEMBER_FUNCTION: { + + if (p_option == MEMBER_REMOVE) { + //delete the function + String name = member_name; + + undo_redo->create_action(TTR("Remove Function")); + undo_redo->add_do_method(script.ptr(), "remove_function", name); + undo_redo->add_undo_method(script.ptr(), "add_function", name); + List<int> nodes; + script->get_node_list(name, &nodes); + for (List<int>::Element *E = nodes.front(); E; E = E->next()) { + undo_redo->add_undo_method(script.ptr(), "add_node", name, E->get(), script->get_node(name, E->get()), script->get_node_pos(name, E->get())); + } + + List<VisualScript::SequenceConnection> seq_connections; + + script->get_sequence_connection_list(name, &seq_connections); + + for (List<VisualScript::SequenceConnection>::Element *E = seq_connections.front(); E; E = E->next()) { + undo_redo->add_undo_method(script.ptr(), "sequence_connect", name, E->get().from_node, E->get().from_output, E->get().to_node); + } + + List<VisualScript::DataConnection> data_connections; + + script->get_data_connection_list(name, &data_connections); + + for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) { + undo_redo->add_undo_method(script.ptr(), "data_connect", name, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + } + + /* + for(int i=0;i<script->function_get_argument_count(name);i++) { + undo_redo->add_undo_method(script.ptr(),"function_add_argument",name,script->function_get_argument_name(name,i),script->function_get_argument_type(name,i)); + } + */ + undo_redo->add_do_method(this, "_update_members"); + undo_redo->add_undo_method(this, "_update_members"); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + } + } break; + case MEMBER_VARIABLE: { + + String name = member_name; + + if (p_option == MEMBER_REMOVE) { + undo_redo->create_action(TTR("Remove Variable")); + undo_redo->add_do_method(script.ptr(), "remove_variable", name); + undo_redo->add_undo_method(script.ptr(), "add_variable", name, script->get_variable_default_value(name)); + undo_redo->add_undo_method(script.ptr(), "set_variable_info", name, script->call("get_variable_info", name)); //return as dict + undo_redo->add_do_method(this, "_update_members"); + undo_redo->add_undo_method(this, "_update_members"); + undo_redo->commit_action(); + } else if (p_option == MEMBER_EDIT) { + variable_editor->edit(name); + edit_variable_dialog->set_title(TTR("Editing Variable:") + " " + name); + edit_variable_dialog->popup_centered_minsize(Size2(400, 200) * EDSCALE); + } + } break; + case MEMBER_SIGNAL: { + String name = member_name; + + if (p_option == MEMBER_REMOVE) { + undo_redo->create_action(TTR("Remove Signal")); + undo_redo->add_do_method(script.ptr(), "remove_custom_signal", name); + undo_redo->add_undo_method(script.ptr(), "add_custom_signal", name); + + for (int i = 0; i < script->custom_signal_get_argument_count(name); i++) { + undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", name, script->custom_signal_get_argument_name(name, i), script->custom_signal_get_argument_type(name, i)); + } + + undo_redo->add_do_method(this, "_update_members"); + undo_redo->add_undo_method(this, "_update_members"); + undo_redo->commit_action(); + } else if (p_option == MEMBER_EDIT) { + + signal_editor->edit(name); + edit_signal_dialog->set_title(TTR("Editing Signal:") + " " + name); + edit_signal_dialog->popup_centered_minsize(Size2(400, 300) * EDSCALE); + } + } break; + } +} + void VisualScriptEditor::_bind_methods() { ClassDB::bind_method("_member_button", &VisualScriptEditor::_member_button); @@ -3101,6 +3154,10 @@ void VisualScriptEditor::_bind_methods() { ClassDB::bind_method("_selected_method", &VisualScriptEditor::_selected_method); ClassDB::bind_method("_draw_color_over_button", &VisualScriptEditor::_draw_color_over_button); + + ClassDB::bind_method("_member_rmb_selected", &VisualScriptEditor::_member_rmb_selected); + + ClassDB::bind_method("_member_option", &VisualScriptEditor::_member_option); } VisualScriptEditor::VisualScriptEditor() { @@ -3122,17 +3179,16 @@ VisualScriptEditor::VisualScriptEditor() { edit_menu->get_popup()->connect("id_pressed", this, "_menu_option"); - main_hsplit = memnew(HSplitContainer); - add_child(main_hsplit); - main_hsplit->set_area_as_parent_rect(); - left_vsplit = memnew(VSplitContainer); - main_hsplit->add_child(left_vsplit); + ScriptEditor::get_singleton()->get_left_list_split()->call_deferred("add_child", left_vsplit); //add but wait until done settig up this + left_vsplit->set_v_size_flags(SIZE_EXPAND_FILL); + left_vsplit->set_stretch_ratio(2); + left_vsplit->hide(); VBoxContainer *left_vb = memnew(VBoxContainer); left_vsplit->add_child(left_vb); left_vb->set_v_size_flags(SIZE_EXPAND_FILL); - left_vb->set_custom_minimum_size(Size2(230, 1) * EDSCALE); + //left_vb->set_custom_minimum_size(Size2(230, 1) * EDSCALE); base_type_select = memnew(Button); left_vb->add_margin_child(TTR("Base Type:"), base_type_select); @@ -3174,7 +3230,8 @@ VisualScriptEditor::VisualScriptEditor() { nodes->set_drag_forwarding(this); graph = memnew(GraphEdit); - main_hsplit->add_child(graph); + add_child(graph); + graph->set_area_as_parent_rect(); graph->set_h_size_flags(SIZE_EXPAND_FILL); graph->connect("node_selected", this, "_node_selected"); graph->connect("_begin_node_move", this, "_begin_node_move"); @@ -3190,7 +3247,8 @@ VisualScriptEditor::VisualScriptEditor() { select_func_text->set_align(Label::ALIGN_CENTER); select_func_text->set_valign(Label::VALIGN_CENTER); select_func_text->set_h_size_flags(SIZE_EXPAND_FILL); - main_hsplit->add_child(select_func_text); + add_child(select_func_text); + graph->set_area_as_parent_rect(); hint_text = memnew(Label); hint_text->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, 100); @@ -3280,6 +3338,12 @@ VisualScriptEditor::VisualScriptEditor() { port_action_popup = memnew(PopupMenu); add_child(port_action_popup); port_action_popup->connect("id_pressed", this, "_port_action_menu"); + + member_popup = memnew(PopupMenu); + add_child(member_popup); + members->connect("item_rmb_selected", this, "_member_rmb_selected"); + members->set_allow_rmb_select(true); + member_popup->connect("id_pressed", this, "_member_option"); } VisualScriptEditor::~VisualScriptEditor() { diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index 92f31f20da..fee4e27bd5 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -72,15 +72,25 @@ class VisualScriptEditor : public ScriptEditorBase { CREATE_RETURN, }; + enum MemberAction { + MEMBER_EDIT, + MEMBER_REMOVE + + }; + + enum MemberType { + MEMBER_FUNCTION, + MEMBER_VARIABLE, + MEMBER_SIGNAL + }; + + VSplitContainer *left_vsplit; MenuButton *edit_menu; Ref<VisualScript> script; Button *base_type_select; - HSplitContainer *main_hsplit; - VSplitContainer *left_vsplit; - GraphEdit *graph; LineEdit *node_filter; @@ -154,6 +164,10 @@ class VisualScriptEditor : public ScriptEditorBase { static Clipboard *clipboard; PopupMenu *port_action_popup; + PopupMenu *member_popup; + + MemberType member_type; + String member_name; PortAction port_action; int port_action_node; @@ -223,6 +237,9 @@ class VisualScriptEditor : public ScriptEditorBase { VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &visited_nodes); + void _member_rmb_selected(const Vector2 &p_pos); + void _member_option(int p_option); + protected: void _notification(int p_what); static void _bind_methods(); @@ -252,6 +269,7 @@ public: virtual void set_debugger_active(bool p_active); virtual void set_tooltip_request_func(String p_method, Object *p_obj); virtual Control *get_edit_menu(); + virtual void clear_edit_menu(); virtual bool can_lose_focus_on_node_selection() { return false; } static void register_editor(); diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index 791b5d99ff..78b70934c0 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -68,12 +68,12 @@ bool VisualScriptExpression::_set(const StringName &p_name, const Variant &p_val return true; } - if (String(p_name).begins_with("input/")) { + if (String(p_name).begins_with("input_")) { - int idx = String(p_name).get_slice("/", 1).to_int(); + int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int(); ERR_FAIL_INDEX_V(idx, inputs.size(), false); - String what = String(p_name).get_slice("/", 2); + String what = String(p_name).get_slice("/", 1); if (what == "type") { @@ -115,12 +115,12 @@ bool VisualScriptExpression::_get(const StringName &p_name, Variant &r_ret) cons return true; } - if (String(p_name).begins_with("input/")) { + if (String(p_name).begins_with("input_")) { - int idx = String(p_name).get_slice("/", 1).to_int(); + int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int(); ERR_FAIL_INDEX_V(idx, inputs.size(), false); - String what = String(p_name).get_slice("/", 2); + String what = String(p_name).get_slice("/", 1); if (what == "type") { @@ -151,8 +151,8 @@ void VisualScriptExpression::_get_property_list(List<PropertyInfo> *p_list) cons for (int i = 0; i < inputs.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, "input/" + itos(i) + "/type", PROPERTY_HINT_ENUM, argt)); - p_list->push_back(PropertyInfo(Variant::STRING, "input/" + itos(i) + "/name")); + p_list->push_back(PropertyInfo(Variant::INT, "input_" + itos(i) + "/type", PROPERTY_HINT_ENUM, argt)); + p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name")); } } diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index 07d69db207..28622bed47 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -30,6 +30,7 @@ #include "visual_script_flow_control.h" #include "global_config.h" +#include "io/resource_loader.h" #include "os/keyboard.h" ////////////////////////////////////////// @@ -119,8 +120,8 @@ void VisualScriptReturn::_bind_methods() { argt += "," + Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "return_value/enabled"), "set_enable_return_value", "is_return_value_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "return_value/type", PROPERTY_HINT_ENUM, argt), "set_return_type", "get_return_type"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "return_enabled"), "set_enable_return_value", "is_return_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "return_type", PROPERTY_HINT_ENUM, argt), "set_return_type", "get_return_type"); } class VisualScriptNodeInstanceReturn : public VisualScriptNodeInstance { @@ -1725,6 +1726,20 @@ String VisualScriptTypeCast::get_base_script() const { return script; } +VisualScriptTypeCast::TypeGuess VisualScriptTypeCast::guess_output_type(TypeGuess *p_inputs, int p_output) const { + + TypeGuess tg; + tg.type = Variant::OBJECT; + if (script != String()) { + tg.script = ResourceLoader::load(script); + } + //if (!tg.script.is_valid()) { + // tg.gdclass = base_type; + //} + + return tg; +} + class VisualScriptNodeInstanceTypeCast : public VisualScriptNodeInstance { public: VisualScriptInstance *instance; @@ -1815,8 +1830,8 @@ void VisualScriptTypeCast::_bind_methods() { script_ext_hint += "*." + E->get(); } - ADD_PROPERTY(PropertyInfo(Variant::STRING, "function/base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); } VisualScriptTypeCast::VisualScriptTypeCast() { diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h index 314804602e..d27fd47f84 100644 --- a/modules/visual_script/visual_script_flow_control.h +++ b/modules/visual_script/visual_script_flow_control.h @@ -261,6 +261,7 @@ public: VisualScriptInputFilter(); }; #endif + class VisualScriptTypeCast : public VisualScriptNode { GDCLASS(VisualScriptTypeCast, VisualScriptNode) @@ -293,6 +294,8 @@ public: void set_base_script(const String &p_path); String get_base_script() const; + virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const; + virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance); VisualScriptTypeCast(); diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index e0e1a217b3..93b2aa2982 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -546,25 +546,25 @@ Dictionary VisualScriptFunctionCall::_get_argument_cache() const { void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const { - if (property.name == "function/base_type") { + if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = PROPERTY_USAGE_NOEDITOR; } } - if (property.name == "function/base_script") { + if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = 0; } } - if (property.name == "function/basic_type") { + if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { property.usage = 0; } } - if (property.name == "function/singleton") { + if (property.name == "singleton") { if (call_mode != CALL_MODE_SINGLETON) { property.usage = 0; } else { @@ -581,7 +581,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } } - if (property.name == "function/node_path") { + if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { property.usage = 0; } else { @@ -594,7 +594,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } } - if (property.name == "function/function") { + if (property.name == "function") { if (call_mode == CALL_MODE_BASIC_TYPE) { @@ -648,7 +648,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } } - if (property.name == "function/use_default_args") { + if (property.name == "use_default_args") { property.hint = PROPERTY_HINT_RANGE; @@ -673,7 +673,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } } - if (property.name == "rpc/call_mode") { + if (property.name == "rpc_call_mode") { if (call_mode == CALL_MODE_BASIC_TYPE) { property.usage = 0; } @@ -735,17 +735,17 @@ void VisualScriptFunctionCall::_bind_methods() { script_ext_hint += "*." + E->get(); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "function/call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type,Singleton"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "function/base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "function/base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "function/singleton"), "set_singleton", "get_singleton"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function/basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "function/node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "function/argument_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_argument_cache", "_get_argument_cache"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "function/function"), "set_function", "get_function"); //when set, if loaded properly, will override argument count. - ADD_PROPERTY(PropertyInfo(Variant::INT, "function/use_default_args"), "set_use_default_args", "get_use_default_args"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "function/validate"), "set_validate", "get_validate"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "rpc/call_mode", PROPERTY_HINT_ENUM, "Disabled,Reliable,Unreliable,ReliableToID,UnreliableToID"), "set_rpc_call_mode", "get_rpc_call_mode"); //when set, if loaded properly, will override argument count. + ADD_PROPERTY(PropertyInfo(Variant::INT, "call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type,Singleton"), "set_call_mode", "get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "singleton"), "set_singleton", "get_singleton"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "argument_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_argument_cache", "_get_argument_cache"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "function"), "set_function", "get_function"); //when set, if loaded properly, will override argument count. + ADD_PROPERTY(PropertyInfo(Variant::INT, "use_default_args"), "set_use_default_args", "get_use_default_args"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "validate"), "set_validate", "get_validate"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rpc_call_mode", PROPERTY_HINT_ENUM, "Disabled,Reliable,Unreliable,ReliableToID,UnreliableToID"), "set_rpc_call_mode", "get_rpc_call_mode"); //when set, if loaded properly, will override argument count. BIND_CONSTANT(CALL_MODE_SELF); BIND_CONSTANT(CALL_MODE_NODE_PATH); @@ -1020,6 +1020,18 @@ String VisualScriptPropertySet::get_output_sequence_port_text(int p_port) const return String(); } +void VisualScriptPropertySet::_adjust_input_index(PropertyInfo &pinfo) const { + + if (index != StringName()) { + + Variant v; + Variant::CallError ce; + v = Variant::construct(pinfo.type, NULL, 0, ce); + Variant i = v.get(index); + pinfo.type = i.get_type(); + } +} + PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const { if (call_mode == CALL_MODE_INSTANCE || call_mode == CALL_MODE_BASIC_TYPE) { @@ -1027,6 +1039,7 @@ PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const PropertyInfo pi; pi.type = (call_mode == CALL_MODE_INSTANCE ? Variant::OBJECT : basic_type); pi.name = (call_mode == CALL_MODE_INSTANCE ? String("instance") : Variant::get_type_name(basic_type).to_lower()); + _adjust_input_index(pi); return pi; } else { p_idx--; @@ -1035,6 +1048,7 @@ PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const PropertyInfo pinfo = type_cache; pinfo.name = "value"; + _adjust_input_index(pinfo); return pinfo; } @@ -1051,13 +1065,16 @@ PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) cons String VisualScriptPropertySet::get_caption() const { static const char *cname[4] = { - "SelfSet", - "NodeSet", - "InstanceSet", - "BasicSet" + "Self", + "Node", + "Instance", + "Basic" }; - return cname[call_mode]; + static const char *opname[ASSIGN_OP_MAX] = { + "Set", "Add", "Sub", "Mul", "Div", "Mod", "ShiftLeft", "ShiftRight", "BitAnd", "BitOr", "BitXor" + }; + return String(cname[call_mode]) + opname[assign_op]; } String VisualScriptPropertySet::get_text() const { @@ -1073,6 +1090,9 @@ String VisualScriptPropertySet::get_text() const { else if (call_mode == CALL_MODE_INSTANCE) prop = String(base_type) + ":" + property; + if (index != StringName()) { + prop += "." + String(index); + } return prop; } @@ -1236,6 +1256,7 @@ void VisualScriptPropertySet::set_property(const StringName &p_type) { return; property = p_type; + index = StringName(); _update_cache(); _change_notify(); ports_changed_notify(); @@ -1285,27 +1306,58 @@ Dictionary VisualScriptPropertySet::_get_type_cache() const { return type_cache; } +void VisualScriptPropertySet::set_index(const StringName &p_type) { + + if (index == p_type) + return; + index = p_type; + _update_cache(); + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptPropertySet::get_index() const { + + return index; +} + +void VisualScriptPropertySet::set_assign_op(AssignOp p_op) { + + ERR_FAIL_INDEX(p_op, ASSIGN_OP_MAX); + if (assign_op == p_op) + return; + + assign_op = p_op; + _update_cache(); + _change_notify(); + ports_changed_notify(); +} + +VisualScriptPropertySet::AssignOp VisualScriptPropertySet::get_assign_op() const { + return assign_op; +} + void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { - if (property.name == "property/base_type") { + if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = PROPERTY_USAGE_NOEDITOR; } } - if (property.name == "property/base_script") { + if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = 0; } } - if (property.name == "property/basic_type") { + if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { property.usage = 0; } } - if (property.name == "property/node_path") { + if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { property.usage = 0; } else { @@ -1318,7 +1370,7 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { } } - if (property.name == "property/property") { + if (property.name == "property") { if (call_mode == CALL_MODE_BASIC_TYPE) { @@ -1360,6 +1412,24 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { } } } + + if (property.name == "index") { + + Variant::CallError ce; + Variant v = Variant::construct(type_cache.type, NULL, 0, ce); + List<PropertyInfo> plist; + v.get_property_list(&plist); + String options = ""; + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + options += "," + E->get().name; + } + + property.hint = PROPERTY_HINT_ENUM; + property.hint_string = options; + property.type = Variant::STRING; + if (options == "") + property.usage = 0; //hide if type has no usable index + } } void VisualScriptPropertySet::_bind_methods() { @@ -1385,6 +1455,12 @@ void VisualScriptPropertySet::_bind_methods() { ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptPropertySet::set_base_path); ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptPropertySet::get_base_path); + ClassDB::bind_method(D_METHOD("set_index", "index"), &VisualScriptPropertySet::set_index); + ClassDB::bind_method(D_METHOD("get_index"), &VisualScriptPropertySet::get_index); + + ClassDB::bind_method(D_METHOD("set_assign_op", "assign_op"), &VisualScriptPropertySet::set_assign_op); + ClassDB::bind_method(D_METHOD("get_assign_op"), &VisualScriptPropertySet::get_assign_op); + String bt; for (int i = 0; i < Variant::VARIANT_MAX; i++) { if (i > 0) @@ -1405,14 +1481,15 @@ void VisualScriptPropertySet::_bind_methods() { script_ext_hint += "*." + E->get(); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_type_cache", "_get_type_cache"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "property/node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/property"), "set_property", "get_property"); - + ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_type_cache", "_get_type_cache"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "property"), "set_property", "get_property"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "index"), "set_index", "get_index"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "assign_op", PROPERTY_HINT_ENUM, "Assign,Add,Sub,Mul,Div,Mod,ShiftLeft,ShiftRight,BitAnd,BitOr,Bitxor"), "set_assign_op", "get_assign_op"); BIND_CONSTANT(CALL_MODE_SELF); BIND_CONSTANT(CALL_MODE_NODE_PATH); BIND_CONSTANT(CALL_MODE_INSTANCE); @@ -1426,11 +1503,72 @@ public: VisualScriptPropertySet *node; VisualScriptInstance *instance; + VisualScriptPropertySet::AssignOp assign_op; + StringName index; + bool needs_get; //virtual int get_working_memory_size() const { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + _FORCE_INLINE_ void _process_get(Variant &source, const Variant &p_argument, bool &valid) { + + if (index != StringName() && assign_op == VisualScriptPropertySet::ASSIGN_OP_NONE) { + source.set_named(index, p_argument, &valid); + } else { + + Variant value; + if (index != StringName()) { + value = source.get_named(index, &valid); + } else { + value = source; + } + + switch (assign_op) { + case VisualScriptPropertySet::ASSIGN_OP_NONE: { + //should never get here + } break; + case VisualScriptPropertySet::ASSIGN_OP_ADD: { + value = Variant::evaluate(Variant::OP_ADD, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_SUB: { + value = Variant::evaluate(Variant::OP_SUBSTRACT, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_MUL: { + value = Variant::evaluate(Variant::OP_MULTIPLY, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_DIV: { + value = Variant::evaluate(Variant::OP_DIVIDE, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_MOD: { + value = Variant::evaluate(Variant::OP_MODULE, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_SHIFT_LEFT: { + value = Variant::evaluate(Variant::OP_SHIFT_LEFT, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_SHIFT_RIGHT: { + value = Variant::evaluate(Variant::OP_SHIFT_RIGHT, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_BIT_AND: { + value = Variant::evaluate(Variant::OP_BIT_AND, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_BIT_OR: { + value = Variant::evaluate(Variant::OP_BIT_OR, value, p_argument); + } break; + case VisualScriptPropertySet::ASSIGN_OP_BIT_XOR: { + value = Variant::evaluate(Variant::OP_BIT_XOR, value, p_argument); + } break; + default: {} + } + + if (index != StringName()) { + source.set_named(index, value, &valid); + } else { + source = value; + } + } + } + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Variant::CallError &r_error, String &r_error_str) { switch (call_mode) { @@ -1441,7 +1579,13 @@ public: bool valid; - object->set(property, *p_inputs[0], &valid); + if (needs_get) { + Variant value = object->get(property, &valid); + _process_get(value, *p_inputs[0], valid); + object->set(property, value, &valid); + } else { + object->set(property, *p_inputs[0], &valid); + } if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; @@ -1466,7 +1610,14 @@ public: bool valid; - another->set(property, *p_inputs[0], &valid); + if (needs_get) { + + Variant value = another->get(property, &valid); + _process_get(value, *p_inputs[0], valid); + another->set(property, value, &valid); + } else { + another->set(property, *p_inputs[0], &valid); + } if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; @@ -1481,7 +1632,14 @@ public: bool valid; - v.set(property, *p_inputs[1], &valid); + if (needs_get) { + Variant value = v.get_named(property, &valid); + _process_get(value, *p_inputs[1], valid); + v.set_named(property, value, &valid); + + } else { + v.set_named(property, *p_inputs[1], &valid); + } if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; @@ -1504,6 +1662,9 @@ VisualScriptNodeInstance *VisualScriptPropertySet::instance(VisualScriptInstance instance->property = property; instance->call_mode = call_mode; instance->node_path = base_path; + instance->assign_op = assign_op; + instance->index = index; + instance->needs_get = index != StringName() || assign_op != ASSIGN_OP_NONE; return instance; } @@ -1517,6 +1678,7 @@ VisualScriptPropertySet::TypeGuess VisualScriptPropertySet::guess_output_type(Ty } VisualScriptPropertySet::VisualScriptPropertySet() { + assign_op = ASSIGN_OP_NONE; call_mode = CALL_MODE_SELF; base_type = "Object"; basic_type = Variant::NIL; @@ -1641,6 +1803,15 @@ PropertyInfo VisualScriptPropertyGet::get_input_value_port_info(int p_idx) const PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) const { + if (index != StringName()) { + + Variant v; + Variant::CallError ce; + v = Variant::construct(type_cache, NULL, 0, ce); + Variant i = v.get(index); + return PropertyInfo(i.get_type(), "value." + String(index)); + } + return PropertyInfo(type_cache, "value"); } @@ -1867,27 +2038,42 @@ Variant::Type VisualScriptPropertyGet::_get_type_cache() const { return type_cache; } +void VisualScriptPropertyGet::set_index(const StringName &p_type) { + + if (index == p_type) + return; + index = p_type; + _update_cache(); + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptPropertyGet::get_index() const { + + return index; +} + void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { - if (property.name == "property/base_type") { + if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = PROPERTY_USAGE_NOEDITOR; } } - if (property.name == "property/base_script") { + if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = 0; } } - if (property.name == "property/basic_type") { + if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { property.usage = 0; } } - if (property.name == "property/node_path") { + if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { property.usage = 0; } else { @@ -1900,7 +2086,7 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { } } - if (property.name == "property/property") { + if (property.name == "property") { if (call_mode == CALL_MODE_BASIC_TYPE) { @@ -1941,6 +2127,24 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { } } } + + if (property.name == "index") { + + Variant::CallError ce; + Variant v = Variant::construct(type_cache, NULL, 0, ce); + List<PropertyInfo> plist; + v.get_property_list(&plist); + String options = ""; + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + options += "," + E->get().name; + } + + property.hint = PROPERTY_HINT_ENUM; + property.hint_string = options; + property.type = Variant::STRING; + if (options == "") + property.usage = 0; //hide if type has no usable index + } } void VisualScriptPropertyGet::_bind_methods() { @@ -1966,6 +2170,9 @@ void VisualScriptPropertyGet::_bind_methods() { ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptPropertyGet::set_base_path); ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptPropertyGet::get_base_path); + ClassDB::bind_method(D_METHOD("set_index", "index"), &VisualScriptPropertyGet::set_index); + ClassDB::bind_method(D_METHOD("get_index"), &VisualScriptPropertyGet::get_index); + String bt; for (int i = 0; i < Variant::VARIANT_MAX; i++) { if (i > 0) @@ -1986,13 +2193,14 @@ void VisualScriptPropertyGet::_bind_methods() { script_ext_hint += "." + E->get(); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_type_cache", "_get_type_cache"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "property/basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "property/node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property/property"), "set_property", "get_property"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_type_cache", "_get_type_cache"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "property"), "set_property", "get_property"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "index", PROPERTY_HINT_ENUM), "set_index", "get_index"); BIND_CONSTANT(CALL_MODE_SELF); BIND_CONSTANT(CALL_MODE_NODE_PATH); @@ -2004,6 +2212,7 @@ public: VisualScriptPropertyGet::CallMode call_mode; NodePath node_path; StringName property; + StringName index; VisualScriptPropertyGet *node; VisualScriptInstance *instance; @@ -2020,6 +2229,10 @@ public: *p_outputs[0] = object->get(property, &valid); + if (index != StringName()) { + *p_outputs[0] = p_outputs[0]->get_named(index); + } + if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = RTR("Invalid index property name."); @@ -2046,6 +2259,10 @@ public: *p_outputs[0] = another->get(property, &valid); + if (index != StringName()) { + *p_outputs[0] = p_outputs[0]->get_named(index); + } + if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = vformat(RTR("Invalid index property name '%s' in node %s."), String(property), another->get_name()); @@ -2059,6 +2276,9 @@ public: Variant v = *p_inputs[0]; *p_outputs[0] = v.get(property, &valid); + if (index != StringName()) { + *p_outputs[0] = p_outputs[0]->get_named(index); + } if (!valid) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; @@ -2079,6 +2299,7 @@ VisualScriptNodeInstance *VisualScriptPropertyGet::instance(VisualScriptInstance instance->property = property; instance->call_mode = call_mode; instance->node_path = base_path; + instance->index = index; return instance; } @@ -2182,7 +2403,7 @@ StringName VisualScriptEmitSignal::get_signal() const { void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { - if (property.name == "signal/signal") { + if (property.name == "signal") { property.hint = PROPERTY_HINT_ENUM; List<StringName> sigs; @@ -2210,7 +2431,7 @@ void VisualScriptEmitSignal::_bind_methods() { ClassDB::bind_method(D_METHOD("set_signal", "name"), &VisualScriptEmitSignal::set_signal); ClassDB::bind_method(D_METHOD("get_signal"), &VisualScriptEmitSignal::get_signal); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal/signal"), "set_signal", "get_signal"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal"), "set_signal", "get_signal"); } class VisualScriptNodeInstanceEmitSignal : public VisualScriptNodeInstance { diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h index 3b284952c5..7839748661 100644 --- a/modules/visual_script/visual_script_func_nodes.h +++ b/modules/visual_script/visual_script_func_nodes.h @@ -146,6 +146,21 @@ public: }; + enum AssignOp { + ASSIGN_OP_NONE, + ASSIGN_OP_ADD, + ASSIGN_OP_SUB, + ASSIGN_OP_MUL, + ASSIGN_OP_DIV, + ASSIGN_OP_MOD, + ASSIGN_OP_SHIFT_LEFT, + ASSIGN_OP_SHIFT_RIGHT, + ASSIGN_OP_BIT_AND, + ASSIGN_OP_BIT_OR, + ASSIGN_OP_BIT_XOR, + ASSIGN_OP_MAX + }; + private: PropertyInfo type_cache; @@ -155,6 +170,8 @@ private: String base_script; NodePath base_path; StringName property; + StringName index; + AssignOp assign_op; Node *_get_base_node() const; StringName _get_base_type() const; @@ -166,6 +183,8 @@ private: void _set_type_cache(const Dictionary &p_type); Dictionary _get_type_cache() const; + void _adjust_input_index(PropertyInfo &pinfo) const; + protected: virtual void _validate_property(PropertyInfo &property) const; @@ -205,6 +224,12 @@ public: void set_call_mode(CallMode p_mode); CallMode get_call_mode() const; + void set_index(const StringName &p_type); + StringName get_index() const; + + void set_assign_op(AssignOp p_op); + AssignOp get_assign_op() const; + virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance); virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const; @@ -212,6 +237,7 @@ public: }; VARIANT_ENUM_CAST(VisualScriptPropertySet::CallMode); +VARIANT_ENUM_CAST(VisualScriptPropertySet::AssignOp); class VisualScriptPropertyGet : public VisualScriptNode { @@ -234,6 +260,7 @@ private: String base_script; NodePath base_path; StringName property; + StringName index; void _update_base_type(); Node *_get_base_node() const; @@ -283,6 +310,9 @@ public: void set_call_mode(CallMode p_mode); CallMode get_call_mode() const; + void set_index(const StringName &p_type); + StringName get_index() const; + virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance); VisualScriptPropertyGet(); diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 86c98d076e..f707471405 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -59,10 +59,10 @@ bool VisualScriptFunction::_set(const StringName &p_name, const Variant &p_value _change_notify(); return true; } - if (String(p_name).begins_with("argument/")) { - int idx = String(p_name).get_slice("/", 1).to_int() - 1; + if (String(p_name).begins_with("argument_")) { + int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; ERR_FAIL_INDEX_V(idx, arguments.size(), false); - String what = String(p_name).get_slice("/", 2); + String what = String(p_name).get_slice("/", 1); if (what == "type") { Variant::Type new_type = Variant::Type(int(p_value)); @@ -104,10 +104,10 @@ bool VisualScriptFunction::_get(const StringName &p_name, Variant &r_ret) const r_ret = arguments.size(); return true; } - if (String(p_name).begins_with("argument/")) { - int idx = String(p_name).get_slice("/", 1).to_int() - 1; + if (String(p_name).begins_with("argument_")) { + int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; ERR_FAIL_INDEX_V(idx, arguments.size(), false); - String what = String(p_name).get_slice("/", 2); + String what = String(p_name).get_slice("/", 1); if (what == "type") { r_ret = arguments[idx].type; return true; @@ -144,8 +144,8 @@ void VisualScriptFunction::_get_property_list(List<PropertyInfo> *p_list) const } for (int i = 0; i < arguments.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, "argument/" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt)); - p_list->push_back(PropertyInfo(Variant::STRING, "argument/" + itos(i + 1) + "/name")); + p_list->push_back(PropertyInfo(Variant::INT, "argument_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt)); + p_list->push_back(PropertyInfo(Variant::STRING, "argument_" + itos(i + 1) + "/name")); } if (!stack_less) { p_list->push_back(PropertyInfo(Variant::INT, "stack/size", PROPERTY_HINT_RANGE, "1,100000")); @@ -559,8 +559,8 @@ void VisualScriptOperator::_bind_methods() { argt += "," + Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "operator_value/type", PROPERTY_HINT_ENUM, types), "set_operator", "get_operator"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "typed_value/typed", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, types), "set_operator", "get_operator"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed"); } class VisualScriptNodeInstanceOperator : public VisualScriptNodeInstance { @@ -621,6 +621,113 @@ static Ref<VisualScriptNode> create_op_node(const String &p_name) { } ////////////////////////////////////////// +////////////////OPERATOR////////////////// +////////////////////////////////////////// + +int VisualScriptSelect::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptSelect::has_input_sequence_port() const { + + return false; +} + +int VisualScriptSelect::get_input_value_port_count() const { + + return 3; +} +int VisualScriptSelect::get_output_value_port_count() const { + + return 1; +} + +String VisualScriptSelect::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptSelect::get_input_value_port_info(int p_idx) const { + + if (p_idx == 0) { + return PropertyInfo(Variant::BOOL, "cond"); + } else if (p_idx == 1) { + return PropertyInfo(typed, "a"); + } else { + return PropertyInfo(typed, "b"); + } +} +PropertyInfo VisualScriptSelect::get_output_value_port_info(int p_idx) const { + + return PropertyInfo(typed, "out"); +} + +String VisualScriptSelect::get_caption() const { + + return "Select"; +} + +String VisualScriptSelect::get_text() const { + + return "a if cond, else b"; +} + +void VisualScriptSelect::set_typed(Variant::Type p_op) { + + if (typed == p_op) + return; + + typed = p_op; + ports_changed_notify(); +} + +Variant::Type VisualScriptSelect::get_typed() const { + + return typed; +} + +void VisualScriptSelect::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_typed", "type"), &VisualScriptSelect::set_typed); + ClassDB::bind_method(D_METHOD("get_typed"), &VisualScriptSelect::get_typed); + + String argt = "Any"; + for (int i = 1; i < Variant::VARIANT_MAX; i++) { + argt += "," + Variant::get_type_name(Variant::Type(i)); + } + + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed"); +} + +class VisualScriptNodeInstanceSelect : public VisualScriptNodeInstance { +public: + //virtual int get_working_memory_size() const { return 0; } + + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Variant::CallError &r_error, String &r_error_str) { + + bool cond = *p_inputs[0]; + if (cond) + *p_outputs[0] = *p_inputs[1]; + else + *p_outputs[0] = *p_inputs[2]; + + return 0; + } +}; + +VisualScriptNodeInstance *VisualScriptSelect::instance(VisualScriptInstance *p_instance) { + + VisualScriptNodeInstanceSelect *instance = memnew(VisualScriptNodeInstanceSelect); + return instance; +} + +VisualScriptSelect::VisualScriptSelect() { + + typed = Variant::NIL; +} + +////////////////////////////////////////// ////////////////VARIABLE GET////////////////// ////////////////////////////////////////// @@ -691,7 +798,7 @@ StringName VisualScriptVariableGet::get_variable() const { void VisualScriptVariableGet::_validate_property(PropertyInfo &property) const { - if (property.name == "variable/name" && get_visual_script().is_valid()) { + if (property.name == "var_name" && get_visual_script().is_valid()) { Ref<VisualScript> vs = get_visual_script(); List<StringName> vars; vs->get_variable_list(&vars); @@ -714,7 +821,7 @@ void VisualScriptVariableGet::_bind_methods() { ClassDB::bind_method(D_METHOD("set_variable", "name"), &VisualScriptVariableGet::set_variable); ClassDB::bind_method(D_METHOD("get_variable"), &VisualScriptVariableGet::get_variable); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable/name"), "set_variable", "get_variable"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_variable", "get_variable"); } class VisualScriptNodeInstanceVariableGet : public VisualScriptNodeInstance { @@ -816,7 +923,7 @@ StringName VisualScriptVariableSet::get_variable() const { void VisualScriptVariableSet::_validate_property(PropertyInfo &property) const { - if (property.name == "variable/name" && get_visual_script().is_valid()) { + if (property.name == "var_name" && get_visual_script().is_valid()) { Ref<VisualScript> vs = get_visual_script(); List<StringName> vars; vs->get_variable_list(&vars); @@ -839,7 +946,7 @@ void VisualScriptVariableSet::_bind_methods() { ClassDB::bind_method(D_METHOD("set_variable", "name"), &VisualScriptVariableSet::set_variable); ClassDB::bind_method(D_METHOD("get_variable"), &VisualScriptVariableSet::get_variable); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable/name"), "set_variable", "get_variable"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_variable", "get_variable"); } class VisualScriptNodeInstanceVariableSet : public VisualScriptNodeInstance { @@ -956,7 +1063,7 @@ Variant VisualScriptConstant::get_constant_value() const { void VisualScriptConstant::_validate_property(PropertyInfo &property) const { - if (property.name == "constant/value") { + if (property.name == "value") { property.type = type; if (type == Variant::NIL) property.usage = 0; //do not save if nil @@ -976,8 +1083,8 @@ void VisualScriptConstant::_bind_methods() { argt += "," + Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "constant/type", PROPERTY_HINT_ENUM, argt), "set_constant_type", "get_constant_type"); - ADD_PROPERTY(PropertyInfo(Variant::NIL, "constant/value"), "set_constant_value", "get_constant_value"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_constant_type", "get_constant_type"); + ADD_PROPERTY(PropertyInfo(Variant::NIL, "value"), "set_constant_value", "get_constant_value"); } class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance { @@ -1842,7 +1949,7 @@ VisualScriptEngineSingleton::TypeGuess VisualScriptEngineSingleton::guess_output TypeGuess tg; tg.type = Variant::OBJECT; if (obj) { - tg.GDCLASS = obj->get_class(); + tg.gdclass = obj->get_class(); tg.script = obj->get_script(); } @@ -2002,7 +2109,7 @@ VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGu VisualScriptSceneNode::TypeGuess tg; tg.type = Variant::OBJECT; - tg.GDCLASS = "Node"; + tg.gdclass = "Node"; #ifdef TOOLS_ENABLED Ref<Script> script = get_visual_script(); @@ -2031,7 +2138,7 @@ VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGu Node *another = script_node->get_node(path); if (another) { - tg.GDCLASS = another->get_class(); + tg.gdclass = another->get_class(); tg.script = another->get_script(); } #endif @@ -2173,7 +2280,7 @@ VisualScriptSceneTree::TypeGuess VisualScriptSceneTree::guess_output_type(TypeGu TypeGuess tg; tg.type = Variant::OBJECT; - tg.GDCLASS = "SceneTree"; + tg.gdclass = "SceneTree"; return tg; } @@ -2353,13 +2460,13 @@ VisualScriptSelf::TypeGuess VisualScriptSelf::guess_output_type(TypeGuess *p_inp VisualScriptSceneNode::TypeGuess tg; tg.type = Variant::OBJECT; - tg.GDCLASS = "Object"; + tg.gdclass = "Object"; Ref<Script> script = get_visual_script(); if (!script.is_valid()) return tg; - tg.GDCLASS = script->get_instance_base_type(); + tg.gdclass = script->get_instance_base_type(); tg.script = script; return tg; @@ -3088,8 +3195,8 @@ void VisualScriptLocalVar::_bind_methods() { argt += "," + Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable/name"), "set_var_name", "get_var_name"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "variable/type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_var_name", "get_var_name"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type"); } VisualScriptLocalVar::VisualScriptLocalVar() { @@ -3210,8 +3317,8 @@ void VisualScriptLocalVarSet::_bind_methods() { argt += "," + Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable/name"), "set_var_name", "get_var_name"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "variable/type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_var_name", "get_var_name"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type"); } VisualScriptLocalVarSet::VisualScriptLocalVarSet() { @@ -3253,32 +3360,33 @@ PropertyInfo VisualScriptInputAction::get_input_value_port_info(int p_idx) const } PropertyInfo VisualScriptInputAction::get_output_value_port_info(int p_idx) const { - return PropertyInfo(Variant::BOOL, "pressed"); -} - -String VisualScriptInputAction::get_caption() const { - - return "Action"; -} - -String VisualScriptInputAction::get_text() const { - + String mstr; switch (mode) { case MODE_PRESSED: { - return name; + mstr = "pressed"; } break; case MODE_RELEASED: { - return "not " + name; + mstr = "not pressed"; } break; case MODE_JUST_PRESSED: { - return String(name) + " " + TTR("just pressed"); + mstr = "just pressed"; } break; case MODE_JUST_RELEASED: { - return String(name) + " " + TTR("just released"); + mstr = "just released"; } break; } - return String(); + return PropertyInfo(Variant::BOOL, mstr); +} + +String VisualScriptInputAction::get_caption() const { + + return "Action"; +} + +String VisualScriptInputAction::get_text() const { + + return name; } String VisualScriptInputAction::get_category() const { @@ -3319,8 +3427,6 @@ public: StringName action; VisualScriptInputAction::Mode mode; - virtual int get_working_memory_size() const { return 1; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Variant::CallError &r_error, String &r_error_str) { switch (mode) { @@ -3628,6 +3734,7 @@ void register_visual_script_nodes() { VisualScriptLanguage::singleton->add_register_func("operators/logic/xor", create_op_node<Variant::OP_XOR>); VisualScriptLanguage::singleton->add_register_func("operators/logic/not", create_op_node<Variant::OP_NOT>); VisualScriptLanguage::singleton->add_register_func("operators/logic/in", create_op_node<Variant::OP_IN>); + VisualScriptLanguage::singleton->add_register_func("operators/logic/select", create_node_generic<VisualScriptSelect>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct", create_node_generic<VisualScriptDeconstruct>); diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h index 402093fa80..5ae9a1b30b 100644 --- a/modules/visual_script/visual_script_nodes.h +++ b/modules/visual_script/visual_script_nodes.h @@ -127,6 +127,39 @@ public: VisualScriptOperator(); }; +class VisualScriptSelect : public VisualScriptNode { + + GDCLASS(VisualScriptSelect, VisualScriptNode) + + Variant::Type typed; + +protected: + static void _bind_methods(); + +public: + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + virtual String get_output_sequence_port_text(int p_port) const; + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "operators"; } + + void set_typed(Variant::Type p_op); + Variant::Type get_typed() const; + + virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance); + + VisualScriptSelect(); +}; + class VisualScriptVariableGet : public VisualScriptNode { GDCLASS(VisualScriptVariableGet, VisualScriptNode) diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index be5b218d0a..2e111511b7 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -419,13 +419,13 @@ VisualScriptYieldSignal::CallMode VisualScriptYieldSignal::get_call_mode() const void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const { - if (property.name == "signal/base_type") { + if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { property.usage = PROPERTY_USAGE_NOEDITOR; } } - if (property.name == "signal/node_path") { + if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { property.usage = 0; } else { @@ -438,7 +438,7 @@ void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const { } } - if (property.name == "signal/signal") { + if (property.name == "signal") { property.hint = PROPERTY_HINT_ENUM; List<MethodInfo> methods; @@ -488,10 +488,10 @@ void VisualScriptYieldSignal::_bind_methods() { bt += Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::INT, "signal/call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal/base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "signal/node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal/signal"), "set_signal", "get_signal"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance"), "set_call_mode", "get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal"), "set_signal", "get_signal"); BIND_CONSTANT(CALL_MODE_SELF); BIND_CONSTANT(CALL_MODE_NODE_PATH); diff --git a/platform/android/detect.py b/platform/android/detect.py index ce44ffbf74..7508c9ed0e 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -14,22 +14,17 @@ def get_name(): def can_build(): - import os - if (not os.environ.has_key("ANDROID_NDK_ROOT")): - return False - - return True + return (os.environ.has_key("ANDROID_NDK_ROOT")) def get_opts(): return [ - ('ANDROID_NDK_ROOT', 'the path to Android NDK', - os.environ.get("ANDROID_NDK_ROOT", 0)), - ('ndk_platform', 'compile for platform: (android-<api> , example: android-18)', "android-18"), - ('android_arch', 'select compiler architecture: (armv7/armv6/x86)', "armv7"), - ('android_neon', 'enable neon (armv7 only)', "yes"), - ('android_stl', 'enable STL support in android port (for modules)', "no") + ('ANDROID_NDK_ROOT', 'Path to the Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)), + ('ndk_platform', 'Target platform (android-<api>, e.g. "android-18")', "android-18"), + ('android_arch', 'Target architecture (armv7/armv6/x86)', "armv7"), + ('android_neon', 'Enable NEON support (armv7 only)', "yes"), + ('android_stl', 'Enable Android STL support (for modules)', "no") ] @@ -41,6 +36,7 @@ def get_flags(): def create(env): + tools = env['TOOLS'] if "mingw" in tools: tools.remove('mingw') @@ -54,7 +50,6 @@ def configure(env): # Workaround for MinGW. See: # http://www.scons.org/wiki/LongCmdLinesOnWin32 - import os if (os.name == "nt"): import subprocess @@ -92,35 +87,43 @@ def configure(env): env['SPAWN'] = mySpawn - ndk_platform = env['ndk_platform'] + ## Build type - if env['android_arch'] not in ['armv7', 'armv6', 'x86']: - env['android_arch'] = 'armv7' + if (env["target"].startswith("release")): + env.Append(LINKFLAGS=['-O2']) + env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', '-funsafe-math-optimizations', '-fomit-frame-pointer']) + if (can_vectorize): + env.Append(CPPFLAGS=['-ftree-vectorize']) + if (env["target"] == "release_debug"): + env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) + elif (env["target"] == "debug"): + env.Append(LINKFLAGS=['-O0']) + env.Append(CPPFLAGS=['-O0', '-D_DEBUG', '-UNDEBUG', '-DDEBUG_ENABLED', + '-DDEBUG_MEMORY_ENABLED', '-g', '-fno-limit-debug-info']) - if env['android_arch'] == 'x86': - env["x86_libtheora_opt_gcc"] = True + ## Architecture - if env['PLATFORM'] == 'win32': - env.Tool('gcc') - env['SHLIBSUFFIX'] = '.so' + if env['android_arch'] not in ['armv7', 'armv6', 'x86']: + env['android_arch'] = 'armv7' neon_text = "" if env["android_arch"] == "armv7" and env['android_neon'] == 'yes': - neon_text = " (with neon)" - print("Godot Android!!!!! (" + env['android_arch'] + ")" + neon_text) - - env.Append(CPPPATH=['#platform/android']) + neon_text = " (with NEON)" + print("Building for Android (" + env['android_arch'] + ")" + neon_text) + can_vectorize = True if env['android_arch'] == 'x86': env.extra_suffix = ".x86" + env.extra_suffix target_subpath = "x86-4.9" abi_subpath = "i686-linux-android" arch_subpath = "x86" + env["x86_libtheora_opt_gcc"] = True elif env['android_arch'] == 'armv6': env.extra_suffix = ".armv6" + env.extra_suffix target_subpath = "arm-linux-androideabi-4.9" abi_subpath = "arm-linux-androideabi" arch_subpath = "armeabi" + can_vectorize = False elif env["android_arch"] == "armv7": target_subpath = "arm-linux-androideabi-4.9" abi_subpath = "arm-linux-androideabi" @@ -130,6 +133,14 @@ def configure(env): else: env.extra_suffix = ".armv7" + env.extra_suffix + ## Compiler configuration + + env['SHLIBSUFFIX'] = '.so' + + if env['PLATFORM'] == 'win32': + env.Tool('gcc') + env.use_windows_spawn_fix() + mt_link = True if (sys.platform.startswith("linux")): host_subpath = "linux-x86_64" @@ -142,10 +153,8 @@ def configure(env): mt_link = False host_subpath = "windows" - compiler_path = env["ANDROID_NDK_ROOT"] + \ - "/toolchains/llvm/prebuilt/" + host_subpath + "/bin" - gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + \ - "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath + compiler_path = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/" + host_subpath + "/bin" + gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath tools_path = gcc_toolchain_path + "/" + abi_subpath + "/bin" # For Clang to find NDK tools in preference of those system-wide @@ -162,31 +171,28 @@ def configure(env): else: env['ARCH'] = 'arch-arm' - sysroot = env["ANDROID_NDK_ROOT"] + \ - "/platforms/" + ndk_platform + "/" + env['ARCH'] + sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH'] common_opts = ['-fno-integrated-as', '-gcc-toolchain', gcc_toolchain_path] + ## Compile flags + env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"]) - env.Append(CPPFLAGS=string.split( - '-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing')) + env.Append(CPPFLAGS=string.split('-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing')) env.Append(CPPFLAGS=string.split('-DANDROID -DNO_STATVFS -DGLES2_ENABLED')) env['neon_enabled'] = False if env['android_arch'] == 'x86': - can_vectorize = True target_opts = ['-target', 'i686-none-linux-android'] # The NDK adds this if targeting API < 21, so we can drop it when Godot targets it at least env.Append(CPPFLAGS=['-mstackrealign']) + elif env["android_arch"] == "armv6": - can_vectorize = False target_opts = ['-target', 'armv6-none-linux-androideabi'] - env.Append(CPPFLAGS=string.split( - '-D__ARM_ARCH_6__ -march=armv6 -mfpu=vfp -mfloat-abi=softfp')) + env.Append(CPPFLAGS=string.split('-D__ARM_ARCH_6__ -march=armv6 -mfpu=vfp -mfloat-abi=softfp')) + elif env["android_arch"] == "armv7": - can_vectorize = True target_opts = ['-target', 'armv7-none-linux-androideabi'] - env.Append(CPPFLAGS=string.split( - '-D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -march=armv7-a -mfloat-abi=softfp')) + env.Append(CPPFLAGS=string.split('-D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -march=armv7-a -mfloat-abi=softfp')) if env['android_neon'] == 'yes': env['neon_enabled'] = True env.Append(CPPFLAGS=['-mfpu=neon', '-D__ARM_NEON__']) @@ -196,21 +202,20 @@ def configure(env): env.Append(CPPFLAGS=target_opts) env.Append(CPPFLAGS=common_opts) - env.Append(LIBS=['OpenSLES']) - env.Append(LIBS=['EGL', 'OpenSLES', 'android']) - env.Append(LIBS=['log', 'GLESv1_CM', 'GLESv2', 'GLESv3','z']) - - if (sys.platform.startswith("darwin")): - env['SHLIBSUFFIX'] = '.so' - - env['LINKFLAGS'] = ['-shared', '--sysroot=' + - sysroot, '-Wl,--warn-shared-textrel'] - env.Append(LINKFLAGS=string.split( - '-Wl,--fix-cortex-a8')) - env.Append(LINKFLAGS=string.split( - '-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now')) - env.Append(LINKFLAGS=string.split( - '-Wl,-soname,libgodot_android.so -Wl,--gc-sections')) + if (env['android_stl'] == 'yes'): + env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/include"]) + env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath + "/include"]) + env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath]) + env.Append(LIBS=["gnustl_static"]) + else: + env.Append(CXXFLAGS=['-fno-rtti', '-fno-exceptions', '-DNO_SAFE_CAST']) + + ## Link flags + + env['LINKFLAGS'] = ['-shared', '--sysroot=' + sysroot, '-Wl,--warn-shared-textrel'] + env.Append(LINKFLAGS=string.split('-Wl,--fix-cortex-a8')) + env.Append(LINKFLAGS=string.split('-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now')) + env.Append(LINKFLAGS=string.split('-Wl,-soname,libgodot_android.so -Wl,--gc-sections')) if mt_link: env.Append(LINKFLAGS=['-Wl,--threads']) env.Append(LINKFLAGS=target_opts) @@ -221,45 +226,12 @@ def configure(env): env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + '/toolchains/arm-linux-androideabi-4.9/prebuilt/' + host_subpath + '/' + abi_subpath + '/lib']) - if (env["target"].startswith("release")): - env.Append(LINKFLAGS=['-O2']) - env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', - '-funsafe-math-optimizations', '-fomit-frame-pointer']) - if (can_vectorize): - env.Append(CPPFLAGS=['-ftree-vectorize']) - if (env["target"] == "release_debug"): - env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) - elif (env["target"] == "debug"): - env.Append(LINKFLAGS=['-O0']) - env.Append(CPPFLAGS=['-O0', '-D_DEBUG', '-UNDEBUG', '-DDEBUG_ENABLED', - '-DDEBUG_MEMORY_ENABLED', '-g', '-fno-limit-debug-info']) - - env.Append(CPPFLAGS=['-DANDROID_ENABLED', - '-DUNIX_ENABLED', '-DNO_FCNTL', '-DMPC_FIXED_POINT']) + env.Append(CPPPATH=['#platform/android']) + env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL', '-DMPC_FIXED_POINT']) + env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'android', 'log', 'z']) # TODO: Move that to opus module's config if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): if (env["android_arch"] == "armv6" or env["android_arch"] == "armv7"): env.Append(CFLAGS=["-DOPUS_ARM_OPT"]) env.opus_fixed_point = "yes" - - if (env['android_stl'] == 'yes'): - env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + - "/sources/cxx-stl/gnu-libstdc++/4.9/include"]) - env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + - "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath + "/include"]) - env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + - "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath]) - env.Append(LIBS=["gnustl_static"]) - else: - env.Append(CXXFLAGS=['-fno-rtti', '-fno-exceptions', '-DNO_SAFE_CAST']) - - 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.use_windows_spawn_fix() diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py index 54e227cd19..c0e003a3d2 100644 --- a/platform/haiku/detect.py +++ b/platform/haiku/detect.py @@ -11,57 +11,58 @@ def get_name(): def can_build(): - if (os.name != "posix"): - return False - if (sys.platform == "darwin"): + if (os.name != "posix" or sys.platform == "darwin"): return False return True def get_opts(): + return [ ('debug_release', 'Add debug symbols to release version', 'no') ] def get_flags(): + return [ ] def configure(env): - is64 = sys.maxsize > 2**32 - - if (env["bits"] == "default"): - if (is64): - env["bits"] = "64" - else: - env["bits"] = "32" - - env.Append(CPPPATH=['#platform/haiku']) - env["CC"] = "gcc-x86" - env["CXX"] = "g++-x86" + ## Build type if (env["target"] == "release"): if (env["debug_release"] == "yes"): - env.Append(CCFLAGS=['-g2']) + env.Prepend(CCFLAGS=['-g2']) else: - env.Append(CCFLAGS=['-O3', '-ffast-math']) + env.Prepend(CCFLAGS=['-O3', '-ffast-math']) + elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) + env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) + elif (env["target"] == "debug"): - env.Append(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + + ## Architecture + + is64 = sys.maxsize > 2**32 + if (env["bits"] == "default"): + env["bits"] = "64" if is64 else "32" + + ## Compiler configuration + env["CC"] = "gcc-x86" + env["CXX"] = "g++-x86" + + ## Flags + + env.Append(CPPPATH=['#platform/haiku']) + env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) + env.Append(CPPFLAGS=['-DMEDIA_KIT_ENABLED']) # env.Append(CCFLAGS=['-DFREETYPE_ENABLED']) env.Append(CPPFLAGS=['-DPTHREAD_NO_RENAME']) # TODO: enable when we have pthread_setname_np - env.Append(CPPFLAGS=['-DOPENGL_ENABLED', '-DMEDIA_KIT_ENABLED']) - env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) env.Append(LIBS=['be', 'game', 'media', 'network', 'bnetapi', 'z', 'GL']) - - 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')}) diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index 466b8241de..998d0a3f0d 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -17,17 +17,8 @@ iphone_lib = [ 'ios.mm', ] -# env.Depends('#core/math/vector3.h', 'vector3_psp.h') - -#iphone_lib = env.Library('iphone', iphone_lib) - env_ios = env.Clone() - -if env['ios_gles22_override'] == "yes": - env_ios.Append(CPPFLAGS=['-DGLES2_OVERRIDE']) - - obj = env_ios.Object('godot_iphone.cpp') prog = None diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index c20d8e90f4..1d802ff288 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -1,4 +1,5 @@ import os +import string import sys @@ -12,8 +13,6 @@ def get_name(): def can_build(): - import sys - import os if sys.platform == 'darwin' or os.environ.has_key("OSXCROSS_IOS"): return True @@ -23,13 +22,12 @@ def can_build(): def get_opts(): return [ - ('IPHONEPLATFORM', 'name of the iphone platform', 'iPhoneOS'), - ('IPHONEPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'), - ('IPHONESDK', 'path to the iphone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/${IPHONEPLATFORM}.platform/Developer/SDKs/${IPHONEPLATFORM}.sdk/'), + ('IPHONEPLATFORM', 'Name of the iPhone platform', 'iPhoneOS'), + ('IPHONEPATH', 'Path to iPhone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'), + ('IPHONESDK', 'Path to the iPhone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/${IPHONEPLATFORM}.platform/Developer/SDKs/${IPHONEPLATFORM}.sdk/'), ('game_center', 'Support for game center', 'yes'), ('store_kit', 'Support for in-app store', 'yes'), ('icloud', 'Support for iCloud', 'yes'), - ('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'), ('ios_exceptions', 'Enable exceptions', 'no'), ('ios_triple', 'Triple for ios toolchain', ''), ('ios_sim', 'Build simulator binary', 'no'), @@ -45,95 +43,92 @@ def get_flags(): def configure(env): - env.Append(CPPPATH=['#platform/iphone']) + ## Build type - env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH'] + if (env["target"].startswith("release")): + env.Append(CPPFLAGS=['-DNDEBUG', '-DNS_BLOCK_ASSERTIONS=1']) + env.Append(CPPFLAGS=['-O2', '-flto', '-ftree-vectorize', '-fomit-frame-pointer', '-ffast-math', '-funsafe-math-optimizations']) + env.Append(LINKFLAGS=['-O2', '-flto']) - env['CC'] = '$IPHONEPATH/usr/bin/${ios_triple}clang' - env['CXX'] = '$IPHONEPATH/usr/bin/${ios_triple}clang++' - env['AR'] = '$IPHONEPATH/usr/bin/${ios_triple}ar' - env['RANLIB'] = '$IPHONEPATH/usr/bin/${ios_triple}ranlib' + if env["target"] == "release_debug": + env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) + + elif (env["target"] == "debug"): + env.Append(CPPFLAGS=['-D_DEBUG', '-DDEBUG=1', '-gdwarf-2', '-O0', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + + ## Architecture - import string if (env["ios_sim"] == "yes" or env["arch"] == "x86"): # i386, simulator env["arch"] = "x86" env["bits"] = "32" - env.Append(CCFLAGS=string.split('-arch i386 -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -D__IPHONE_OS_VERSION_MIN_REQUIRED=40100 -isysroot $IPHONESDK -mios-simulator-version-min=4.3 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"')) elif (env["arch"] == "arm" or env["arch"] == "arm32" or env["arch"] == "armv7" or env["bits"] == "32"): # arm env["arch"] = "arm" env["bits"] = "32" - env.Append(CCFLAGS=string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=9.0 -MMD -MT dependencies')) else: # armv64 env["arch"] = "arm64" env["bits"] = "64" + + ## Compiler configuration + + env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH'] + + env['CC'] = '$IPHONEPATH/usr/bin/${ios_triple}clang' + env['CXX'] = '$IPHONEPATH/usr/bin/${ios_triple}clang++' + env['AR'] = '$IPHONEPATH/usr/bin/${ios_triple}ar' + env['RANLIB'] = '$IPHONEPATH/usr/bin/${ios_triple}ranlib' + env['S_compiler'] = '$IPHONEPATH/Developer/usr/bin/gcc' + + ## Compile flags + + if (env["arch"] == "x86"): + env['IPHONEPLATFORM'] = 'iPhoneSimulator' + env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.6' + env.Append(CCFLAGS=string.split('-arch i386 -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -D__IPHONE_OS_VERSION_MIN_REQUIRED=40100 -isysroot $IPHONESDK -mios-simulator-version-min=4.3 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"')) + elif (env["arch"] == "arm"): + env.Append(CCFLAGS=string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=9.0 -MMD -MT dependencies')) + elif (env["arch"] == "arm64"): env.Append(CCFLAGS=string.split('-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -miphoneos-version-min=9.0 -isysroot $IPHONESDK')) env.Append(CPPFLAGS=['-DNEED_LONG_INT']) env.Append(CPPFLAGS=['-DLIBYUV_DISABLE_NEON']) + if env['ios_exceptions'] == 'yes': + env.Append(CPPFLAGS=['-fexceptions']) + else: + env.Append(CPPFLAGS=['-fno-exceptions']) + + ## Link flags + if (env["arch"] == "x86"): - env['IPHONEPLATFORM'] = 'iPhoneSimulator' env.Append(LINKFLAGS=['-arch', 'i386', '-mios-simulator-version-min=4.3', '-isysroot', '$IPHONESDK', - #'-mmacosx-version-min=10.6', '-Xlinker', '-objc_abi_version', '-Xlinker', '2', - '-framework', 'AudioToolbox', - '-framework', 'AVFoundation', - '-framework', 'CoreAudio', - '-framework', 'CoreGraphics', - '-framework', 'CoreMedia', - '-framework', 'CoreMotion', - '-framework', 'Foundation', - '-framework', 'Security', - '-framework', 'UIKit', - '-framework', 'MediaPlayer', - '-framework', 'OpenGLES', - '-framework', 'QuartzCore', - '-framework', 'SystemConfiguration', - '-framework', 'GameController', '-F$IPHONESDK', ]) - elif (env["arch"] == "arm64"): - env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=9.0', - '-isysroot', '$IPHONESDK', - #'-stdlib=libc++', - '-framework', 'Foundation', - '-framework', 'UIKit', - '-framework', 'CoreGraphics', - '-framework', 'OpenGLES', - '-framework', 'QuartzCore', - '-framework', 'CoreAudio', - '-framework', 'AudioToolbox', - '-framework', 'SystemConfiguration', - '-framework', 'Security', - #'-framework', 'AdSupport', - '-framework', 'MediaPlayer', - '-framework', 'AVFoundation', - '-framework', 'CoreMedia', - '-framework', 'CoreMotion', - '-framework', 'GameController', - ]) - else: - env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=9.0', - '-isysroot', '$IPHONESDK', - '-framework', 'Foundation', - '-framework', 'UIKit', - '-framework', 'CoreGraphics', - '-framework', 'OpenGLES', - '-framework', 'QuartzCore', - '-framework', 'CoreAudio', - '-framework', 'AudioToolbox', - '-framework', 'SystemConfiguration', - '-framework', 'Security', - #'-framework', 'AdSupport', - '-framework', 'MediaPlayer', - '-framework', 'AVFoundation', - '-framework', 'CoreMedia', - '-framework', 'CoreMotion', - '-framework', 'GameController', - ]) - + elif (env["arch"] == "arm"): + env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=9.0']) + if (env["arch"] == "arm64"): + env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=9.0']) + + env.Append(LINKFLAGS=['-isysroot', '$IPHONESDK', + '-framework', 'AudioToolbox', + '-framework', 'AVFoundation', + '-framework', 'CoreAudio', + '-framework', 'CoreGraphics', + '-framework', 'CoreMedia', + '-framework', 'CoreMotion', + '-framework', 'Foundation', + '-framework', 'GameController', + '-framework', 'MediaPlayer', + '-framework', 'OpenGLES', + '-framework', 'QuartzCore', + '-framework', 'Security', + '-framework', 'SystemConfiguration', + '-framework', 'UIKit', + ]) + + # Feature options if env['game_center'] == 'yes': env.Append(CPPFLAGS=['-DGAME_CENTER_ENABLED']) env.Append(LINKFLAGS=['-framework', 'GameKit']) @@ -145,45 +140,20 @@ def configure(env): if env['icloud'] == 'yes': env.Append(CPPFLAGS=['-DICLOUD_ENABLED']) - env.Append(CPPPATH=['$IPHONESDK/usr/include', '$IPHONESDK/System/Library/Frameworks/OpenGLES.framework/Headers', '$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers']) + env.Append(CPPPATH=['$IPHONESDK/usr/include', + '$IPHONESDK/System/Library/Frameworks/OpenGLES.framework/Headers', + '$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers', + ]) - if (env["target"].startswith("release")): - - env.Append(CPPFLAGS=['-DNDEBUG', '-DNS_BLOCK_ASSERTIONS=1']) - env.Append(CPPFLAGS=['-O2', '-flto', '-ftree-vectorize', '-fomit-frame-pointer', '-ffast-math', '-funsafe-math-optimizations']) - env.Append(LINKFLAGS=['-O2', '-flto']) - - if env["target"] == "release_debug": - env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) - - elif (env["target"] == "debug"): - - env.Append(CPPFLAGS=['-D_DEBUG', '-DDEBUG=1', '-gdwarf-2', '-O0', '-DDEBUG_ENABLED']) - env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ENABLED']) - - if (env["ios_sim"] == "yes"): # TODO: Check if needed? - env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.6' env['ENV']['CODESIGN_ALLOCATE'] = '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate' + + env.Append(CPPPATH=['#platform/iphone']) env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DMPC_FIXED_POINT']) # TODO: Move that to opus module's config if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): env.opus_fixed_point = "yes" - if env["arch"] == "x86": - pass - elif(env["arch"] == "arm64"): - env.Append(CFLAGS=["-DOPUS_ARM64_OPT"]) - else: + if (env["arch"] == "arm"): env.Append(CFLAGS=["-DOPUS_ARM_OPT"]) - - if env['ios_exceptions'] == 'yes': - env.Append(CPPFLAGS=['-fexceptions']) - else: - env.Append(CPPFLAGS=['-fno-exceptions']) - # env['neon_enabled']=True - env['S_compiler'] = '$IPHONEPATH/Developer/usr/bin/gcc' - - 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')}) + elif (env["arch"] == "arm64"): + env.Append(CFLAGS=["-DOPUS_ARM64_OPT"]) diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index 41fe3fb027..68c8d1eea5 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -1,6 +1,6 @@ import os -import sys import string +import sys def is_active(): @@ -12,7 +12,8 @@ def get_name(): def can_build(): - return os.environ.has_key("EMSCRIPTEN_ROOT") + + return (os.environ.has_key("EMSCRIPTEN_ROOT")) def get_opts(): @@ -27,12 +28,12 @@ def get_flags(): return [ ('tools', 'no'), - ('module_etc1_enabled', 'no'), ('module_theora_enabled', 'no'), ] def create(env): + # remove Windows' .exe suffix return env.Clone(tools=['textfile', 'zip'], PROGSUFFIX='') @@ -45,10 +46,26 @@ def escape_target_backslashes(target, source, env, for_signature): def configure(env): - env['ENV'] = os.environ - env.Append(CPPPATH=['#platform/javascript']) + ## Build type + + if (env["target"] == "release"): + env.Append(CCFLAGS=['-O3']) + env.Append(LINKFLAGS=['-O3']) + elif (env["target"] == "release_debug"): + env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + env.Append(LINKFLAGS=['-O2', '-s', 'ASSERTIONS=1']) + # retain function names at the cost of file size, for backtraces and profiling + env.Append(LINKFLAGS=['--profiling-funcs']) + + elif (env["target"] == "debug"): + env.Append(CCFLAGS=['-O1', '-D_DEBUG', '-g', '-DDEBUG_ENABLED']) + env.Append(LINKFLAGS=['-O1', '-g']) + + ## Compiler configuration + + env['ENV'] = os.environ env.PrependENVPath('PATH', os.environ['EMSCRIPTEN_ROOT']) env['CC'] = 'emcc' env['CXX'] = 'em++' @@ -57,6 +74,7 @@ def configure(env): # Emscripten's ar has issues with duplicate file names, so use cc env['AR'] = 'emcc' env['ARFLAGS'] = '-o' + if (os.name == 'nt'): # use TempFileMunge on Windows since some commands get too long for # cmd.exe even with spawn_fix @@ -68,26 +86,20 @@ def configure(env): env['OBJSUFFIX'] = '.bc' env['LIBSUFFIX'] = '.bc' - if (env["target"] == "release"): - env.Append(CCFLAGS=['-O3']) - env.Append(LINKFLAGS=['-O3']) - elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) - env.Append(LINKFLAGS=['-O2', '-s', 'ASSERTIONS=1']) - # retain function names at the cost of file size, for backtraces and profiling - env.Append(LINKFLAGS=['--profiling-funcs']) - elif (env["target"] == "debug"): - env.Append(CCFLAGS=['-O1', '-D_DEBUG', '-g', '-DDEBUG_ENABLED']) - env.Append(LINKFLAGS=['-O1', '-g']) + ## Compile flags - # TODO: Move that to opus module's config - if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): - env.opus_fixed_point = "yes" + env.Append(CPPPATH=['#platform/javascript']) + env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-DPTHREAD_NO_RENAME', '-DTYPED_METHOD_BIND', '-DNO_THREADS']) + env.Append(CPPFLAGS=['-DGLES3_ENABLED']) # 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', '-DTYPED_METHOD_BIND', '-DNO_THREADS']) - env.Append(CPPFLAGS=['-DGLES3_ENABLED']) + + if env['javascript_eval'] == 'yes': + env.Append(CPPFLAGS=['-DJAVASCRIPT_EVAL_ENABLED']) + + ## Link flags + env.Append(LINKFLAGS=['-s', 'USE_WEBGL2=1']) if (env['wasm'] == 'yes'): @@ -101,8 +113,6 @@ def configure(env): env.Append(LINKFLAGS=['-s', 'ASM_JS=1']) env.Append(LINKFLAGS=['--separate-asm']) - if env['javascript_eval'] == 'yes': - env.Append(CPPFLAGS=['-DJAVASCRIPT_EVAL_ENABLED']) - - - import methods + # TODO: Move that to opus module's config + if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): + env.opus_fixed_point = "yes" diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 39ee33ae82..dfefbbc1ba 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -1,4 +1,3 @@ - import os import sys @@ -22,9 +21,7 @@ def can_build(): def get_opts(): return [ - ('force_64_bits', 'Force 64 bits binary', 'no'), ('osxcross_sdk', 'OSXCross SDK version', 'darwin14'), - ] @@ -36,36 +33,37 @@ def get_flags(): def configure(env): - env.Append(CPPPATH=['#platform/osx']) - - if (env["bits"] == "default"): - env["bits"] = "32" + ## Build type if (env["target"] == "release"): - - env.Append(CCFLAGS=['-O2', '-ffast-math', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2']) + env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2']) elif (env["target"] == "release_debug"): - - env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + env.Prepend(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) elif (env["target"] == "debug"): + env.Prepend(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) - env.Append(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + ## Architecture - if (not os.environ.has_key("OSXCROSS_ROOT")): - # regular native build - if (env["bits"] == "64"): - env.Append(CCFLAGS=['-arch', 'x86_64']) - env.Append(LINKFLAGS=['-arch', 'x86_64']) + is64 = sys.maxsize > 2**32 + if (env["bits"] == "default"): + env["bits"] = "64" if is64 else "32" + + ## Compiler configuration + + if (not os.environ.has_key("OSXCROSS_ROOT")): # regular native build + if (env["bits"] == "fat"): + env.Append(CCFLAGS=['-arch', 'i386', '-arch', 'x86_64']) + env.Append(LINKFLAGS=['-arch', 'i386', '-arch', 'x86_64']) elif (env["bits"] == "32"): env.Append(CCFLAGS=['-arch', 'i386']) env.Append(LINKFLAGS=['-arch', 'i386']) - else: - env.Append(CCFLAGS=['-arch', 'i386', '-arch', 'x86_64']) - env.Append(LINKFLAGS=['-arch', 'i386', '-arch', 'x86_64']) - else: - # osxcross build + else: # 64-bit, default + env.Append(CCFLAGS=['-arch', 'x86_64']) + env.Append(LINKFLAGS=['-arch', 'x86_64']) + + else: # osxcross build root = os.environ.get("OSXCROSS_ROOT", 0) if env["bits"] == "64": basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-" @@ -78,26 +76,22 @@ def configure(env): env['RANLIB'] = basecmd + "ranlib" env['AS'] = basecmd + "as" - env.Append(CPPFLAGS=["-DAPPLE_STYLE_KEYS"]) - env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DOSX_ENABLED']) - env.Append(CPPFLAGS=["-mmacosx-version-min=10.9"]) - env.Append(LIBS=['pthread']) - #env.Append(CPPFLAGS=['-F/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-mmacosx-version-min=10.4']) - #env.Append(LINKFLAGS=['-mmacosx-version-min=10.4', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk']) - env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) - env.Append(LINKFLAGS=["-mmacosx-version-min=10.9"]) - if (env["CXX"] == "clang++"): env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) env["CC"] = "clang" env["LD"] = "clang++" - import methods + ## Dependencies + + if (env['builtin_libtheora'] != 'no'): + env["x86_libtheora_opt_gcc"] = True + + ## Flags - 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') } ) + env.Append(CPPPATH=['#platform/osx']) + env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DAPPLE_STYLE_KEYS']) + env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) + env.Append(LIBS=['pthread']) - env["x86_libtheora_opt_gcc"] = True - + env.Append(CPPFLAGS=['-mmacosx-version-min=10.9']) + env.Append(LINKFLAGS=['-mmacosx-version-min=10.9']) diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 066adde780..9d3493cb49 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -41,6 +41,7 @@ #include "platform/osx/logo.gen.h" #include "string.h" #include "version.h" +#include <sys/stat.h> class EditorExportPlatformOSX : public EditorExportPlatform { @@ -52,6 +53,10 @@ class EditorExportPlatformOSX : public EditorExportPlatform { void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary); void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data); +#ifdef OSX_ENABLED + Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path); + Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name); +#endif protected: virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features); @@ -61,7 +66,11 @@ public: virtual String get_name() const { return "Mac OSX"; } virtual Ref<Texture> get_logo() const { return logo; } +#ifdef OSX_ENABLED + virtual String get_binary_extension() const { return "dmg"; } +#else virtual String get_binary_extension() const { return "zip"; } +#endif virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0); virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; @@ -90,6 +99,11 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false)); + +#ifdef OSX_ENABLED + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements"), "")); +#endif } void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { @@ -177,21 +191,62 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset } } +#ifdef OSX_ENABLED +/** + If we're running the OSX version of the Godot editor we'll: + - export our application bundle to a temporary folder + - attempt to code sign it + - and then wrap it up in a DMG +**/ + +Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) { + List<String> args; + if (p_preset->get("codesign/entitlements") != "") { + /* this should point to our entitlements.plist file that sandboxes our application, I don't know if this should also be placed in our app bundle */ + args.push_back("-entitlements"); + args.push_back(p_preset->get("codesign/entitlements")); + } + args.push_back("-s"); + args.push_back(p_preset->get("codesign/identity")); + args.push_back("-v"); /* provide some more feedback */ + args.push_back(p_path); + Error err = OS::get_singleton()->execute("/usr/bin/codesign", args, true); + ERR_FAIL_COND_V(err, err); + + return OK; +} + +Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) { + List<String> args; + args.push_back("create"); + args.push_back(p_dmg_path); + args.push_back("-volname"); + args.push_back(p_pkg_name); + args.push_back("-fs"); + args.push_back("HFS+"); + args.push_back("-srcfolder"); + args.push_back(p_app_path_name); + Error err = OS::get_singleton()->execute("/usr/bin/hdiutil", args, true); + ERR_FAIL_COND_V(err, err); + + return OK; +} + Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { - String src_pkg; + String src_pkg_name; - EditorProgress ep("export", "Exporting for OSX", 104); + EditorProgress ep("export", "Exporting for OSX", 3); if (p_debug) - src_pkg = p_preset->get("custom_package/debug"); + src_pkg_name = p_preset->get("custom_package/debug"); else - src_pkg = p_preset->get("custom_package/release"); + src_pkg_name = p_preset->get("custom_package/release"); - if (src_pkg == "") { + if (src_pkg_name == "") { String err; - src_pkg = find_export_template("osx.zip", &err); - if (src_pkg == "") { + src_pkg_name = find_export_template("osx.zip", &err); + if (src_pkg_name == "") { EditorNode::add_io_error(err); return ERR_FILE_NOT_FOUND; } @@ -202,20 +257,15 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p ep.step("Creating app", 0); - unzFile pkg = unzOpen2(src_pkg.utf8().get_data(), &io); - if (!pkg) { + unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); + if (!src_pkg_zip) { - EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg); + EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name); return ERR_FILE_NOT_FOUND; } - ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN); - int ret = unzGoToFirstFile(pkg); - - zlib_filefunc_def io2 = io; - FileAccess *dst_f = NULL; - io2.opaque = &dst_f; - zipFile dpkg = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2); + ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN); + int ret = unzGoToFirstFile(src_pkg_zip); String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + "."; int bits_mode = p_preset->get("application/bits_mode"); @@ -230,14 +280,34 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p else pkg_name = "Unnamed"; + // We're on OSX so we can export to DMG, but first we create our application bundle + String tmp_app_path_name = p_path.get_base_dir() + "/" + pkg_name + ".app"; + print_line("Exporting to " + tmp_app_path_name); + DirAccess *tmp_app_path = DirAccess::create_for_path(tmp_app_path_name); + ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE) + + ///@TODO We should delete the existing application bundle especially if we attempt to code sign it, but what is a safe way to do this? Maybe call system function so it moves to trash? + // tmp_app_path->erase_contents_recursive(); + + // Create our folder structure or rely on unzip? + print_line("Creating " + tmp_app_path_name + "/Contents/MacOS"); + Error dir_err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS"); + ERR_FAIL_COND_V(dir_err, ERR_CANT_CREATE) + print_line("Creating " + tmp_app_path_name + "/Contents/Resources"); + dir_err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources"); + ERR_FAIL_COND_V(dir_err, ERR_CANT_CREATE) + + /* Now process our template */ bool found_binary = false; + int total_size = 0; while (ret == UNZ_OK) { + bool is_execute = false; //get filename unz_file_info info; char fname[16384]; - ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0); + ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0); String file = fname; @@ -246,9 +316,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p data.resize(info.uncompressed_size); //read - unzOpenCurrentFile(pkg); - unzReadCurrentFile(pkg, data.ptr(), data.size()); - unzCloseCurrentFile(pkg); + unzOpenCurrentFile(src_pkg_zip); + unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size()); + unzCloseCurrentFile(src_pkg_zip); //write @@ -261,10 +331,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (file.begins_with("Contents/MacOS/godot_")) { if (file != "Contents/MacOS/" + binary_to_use) { - ret = unzGoToNextFile(pkg); + ret = unzGoToNextFile(src_pkg_zip); continue; //ignore! } found_binary = true; + is_execute = true; file = "Contents/MacOS/" + pkg_name; } @@ -288,11 +359,206 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p //bleh? } - file = pkg_name + ".app/" + file; + if (data.size() > 0) { + print_line("ADDING: " + file + " size: " + itos(data.size())); + total_size += data.size(); + + /* write it into our application bundle */ + file = tmp_app_path_name + "/" + file; + + /* write the file, need to add chmod */ + FileAccess *f = FileAccess::open(file, FileAccess::WRITE); + ERR_FAIL_COND_V(!f, ERR_CANT_CREATE) + f->store_buffer(data.ptr(), data.size()); + f->close(); + memdelete(f); + + if (is_execute) { + // we need execute rights on this file + chmod(file.utf8().get_data(), 0755); + } else { + // seems to already be set correctly + // chmod(file.utf8().get_data(), 0644); + } + } + + ret = unzGoToNextFile(src_pkg_zip); + } + + /* we're done with our source zip */ + unzClose(src_pkg_zip); + + if (!found_binary) { + ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive."); + unzClose(src_pkg_zip); + return ERR_FILE_NOT_FOUND; + } + + ep.step("Making PKG", 1); + + String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck"; + Error err = save_pack(p_preset, pack_path); + // chmod(pack_path.utf8().get_data(), 0644); + + if (err) { + return err; + } + + /* see if we can code sign our new package */ + if (p_preset->get("codesign/identity") != "") { + ep.step("Code signing bundle", 2); + + /* the order in which we code sign is important, this is a bit of a shame or we could do this in our loop that extracts the files from our ZIP */ + + // start with our application + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name); + ERR_FAIL_COND_V(err, err); + + ///@TODO we should check the contents of /Contents/Frameworks for frameworks to sign + + // we should probably loop through all resources and sign them? + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Resources/icon.icns"); + ERR_FAIL_COND_V(err, err); + err = _code_sign(p_preset, pack_path); + ERR_FAIL_COND_V(err, err); + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Info.plist"); + ERR_FAIL_COND_V(err, err); + } + + /* and finally create a DMG */ + ep.step("Making DMG", 3); + err = _create_dmg(p_path, pkg_name, tmp_app_path_name); + ERR_FAIL_COND_V(err, err); + + return OK; +} + +#else + +/** + When exporting for OSX from any other platform we don't have access to code signing or creating DMGs so we'll wrap the bundle into a zip file. + + Should probably find a nicer way to have just one export method instead of duplicating the method like this but I would the code got very + messy with switches inside of it. +**/ +Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + + String src_pkg_name; + + EditorProgress ep("export", "Exporting for OSX", 104); + + if (p_debug) + src_pkg_name = p_preset->get("custom_package/debug"); + else + src_pkg_name = p_preset->get("custom_package/release"); + + if (src_pkg_name == "") { + String err; + src_pkg_name = find_export_template("osx.zip", &err); + if (src_pkg_name == "") { + EditorNode::add_io_error(err); + return ERR_FILE_NOT_FOUND; + } + } + + FileAccess *src_f = NULL; + zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + + ep.step("Creating app", 0); + + unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); + if (!src_pkg_zip) { + + EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name); + return ERR_FILE_NOT_FOUND; + } + + ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN); + int ret = unzGoToFirstFile(src_pkg_zip); + + String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + "."; + int bits_mode = p_preset->get("application/bits_mode"); + binary_to_use += String(bits_mode == 0 ? "fat" : bits_mode == 1 ? "64" : "32"); + + print_line("binary: " + binary_to_use); + String pkg_name; + if (p_preset->get("application/name") != "") + pkg_name = p_preset->get("application/name"); // app_name + else if (String(GlobalConfig::get_singleton()->get("application/name")) != "") + pkg_name = String(GlobalConfig::get_singleton()->get("application/name")); + else + pkg_name = "Unnamed"; + + /* Open our destination zip file */ + zlib_filefunc_def io2 = io; + FileAccess *dst_f = NULL; + io2.opaque = &dst_f; + zipFile dst_pkg_zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2); + + bool found_binary = false; + + while (ret == UNZ_OK) { + + //get filename + unz_file_info info; + char fname[16384]; + ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0); + + String file = fname; + + print_line("READ: " + file); + Vector<uint8_t> data; + data.resize(info.uncompressed_size); + + //read + unzOpenCurrentFile(src_pkg_zip); + unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size()); + unzCloseCurrentFile(src_pkg_zip); + + //write + + file = file.replace_first("osx_template.app/", ""); + + if (file == "Contents/Info.plist") { + print_line("parse plist"); + _fix_plist(p_preset, data, pkg_name); + } + + if (file.begins_with("Contents/MacOS/godot_")) { + if (file != "Contents/MacOS/" + binary_to_use) { + ret = unzGoToNextFile(src_pkg_zip); + continue; //ignore! + } + found_binary = true; + file = "Contents/MacOS/" + pkg_name; + } + + if (file == "Contents/Resources/icon.icns") { + //see if there is an icon + String iconpath; + if (p_preset->get("application/icon") != "") + iconpath = p_preset->get("application/icon"); + else + iconpath = GlobalConfig::get_singleton()->get("application/icon"); + print_line("icon? " + iconpath); + if (iconpath != "") { + Ref<Image> icon; + icon.instance(); + icon->load(iconpath); + if (!icon->empty()) { + print_line("loaded?"); + _make_icon(icon, data); + } + } + //bleh? + } if (data.size() > 0) { print_line("ADDING: " + file + " size: " + itos(data.size())); + /* add it to our zip file */ + file = pkg_name + ".app/" + file; + zip_fileinfo fi; fi.tmz_date.tm_hour = info.tmu_date.tm_hour; fi.tmz_date.tm_min = info.tmu_date.tm_min; @@ -304,7 +570,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p fi.internal_fa = info.internal_fa; fi.external_fa = info.external_fa; - int err = zipOpenNewFileInZip(dpkg, + int err = zipOpenNewFileInZip(dst_pkg_zip, file.utf8().get_data(), &fi, NULL, @@ -316,37 +582,37 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p Z_DEFAULT_COMPRESSION); print_line("OPEN ERR: " + itos(err)); - err = zipWriteInFileInZip(dpkg, data.ptr(), data.size()); + err = zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size()); print_line("WRITE ERR: " + itos(err)); - zipCloseFileInZip(dpkg); + zipCloseFileInZip(dst_pkg_zip); } - ret = unzGoToNextFile(pkg); + ret = unzGoToNextFile(src_pkg_zip); } if (!found_binary) { ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive."); - zipClose(dpkg, NULL); - unzClose(pkg); + zipClose(dst_pkg_zip, NULL); + unzClose(src_pkg_zip); return ERR_FILE_NOT_FOUND; } ep.step("Making PKG", 1); - String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/data.pck"; + String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/" + pkg_name + ".pck"; Error err = save_pack(p_preset, pack_path); if (err) { - zipClose(dpkg, NULL); - unzClose(pkg); + zipClose(dst_pkg_zip, NULL); + unzClose(src_pkg_zip); return err; } { //write datapack - zipOpenNewFileInZip(dpkg, - (pkg_name + ".app/Contents/Resources/data.pck").utf8().get_data(), + zipOpenNewFileInZip(dst_pkg_zip, + (pkg_name + ".app/Contents/Resources/" + pkg_name + ".pck").utf8().get_data(), NULL, NULL, 0, @@ -366,17 +632,18 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p int r = pf->get_buffer(buf, BSIZE); if (r <= 0) break; - zipWriteInFileInZip(dpkg, buf, r); + zipWriteInFileInZip(dst_pkg_zip, buf, r); } - zipCloseFileInZip(dpkg); + zipCloseFileInZip(dst_pkg_zip); memdelete(pf); } - zipClose(dpkg, NULL); - unzClose(pkg); + zipClose(dst_pkg_zip, NULL); + unzClose(src_pkg_zip); return OK; } +#endif bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { diff --git a/platform/server/detect.py b/platform/server/detect.py index 32f3c55135..2bb4b59e94 100644 --- a/platform/server/detect.py +++ b/platform/server/detect.py @@ -1,4 +1,3 @@ - import os import sys @@ -13,17 +12,16 @@ def get_name(): def can_build(): - if (os.name != "posix"): + if (os.name != "posix" or sys.platform == "darwin"): return False - return True # enabled + return True def get_opts(): return [ - ('use_llvm', 'Use llvm compiler', 'no'), - ('force_32_bits', 'Force 32 bits binary', 'no') + ('use_llvm', 'Use the LLVM compiler', 'no'), ] @@ -35,46 +33,59 @@ def get_flags(): def configure(env): - env.Append(CPPPATH=['#platform/server']) - if (env["use_llvm"] == "yes"): - env["CC"] = "clang" - env["CXX"] = "clang++" - env["LD"] = "clang++" - - is64 = sys.maxsize > 2**32 - - if (env["bits"] == "default"): - if (is64): - env["bits"] = "64" - else: - env["bits"] = "32" - - # if (env["tools"]=="no"): - # #no tools suffix - # env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX'] - # env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX'] + ## Build type if (env["target"] == "release"): - env.Append(CCFLAGS=['-O2', '-ffast-math', '-fomit-frame-pointer']) elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) elif (env["target"] == "debug"): - env.Append(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + ## Architecture + + is64 = sys.maxsize > 2**32 + if (env["bits"] == "default"): + env["bits"] = "64" if is64 else "32" + + ## Compiler configuration + + if (env["use_llvm"] == "yes"): + if ('clang++' not in env['CXX']): + env["CC"] = "clang" + env["CXX"] = "clang++" + env["LD"] = "clang++" + env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) + env.extra_suffix = ".llvm" + env.extra_suffix + + ## Dependencies - # Shared libraries, when requested + # FIXME: Check for existence of the libs before parsing their flags with pkg-config if (env['builtin_openssl'] == 'no'): + # Currently not compatible with OpenSSL 1.1.0+ + # https://github.com/godotengine/godot/issues/8624 + import subprocess + openssl_version = subprocess.check_output(['pkg-config', 'openssl', '--modversion']).strip('\n') + if (openssl_version >= "1.1.0"): + print("Error: Found system-installed OpenSSL %s, currently only supporting version 1.0.x." % openssl_version) + print("Aborting.. You can compile with 'builtin_openssl=yes' to use the bundled version.\n") + sys.exit(255) + env.ParseConfig('pkg-config openssl --cflags --libs') if (env['builtin_libwebp'] == 'no'): env.ParseConfig('pkg-config libwebp --cflags --libs') + # freetype depends on libpng and zlib, so bundling one of them while keeping others + # as shared libraries leads to weird issues + if (env['builtin_freetype'] == 'yes' or env['builtin_libpng'] == 'yes' or env['builtin_zlib'] == 'yes'): + env['builtin_freetype'] = 'yes' + env['builtin_libpng'] = 'yes' + env['builtin_zlib'] = 'yes' + if (env['builtin_freetype'] == 'no'): env.ParseConfig('pkg-config freetype2 --cflags --libs') @@ -109,11 +120,12 @@ def configure(env): if (env['builtin_libogg'] == 'no'): env.ParseConfig('pkg-config ogg --cflags --libs') + ## Flags - env.Append(CPPFLAGS=['-DSERVER_ENABLED', '-DUNIX_ENABLED']) - env.Append(LIBS=['pthread', 'z']) # TODO detect linux/BSD! + # Linkflags below this line should typically stay the last ones + if (env['builtin_zlib'] == 'no'): + env.ParseConfig('pkg-config zlib --cflags --libs') - if (env["CXX"] == "clang++"): - env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) - env["CC"] = "clang" - env["LD"] = "clang++" + env.Append(CPPPATH=['#platform/server']) + env.Append(CPPFLAGS=['-DSERVER_ENABLED', '-DUNIX_ENABLED']) + env.Append(LIBS=['pthread']) diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py index baff7f9788..ca469d0056 100644 --- a/platform/uwp/detect.py +++ b/platform/uwp/detect.py @@ -1,8 +1,7 @@ +import methods import os - -import sys import string -import methods +import sys def is_active(): @@ -26,7 +25,9 @@ def can_build(): def get_opts(): - return [] + + return [ + ] def get_flags(): @@ -39,16 +40,36 @@ def get_flags(): def configure(env): - if(env["bits"] != "default"): - print "Error: bits argument is disabled for MSVC" - print ("Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings)" - + " that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits argument (example: scons p=uwp) and SCons will attempt to detect what MSVC compiler" - + " will be executed and inform you.") + if (env["bits"] != "default"): + print("Error: bits argument is disabled for MSVC") + print(""" + Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console + (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits + argument (example: scons p=uwp) and SCons will attempt to detect what MSVC compiler will be executed and inform you. + """) sys.exit() - arch = "" - env['ENV'] = os.environ + ## Build type + + if (env["target"] == "release"): + env.Append(CPPFLAGS=['/O2', '/GL']) + env.Append(CPPFLAGS=['/MD']) + env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS', '/LTCG']) + + elif (env["target"] == "release_debug"): + env.Append(CCFLAGS=['/O2', '/Zi', '/DDEBUG_ENABLED']) + env.Append(CPPFLAGS=['/MD']) + env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) + + elif (env["target"] == "debug"): + env.Append(CCFLAGS=['/Zi', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED']) + env.Append(CPPFLAGS=['/MDd']) + env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) + env.Append(LINKFLAGS=['/DEBUG']) + + ## Compiler configuration + env['ENV'] = os.environ vc_base_path = os.environ['VCTOOLSINSTALLDIR'] if "VCTOOLSINSTALLDIR" in os.environ else os.environ['VCINSTALLDIR'] # ANGLE @@ -60,9 +81,12 @@ def configure(env): if os.path.isfile(str(os.getenv("ANGLE_SRC_PATH")) + "/winrt/10/src/angle.sln"): env["build_angle"] = True + ## Architecture + + arch = "" if os.getenv('Platform') == "ARM": - print "Compiled program architecture will be an ARM executable. (forcing bits=32)." + print("Compiled program architecture will be an ARM executable. (forcing bits=32).") arch = "arm" env["bits"] = "32" @@ -74,17 +98,16 @@ def configure(env): env.Append(LIBPATH=[angle_root + '/winrt/10/src/Release_ARM/lib']) else: - compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV']) if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"): env["bits"] = "64" - print "Compiled program architecture will be a x64 executable (forcing bits=64)." + print("Compiled program architecture will be a x64 executable (forcing bits=64).") elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"): env["bits"] = "32" - print "Compiled program architecture will be a x86 executable. (forcing bits=32)." + print("Compiled program architecture will be a x86 executable. (forcing bits=32).") else: - print "Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup." + print("Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup.") env["bits"] = "32" if (env["bits"] == "32"): @@ -106,48 +129,30 @@ def configure(env): env.Append(LIBPATH=[os.environ['VCINSTALLDIR'] + 'lib/store/amd64']) env.Append(LIBPATH=[angle_root + '/winrt/10/src/Release_x64/lib']) - env.Append(CPPPATH=['#platform/uwp', '#drivers/windows']) - env.Append(LINKFLAGS=['/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', '/WINMD', '/APPCONTAINER', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1', '/NODEFAULTLIB:"kernel32.lib"', '/NODEFAULTLIB:"ole32.lib"']) - env.Append(CPPFLAGS=['/D', '__WRL_NO_DEFAULT_LIB__', '/D', 'WIN32']) - - env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/store/references']) - env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/x86/store/references']) - - if (env["target"] == "release"): - - env.Append(CPPFLAGS=['/O2', '/GL']) - env.Append(CPPFLAGS=['/MD']) - env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS', '/LTCG']) + env["PROGSUFFIX"] = "." + arch + env["PROGSUFFIX"] + env["OBJSUFFIX"] = "." + arch + env["OBJSUFFIX"] + env["LIBSUFFIX"] = "." + arch + env["LIBSUFFIX"] - elif (env["target"] == "release_debug"): + ## Compile flags - env.Append(CCFLAGS=['/O2', '/Zi', '/DDEBUG_ENABLED']) - env.Append(CPPFLAGS=['/MD']) - env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) + env.Append(CPPPATH=['#platform/uwp', '#drivers/windows']) + env.Append(CCFLAGS=['/DUWP_ENABLED', '/DWINDOWS_ENABLED', '/DTYPED_METHOD_BIND']) + env.Append(CCFLAGS=['/DGLES2_ENABLED', '/DGL_GLEXT_PROTOTYPES', '/DEGL_EGLEXT_PROTOTYPES', '/DANGLE_ENABLED']) + winver = "0x0602" # Windows 8 is the minimum target for UWP build + env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver]) - elif (env["target"] == "debug"): + env.Append(CPPFLAGS=['/D', '__WRL_NO_DEFAULT_LIB__', '/D', 'WIN32']) - env.Append(CCFLAGS=['/Zi', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED']) - env.Append(CPPFLAGS=['/MDd']) - env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) - env.Append(LINKFLAGS=['/DEBUG']) + env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/store/references']) + env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/x86/store/references']) env.Append(CCFLAGS=string.split('/FS /MP /GS /wd"4453" /wd"28204" /wd"4291" /Zc:wchar_t /Gm- /fp:precise /D "_UNICODE" /D "UNICODE" /D "WINAPI_FAMILY=WINAPI_FAMILY_APP" /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo')) env.Append(CXXFLAGS=string.split('/ZW /FS')) env.Append(CCFLAGS=['/AI', vc_base_path + '\\vcpackages', '/AI', os.environ['WINDOWSSDKDIR'] + '\\References\\CommonConfiguration\\Neutral']) - env["PROGSUFFIX"] = "." + arch + env["PROGSUFFIX"] - env["OBJSUFFIX"] = "." + arch + env["OBJSUFFIX"] - env["LIBSUFFIX"] = "." + arch + env["LIBSUFFIX"] - - env.Append(CCFLAGS=['/DUWP_ENABLED']) - env.Append(CCFLAGS=['/DWINDOWS_ENABLED']) - env.Append(CCFLAGS=['/DTYPED_METHOD_BIND']) - - env.Append(CCFLAGS=['/DGLES2_ENABLED', '/DGL_GLEXT_PROTOTYPES', '/DEGL_EGLEXT_PROTOTYPES', '/DANGLE_ENABLED']) + ## Link flags - winver = "0x0602" # Windows 8 is the minimum target for UWP build - env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver]) + env.Append(LINKFLAGS=['/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', '/WINMD', '/APPCONTAINER', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1', '/NODEFAULTLIB:"kernel32.lib"', '/NODEFAULTLIB:"ole32.lib"']) LIBS = [ 'WindowsApp', @@ -164,8 +169,3 @@ def configure(env): env['BUILDERS']['Program'] = methods.precious_program env.Append(BUILDERS={'ANGLE': env.Builder(action=angle_build_cmd)}) - - 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={'HLSL9': env.Builder(action=methods.build_hlsl_dx9_headers, suffix='hlsl.h', src_suffix='.hlsl')}) - env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')}) diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 5e56c1db49..a2bc5a11ab 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -1,104 +1,7 @@ -# -# tested on | Windows native | Linux cross-compilation -# ----------------------------+-------------------+--------------------------- -# Visual C++ Build Tools 2015 | WORKS | n/a -# MSVS C++ 2010 Express | WORKS | n/a -# Mingw-w64 | WORKS | WORKS -# Mingw-w32 | WORKS | WORKS -# MinGW | WORKS | untested -# -##### -# Note about Visual C++ Build Tools : -# -# - Visual C++ Build Tools is the standalone MSVC compiler : -# http://landinghub.visualstudio.com/visual-cpp-build-tools -# -##### -# Notes about MSVS C++ : -# -# - MSVC2010-Express compiles to 32bits only. -# -##### -# Notes about Mingw-w64 and Mingw-w32 under Windows : -# -# - both can be installed using the official installer : -# http://mingw-w64.sourceforge.net/download.php#mingw-builds -# -# - if you want to compile both 32bits and 64bits, don't forget to -# run the installer twice to install them both. -# -# - install them into a path that does not contain spaces -# ( example : "C:/Mingw-w32", "C:/Mingw-w64" ) -# -# - if you want to compile faster using the "-j" option, don't forget -# to install the appropriate version of the Pywin32 python extension -# available from : http://sourceforge.net/projects/pywin32/files/ -# -# - before running scons, you must add into the environment path -# the path to the "/bin" directory of the Mingw version you want -# to use : -# -# set PATH=C:/Mingw-w32/bin;%PATH% -# -# - then, scons should be able to detect gcc. -# - Mingw-w32 only compiles 32bits. -# - Mingw-w64 only compiles 64bits. -# -# - it is possible to add them both at the same time into the PATH env, -# if you also define the MINGW32_PREFIX and MINGW64_PREFIX environment -# variables. -# For instance, you could store that set of commands into a .bat script -# that you would run just before scons : -# -# set PATH=C:\mingw-w32\bin;%PATH% -# set PATH=C:\mingw-w64\bin;%PATH% -# set MINGW32_PREFIX=C:\mingw-w32\bin\ -# set MINGW64_PREFIX=C:\mingw-w64\bin\ -# -##### -# Notes about Mingw, Mingw-w64 and Mingw-w32 under Linux : -# -# - default toolchain prefixes are : -# "i586-mingw32msvc-" for MinGW -# "i686-w64-mingw32-" for Mingw-w32 -# "x86_64-w64-mingw32-" for Mingw-w64 -# -# - if both MinGW and Mingw-w32 are installed on your system -# Mingw-w32 should take the priority over MinGW. -# -# - it is possible to manually override prefixes by defining -# the MINGW32_PREFIX and MINGW64_PREFIX environment variables. -# -##### -# Notes about Mingw under Windows : -# -# - this is the MinGW version from http://mingw.org/ -# - install it into a path that does not contain spaces -# ( example : "C:/MinGW" ) -# - several DirectX headers might be missing. You can copy them into -# the C:/MinGW/include" directory from this page : -# https://code.google.com/p/mingw-lib/source/browse/trunk/working/avcodec_to_widget_5/directx_include/ -# - before running scons, add the path to the "/bin" directory : -# set PATH=C:/MinGW/bin;%PATH% -# - scons should be able to detect gcc. -# - -##### -# TODO : -# -# - finish to cleanup this script to remove all the remains of previous hacks and workarounds -# - make it work with the Windows7 SDK that is supposed to enable 64bits compilation for MSVC2010-Express -# - confirm it works well with other Visual Studio versions. -# - update the wiki about the pywin32 extension required for the "-j" option under Windows. -# - update the wiki to document MINGW32_PREFIX and MINGW64_PREFIX -# - +import methods import os - import sys -import methods - def is_active(): return True @@ -115,7 +18,7 @@ def can_build(): if (os.getenv("VCINSTALLDIR")): return True else: - print("\nMSVC not detected, attempting Mingw.") + print("\nMSVC not detected, attempting MinGW.") mingw32 = "" mingw64 = "" if (os.getenv("MINGW32_PREFIX")): @@ -126,7 +29,7 @@ def can_build(): test = "gcc --version > NUL 2>&1" if os.system(test) != 0 and os.system(mingw32 + test) != 0 and os.system(mingw64 + test) != 0: print("- could not detect gcc.") - print("Please, make sure a path to a Mingw /bin directory is accessible into the environment PATH.\n") + print("Please, make sure a path to a MinGW /bin directory is accessible into the environment PATH.\n") return False else: print("- gcc detected.") @@ -172,8 +75,8 @@ def get_opts(): mingw64 = os.getenv("MINGW64_PREFIX") return [ - ('mingw_prefix', 'Mingw Prefix', mingw32), - ('mingw_prefix_64', 'Mingw Prefix 64 bits', mingw64), + ('mingw_prefix', 'MinGW Prefix', mingw32), + ('mingw_prefix_64', 'MinGW Prefix 64 bits', mingw64), ] @@ -211,55 +114,86 @@ def configure(env): # Targeted Windows version: Vista (and later) winver = "0x0600" # Windows Vista is the minimum target for windows builds - env['is_mingw'] = False - if (os.name == "nt" and os.getenv("VCINSTALLDIR")): - # build using visual studio + if (os.name == "nt" and os.getenv("VCINSTALLDIR")): # MSVC + env['ENV']['TMP'] = os.environ['TMP'] - env.Append(CPPPATH=['#platform/windows/include']) - env.Append(LIBPATH=['#platform/windows/lib']) - env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver]) - if (env["target"] == "release"): + ## Build type + if (env["target"] == "release"): env.Append(CCFLAGS=['/O2']) env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS']) env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup']) elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['/O2', '/DDEBUG_ENABLED']) env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) - elif (env["target"] == "debug_release"): + elif (env["target"] == "debug_release"): env.Append(CCFLAGS=['/Z7', '/Od']) env.Append(LINKFLAGS=['/DEBUG']) env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS']) env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup']) elif (env["target"] == "debug"): - env.Append(CCFLAGS=['/Z7', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED', '/DD3D_DEBUG_INFO', '/Od']) env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) env.Append(LINKFLAGS=['/DEBUG']) - env.Append(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo']) + ## Architecture + + # Note: this detection/override code from here onward should be here instead of in SConstruct because it's platform and compiler specific (MSVC/Windows) + if (env["bits"] != "default"): + print("Error: bits argument is disabled for MSVC") + print(""" + Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console + (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits + argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you. + """) + sys.exit() + + # Forcing bits argument because MSVC does not have a flag to set this through SCons... it's different compilers (cl.exe's) called from the proper command prompt + # that decide the architecture that is build for. Scons can only detect the os.getenviron (because vsvarsall.bat sets a lot of stuff for cl.exe to work with) + env["bits"] = "32" + env["x86_libtheora_opt_vc"] = True + + ## Compiler configuration + + env['ENV'] = os.environ + # This detection function needs the tools env (that is env['ENV'], not SCons's env), and that is why it's this far bellow in the code + compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV']) + + print("Detected MSVC compiler: " + compiler_version_str) + # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writting)... vc compiler for 64bit can not compile _asm + if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"): + env["bits"] = "64" + env["x86_libtheora_opt_vc"] = False + print("Compiled program architecture will be a 64 bit executable (forcing bits=64).") + elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"): + print("Compiled program architecture will be a 32 bit executable. (forcing bits=32).") + else: + print("Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup.") + + ## Compile flags + + env.Append(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo']) env.Append(CXXFLAGS=['/TP']) env.Append(CPPFLAGS=['/DMSVC', '/GR', ]) env.Append(CCFLAGS=['/I' + os.getenv("WindowsSdkDir") + "/Include"]) + env.Append(CCFLAGS=['/DWINDOWS_ENABLED']) + env.Append(CCFLAGS=['/DOPENGL_ENABLED']) env.Append(CCFLAGS=['/DRTAUDIO_ENABLED']) - env.Append(CCFLAGS=['/DWIN32']) env.Append(CCFLAGS=['/DTYPED_METHOD_BIND']) + env.Append(CCFLAGS=['/DWIN32']) + env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver]) + if env["bits"] == "64": + env.Append(CCFLAGS=['/D_WIN64']) - env.Append(CCFLAGS=['/DOPENGL_ENABLED']) LIBS = ['winmm', 'opengl32', 'dsound', 'kernel32', 'ole32', 'oleaut32', 'user32', 'gdi32', 'IPHLPAPI', 'Shlwapi', 'wsock32', 'Ws2_32', 'shell32', 'advapi32', 'dinput8', 'dxguid'] env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS]) env.Append(LIBPATH=[os.getenv("WindowsSdkDir") + "/Lib"]) - if (os.getenv("DXSDK_DIR")): - DIRECTX_PATH = os.getenv("DXSDK_DIR") - else: - DIRECTX_PATH = "C:/Program Files/Microsoft DirectX SDK (March 2009)" if (os.getenv("VCINSTALLDIR")): VC_PATH = os.getenv("VCINSTALLDIR") @@ -268,51 +202,37 @@ def configure(env): env.Append(CCFLAGS=["/I" + p for p in os.getenv("INCLUDE").split(";")]) env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")]) - env.Append(CCFLAGS=["/I" + DIRECTX_PATH + "/Include"]) - env.Append(LIBPATH=[DIRECTX_PATH + "/Lib/x86"]) - env['ENV'] = os.environ - - # This detection function needs the tools env (that is env['ENV'], not SCons's env), and that is why it's this far bellow in the code - compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV']) - - # Note: this detection/override code from here onward should be here instead of in SConstruct because it's platform and compiler specific (MSVC/Windows) - if(env["bits"] != "default"): - print "Error: bits argument is disabled for MSVC" - print ("Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings)" - + " that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler" - + " will be executed and inform you.") - sys.exit() - - # Forcing bits argument because MSVC does not have a flag to set this through SCons... it's different compilers (cl.exe's) called from the proper command prompt - # that decide the architecture that is build for. Scons can only detect the os.getenviron (because vsvarsall.bat sets a lot of stuff for cl.exe to work with) - env["bits"] = "32" - env["x86_libtheora_opt_vc"] = True - - print "Detected MSVC compiler: " + compiler_version_str - # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writting)... vc compiler for 64bit can not compile _asm - if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"): - env["bits"] = "64" - env["x86_libtheora_opt_vc"] = False - print "Compiled program architecture will be a 64 bit executable (forcing bits=64)." - elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"): - print "Compiled program architecture will be a 32 bit executable. (forcing bits=32)." - else: - print "Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup." - if env["bits"] == "64": - env.Append(CCFLAGS=['/D_WIN64']) # Incremental linking fix env['BUILDERS']['ProgramOriginal'] = env['BUILDERS']['Program'] env['BUILDERS']['Program'] = methods.precious_program - else: + else: # MinGW # Workaround for MinGW. See: # http://www.scons.org/wiki/LongCmdLinesOnWin32 env.use_windows_spawn_fix() - # build using mingw - env.Append(CCFLAGS=['-DWINVER=%s' % winver, '-D_WIN32_WINNT=%s' % winver]) + ## Build type + + if (env["target"] == "release"): + env.Append(CCFLAGS=['-msse2']) + + if (env["bits"] == "64"): + env.Append(CCFLAGS=['-O3']) + else: + env.Append(CCFLAGS=['-O2']) + + env.Append(LINKFLAGS=['-Wl,--subsystem,windows']) + + elif (env["target"] == "release_debug"): + env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + + elif (env["target"] == "debug"): + env.Append(CCFLAGS=['-g', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + + ## Compiler configuration + if (os.name == "nt"): env['ENV']['TMP'] = os.environ['TMP'] # way to go scons, you can be so stupid sometimes else: @@ -339,30 +259,6 @@ def configure(env): else: nulstr = ">nul" - # if os.system(mingw_prefix+"gcc --version"+nulstr)!=0: - # #not really super consistent but.. - # print("Can't find Windows compiler: "+mingw_prefix) - # sys.exit(255) - - if (env["target"] == "release"): - - env.Append(CCFLAGS=['-msse2']) - - if (env["bits"] == "64"): - env.Append(CCFLAGS=['-O3']) - else: - env.Append(CCFLAGS=['-O2']) - - env.Append(LINKFLAGS=['-Wl,--subsystem,windows']) - - elif (env["target"] == "release_debug"): - - env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) - - elif (env["target"] == "debug"): - - env.Append(CCFLAGS=['-g', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) - env["CC"] = mingw_prefix + "gcc" env['AS'] = mingw_prefix + "as" env['CXX'] = mingw_prefix + "g++" @@ -371,29 +267,15 @@ def configure(env): env['LD'] = mingw_prefix + "g++" env["x86_libtheora_opt_gcc"] = True - #env['CC'] = "winegcc" - #env['CXX'] = "wineg++" + ## Compile flags env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows']) - env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED']) env.Append(CCFLAGS=['-DOPENGL_ENABLED']) + env.Append(CCFLAGS=['-DRTAUDIO_ENABLED']) + env.Append(CCFLAGS=['-DWINVER=%s' % winver, '-D_WIN32_WINNT=%s' % winver]) env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid']) - # if (env["bits"]=="32"): - # env.Append(LIBS=['gcc_s']) - # #--with-arch=i686 - # env.Append(CPPFLAGS=['-march=i686']) - # env.Append(LINKFLAGS=['-march=i686']) - - #'d3dx9d' env.Append(CPPFLAGS=['-DMINGW_ENABLED']) - # env.Append(LINKFLAGS=['-g']) # resrc - env['is_mingw'] = True env.Append(BUILDERS={'RES': env.Builder(action=build_res_file, suffix='.o', src_suffix='.rc')}) - - 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={'HLSL9': env.Builder(action=methods.build_hlsl_dx9_headers, suffix='hlsl.h', src_suffix='.hlsl')}) - env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')}) diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 0ba0f68393..79778136ad 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -1,7 +1,6 @@ - import os -import sys import platform +import sys def is_active(): @@ -14,15 +13,12 @@ def get_name(): def can_build(): - if (os.name != "posix"): + if (os.name != "posix" or sys.platform == "darwin"): return False - if sys.platform == "darwin": - return False # no x11 on mac for now - - errorval = os.system("pkg-config --version > /dev/null") - - if (errorval): + # Check the minimal dependencies + x11_error = os.system("pkg-config --version > /dev/null") + if (x11_error): print("pkg-config not found.. x11 disabled.") return False @@ -31,11 +27,6 @@ def can_build(): print("X11 not found.. x11 disabled.") return False - ssl_error = os.system("pkg-config openssl --modversion > /dev/null ") - if (ssl_error): - print("OpenSSL not found.. x11 disabled.") - return False - x11_error = os.system("pkg-config xcursor --modversion > /dev/null ") if (x11_error): print("xcursor not found.. x11 disabled.") @@ -51,18 +42,18 @@ def can_build(): print("xrandr not found.. x11 disabled.") return False - return True # X11 enabled + return True def get_opts(): return [ - ('use_llvm', 'Use llvm compiler', 'no'), - ('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_llvm', 'Use the LLVM compiler', 'no'), + ('use_static_cpp', 'Link stdc++ statically', 'no'), + ('use_sanitizer', 'Use LLVM compiler address sanitizer', 'no'), + ('use_leak_sanitizer', 'Use LLVM compiler memory leaks sanitizer (implies use_sanitizer)', 'no'), ('use_lto', 'Use link time optimization', 'no'), - ('pulseaudio', 'Detect & Use pulseaudio', 'yes'), + ('pulseaudio', 'Detect & use pulseaudio', 'yes'), ('udev', 'Use udev for gamepad connection callbacks', 'no'), ('debug_release', 'Add debug symbols to release version', 'no'), ] @@ -80,66 +71,62 @@ def get_flags(): def configure(env): - is64 = sys.maxsize > 2**32 + ## Build type + + if (env["target"] == "release"): + env.Prepend(CCFLAGS=['-Ofast']) + if (env["debug_release"] == "yes"): + env.Prepend(CCFLAGS=['-g2']) + + elif (env["target"] == "release_debug"): + env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) + if (env["debug_release"] == "yes"): + env.Prepend(CCFLAGS=['-g2']) + + elif (env["target"] == "debug"): + env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + + ## Architecture + is64 = sys.maxsize > 2**32 if (env["bits"] == "default"): - if (is64): - env["bits"] = "64" - else: - env["bits"] = "32" + env["bits"] = "64" if is64 else "32" + + ## Compiler configuration - env.Append(CPPPATH=['#platform/x11']) if (env["use_llvm"] == "yes"): - if 'clang++' not in env['CXX']: + if ('clang++' not in env['CXX']): env["CC"] = "clang" env["CXX"] = "clang++" env["LD"] = "clang++" env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) - env.extra_suffix = ".llvm" - - if (env["use_sanitizer"] == "yes"): - env.Append(CCFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer']) - env.Append(LINKFLAGS=['-fsanitize=address']) - env.extra_suffix += "s" + env.extra_suffix = ".llvm" + env.extra_suffix - if (env["use_leak_sanitizer"] == "yes"): + # leak sanitizer requires (address) sanitizer + if (env["use_sanitizer"] == "yes" or env["use_leak_sanitizer"] == "yes"): env.Append(CCFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer']) env.Append(LINKFLAGS=['-fsanitize=address']) env.extra_suffix += "s" - - # if (env["tools"]=="no"): - # #no tools suffix - # env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX'] - # env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX'] + if (env["use_leak_sanitizer"] == "yes"): + env.Append(CCFLAGS=['-fsanitize=leak']) + env.Append(LINKFLAGS=['-fsanitize=leak']) 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.Prepend(CCFLAGS=['-g2']) - - elif (env["target"] == "release_debug"): - - env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) - if (env["debug_release"] == "yes"): - env.Prepend(CCFLAGS=['-g2']) - - elif (env["target"] == "debug"): - - env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + ## Dependencies env.ParseConfig('pkg-config x11 --cflags --libs') - env.ParseConfig('pkg-config xinerama --cflags --libs') env.ParseConfig('pkg-config xcursor --cflags --libs') + env.ParseConfig('pkg-config xinerama --cflags --libs') env.ParseConfig('pkg-config xrandr --cflags --libs') + # FIXME: Check for existence of the libs before parsing their flags with pkg-config + if (env['builtin_openssl'] == 'no'): # Currently not compatible with OpenSSL 1.1.0+ # https://github.com/godotengine/godot/issues/8624 @@ -196,47 +183,51 @@ def configure(env): if (env['builtin_libogg'] == 'no'): env.ParseConfig('pkg-config ogg --cflags --libs') - env.Append(CPPFLAGS=['-DOPENGL_ENABLED']) + if (env['builtin_libtheora'] != 'no'): + list_of_x86 = ['x86_64', 'x86', 'i386', 'i586'] + if any(platform.machine() in s for s in list_of_x86): + env["x86_libtheora_opt_gcc"] = True + + ## Flags - if os.system("pkg-config --exists alsa") == 0: + if (os.system("pkg-config --exists alsa") == 0): # 0 means found print("Enabling ALSA") env.Append(CPPFLAGS=["-DALSA_ENABLED"]) env.ParseConfig('pkg-config alsa --cflags --libs') else: print("ALSA libraries not found, disabling driver") - if (platform.system() == "Linux"): - env.Append(CPPFLAGS=["-DJOYDEV_ENABLED"]) - if (env["udev"] == "yes"): - # pkg-config returns 0 when the lib exists... - found_udev = not os.system("pkg-config --exists libudev") - - if (found_udev): - print("Enabling udev support") - env.Append(CPPFLAGS=["-DUDEV_ENABLED"]) - env.ParseConfig('pkg-config libudev --cflags --libs') - else: - print("libudev development libraries not found, disabling udev support") - if (env["pulseaudio"] == "yes"): - if not os.system("pkg-config --exists libpulse-simple"): + if (os.system("pkg-config --exists libpulse-simple") == 0): # 0 means found print("Enabling PulseAudio") env.Append(CPPFLAGS=["-DPULSEAUDIO_ENABLED"]) env.ParseConfig('pkg-config --cflags --libs libpulse-simple') else: print("PulseAudio development libraries not found, disabling driver") + if (platform.system() == "Linux"): + env.Append(CPPFLAGS=["-DJOYDEV_ENABLED"]) + + if (env["udev"] == "yes"): + if (os.system("pkg-config --exists libudev") == 0): # 0 means found + print("Enabling udev support") + env.Append(CPPFLAGS=["-DUDEV_ENABLED"]) + env.ParseConfig('pkg-config libudev --cflags --libs') + else: + print("libudev development libraries not found, disabling udev support") + + # Linkflags below this line should typically stay the last ones if (env['builtin_zlib'] == 'no'): env.ParseConfig('pkg-config zlib --cflags --libs') - env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) + env.Append(CPPPATH=['#platform/x11']) + env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) env.Append(LIBS=['GL', 'pthread']) if (platform.system() == "Linux"): env.Append(LIBS=['dl']) - # env.Append(CPPFLAGS=['-DMPC_FIXED_POINT']) - # host compiler is default.. + ## Cross-compilation if (is64 and env["bits"] == "32"): env.Append(CPPFLAGS=['-m32']) @@ -245,17 +236,5 @@ def configure(env): env.Append(CPPFLAGS=['-m64']) env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu']) - import methods - - # FIXME: Commented out when moving to gles3 - #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') } ) - if (env["use_static_cpp"] == "yes"): env.Append(LINKFLAGS=['-static-libstdc++']) - - list_of_x86 = ['x86_64', 'x86', 'i386', 'i586'] - if any(platform.machine() in s for s in list_of_x86): - env["x86_libtheora_opt_gcc"] = True diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 4a80aba355..68a3166aa7 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -609,6 +609,27 @@ void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width, p_antialiased); } +void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width, bool p_antialiased) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + Vector<Color> colors; + colors.push_back(p_color); + VisualServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width, p_antialiased); +} + +void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + VisualServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased); +} void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled) { if (!drawing) { @@ -955,6 +976,8 @@ void CanvasItem::_bind_methods() { //ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform); ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled"), &CanvasItem::draw_rect, DEFVAL(true)); ClassDB::bind_method(D_METHOD("draw_circle", "pos", "radius", "color"), &CanvasItem::draw_circle); ClassDB::bind_method(D_METHOD("draw_texture", "texture:Texture", "pos", "modulate", "normal_map:Texture"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant())); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 06130e3252..27842727ac 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -242,6 +242,8 @@ public: /* DRAWING API */ void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); + void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); + void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true); void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color); void draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture> &p_normal_map = Ref<Texture>()); diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index c5c274e225..0821b00dd9 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -204,10 +204,10 @@ int CollisionObject2D::shape_owner_get_shape_count(uint32_t p_owner) const { return shapes[p_owner].shapes.size(); } -Ref<Shape> CollisionObject2D::shape_owner_get_shape(uint32_t p_owner, int p_shape) const { +Ref<Shape2D> CollisionObject2D::shape_owner_get_shape(uint32_t p_owner, int p_shape) const { - ERR_FAIL_COND_V(!shapes.has(p_owner), Ref<Shape>()); - ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), Ref<Shape>()); + ERR_FAIL_COND_V(!shapes.has(p_owner), Ref<Shape2D>()); + ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), Ref<Shape2D>()); return shapes[p_owner].shapes[p_shape].shape; } diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index deffe8a002..3580d3d942 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -94,7 +94,7 @@ public: void shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape); int shape_owner_get_shape_count(uint32_t p_owner) const; - Ref<Shape> shape_owner_get_shape(uint32_t p_owner, int p_shape) const; + Ref<Shape2D> shape_owner_get_shape(uint32_t p_owner, int p_shape) const; int shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const; void shape_owner_remove_shape(uint32_t p_owner, int p_shape); diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 6fe1dd73fe..bd6ab99801 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -319,7 +319,7 @@ void Node2D::set_global_scale(const Size2 &p_scale) { CanvasItem *pi = get_parent_item(); if (pi) { const Size2 parent_global_scale = pi->get_global_transform().get_scale(); - set_scale(p_scale - parent_global_scale); + set_scale(p_scale / parent_global_scale); } else { set_scale(p_scale); } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 57e25ec609..9d70b75027 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -461,16 +461,18 @@ void TileMap::_update_dirty_quadrants() { Transform2D xform; xform.set_origin(offset.floor()); - _fix_cell_transform(xform, c, shapes[i].shape_offset + center_ofs, s); + _fix_cell_transform(xform, c, center_ofs, s); + + xform *= shapes[i].shape_transform; if (debug_canvas_item.is_valid()) { vs->canvas_item_add_set_transform(debug_canvas_item, xform); shape->draw(debug_canvas_item, debug_collision_color); } ps->body_add_shape(q.body, shape->get_rid(), xform); - shape_idx++; - ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[i].one_way_collision); ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y)); + ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[i].one_way_collision); + shape_idx++; } } diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index e755b1480b..14886f4b7a 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -32,6 +32,7 @@ #include "body_shape.h" #include "core_string_names.h" #include "physics_body.h" +#include "scene/resources/material.h" #include "scene/scene_string_names.h" #include "skeleton.h" bool MeshInstance::_set(const StringName &p_name, const Variant &p_value) { @@ -274,6 +275,80 @@ void MeshInstance::_mesh_changed() { materials.resize(mesh->get_surface_count()); } +void MeshInstance::create_debug_tagents() { + + Vector<Vector3> lines; + Vector<Color> colors; + + Ref<Mesh> mesh = get_mesh(); + if (!mesh.is_valid()) + return; + + for (int i = 0; i < mesh->get_surface_count(); i++) { + Array arrays = mesh->surface_get_arrays(i); + Vector<Vector3> verts = arrays[Mesh::ARRAY_VERTEX]; + Vector<Vector3> norms = arrays[Mesh::ARRAY_NORMAL]; + if (norms.size() == 0) + continue; + Vector<float> tangents = arrays[Mesh::ARRAY_TANGENT]; + if (tangents.size() == 0) + continue; + + for (int j = 0; j < verts.size(); j++) { + Vector3 v = verts[j]; + Vector3 n = norms[j]; + Vector3 t = Vector3(tangents[j * 4 + 0], tangents[j * 4 + 1], tangents[j * 4 + 2]); + Vector3 b = (n.cross(t)).normalized() * tangents[j * 4 + 3]; + + lines.push_back(v); //normal + colors.push_back(Color(0, 0, 1)); //color + lines.push_back(v + n * 0.04); //normal + colors.push_back(Color(0, 0, 1)); //color + + lines.push_back(v); //tangent + colors.push_back(Color(1, 0, 0)); //color + lines.push_back(v + t * 0.04); //tangent + colors.push_back(Color(1, 0, 0)); //color + + lines.push_back(v); //binormal + colors.push_back(Color(0, 1, 0)); //color + lines.push_back(v + b * 0.04); //binormal + colors.push_back(Color(0, 1, 0)); //color + } + } + + if (lines.size()) { + + Ref<SpatialMaterial> sm; + sm.instance(); + + sm->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + sm->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + sm->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + + Ref<ArrayMesh> am; + am.instance(); + Array a; + a.resize(Mesh::ARRAY_MAX); + a[Mesh::ARRAY_VERTEX] = lines; + a[Mesh::ARRAY_COLOR] = colors; + + am->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a); + am->surface_set_material(0, sm); + + MeshInstance *mi = memnew(MeshInstance); + mi->set_mesh(am); + mi->set_name("DebugTangents"); + add_child(mi); + if (get_parent()) { + if (get_parent() == get_tree()->get_edited_scene_root()) + mi->set_owner(get_parent()); + else + mi->set_owner(get_parent()->get_owner()); + } + } +} + void MeshInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("set_mesh", "mesh:Mesh"), &MeshInstance::set_mesh); @@ -281,12 +356,18 @@ void MeshInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path:NodePath"), &MeshInstance::set_skeleton_path); ClassDB::bind_method(D_METHOD("get_skeleton_path:NodePath"), &MeshInstance::get_skeleton_path); + ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material:Material"), &MeshInstance::set_surface_material); + ClassDB::bind_method(D_METHOD("get_surface_material:Material", "surface"), &MeshInstance::get_surface_material); + ClassDB::bind_method(D_METHOD("create_trimesh_collision"), &MeshInstance::create_trimesh_collision); ClassDB::set_method_flags("MeshInstance", "create_trimesh_collision", METHOD_FLAGS_DEFAULT); ClassDB::bind_method(D_METHOD("create_convex_collision"), &MeshInstance::create_convex_collision); ClassDB::set_method_flags("MeshInstance", "create_convex_collision", METHOD_FLAGS_DEFAULT); ClassDB::bind_method(D_METHOD("_mesh_changed"), &MeshInstance::_mesh_changed); + ClassDB::bind_method(D_METHOD("create_debug_tagents"), &MeshInstance::create_debug_tagents); + ClassDB::set_method_flags("MeshInstance", "create_debug_tagents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton"), "set_skeleton_path", "get_skeleton_path"); } diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h index c11c52b76d..be328084af 100644 --- a/scene/3d/mesh_instance.h +++ b/scene/3d/mesh_instance.h @@ -83,6 +83,8 @@ public: Node *create_convex_collision_node(); void create_convex_collision(); + void create_debug_tagents(); + virtual Rect3 get_aabb() const; virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 82f6f665db..4c93bcfb5e 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -149,8 +149,8 @@ Ref<Mesh> NavigationMesh::get_debug_mesh() { tw[tidx++] = f.vertex[j]; _EdgeKey ek; - ek.from = f.vertex[j].snapped(CMP_EPSILON); - ek.to = f.vertex[(j + 1) % 3].snapped(CMP_EPSILON); + ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); + ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); if (ek.from < ek.to) SWAP(ek.from, ek.to); diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 3debbf02c3..20c2cc1eb5 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -541,10 +541,7 @@ void Spatial::show() { if (!is_inside_tree()) return; - if (!data.parent || is_visible_in_tree()) { - - _propagate_visibility_changed(); - } + _propagate_visibility_changed(); } void Spatial::hide() { @@ -552,14 +549,14 @@ void Spatial::hide() { if (!data.visible) return; - bool was_visible = is_visible_in_tree(); data.visible = false; - if (!data.parent || was_visible) { + if (!is_inside_tree()) + return; - _propagate_visibility_changed(); - } + _propagate_visibility_changed(); } + bool Spatial::is_visible_in_tree() const { const Spatial *s = this; diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 8d085d5399..9d45b6e70a 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -568,7 +568,7 @@ static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, Vector2 start, Vector2 co return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3; } -void GraphEdit::_bake_segment2d(CanvasItem *p_where, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const { +void GraphEdit::_bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const { float mp = p_begin + (p_end - p_begin) * 0.5; Vector2 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b); @@ -581,11 +581,12 @@ void GraphEdit::_bake_segment2d(CanvasItem *p_where, float p_begin, float p_end, if (p_depth >= p_min_depth && (dp < p_tol || p_depth >= p_max_depth)) { - p_where->draw_line(beg, end, p_color.linear_interpolate(p_to_color, mp), 2, true); + points.push_back((beg + end) * 0.5); + colors.push_back(p_color.linear_interpolate(p_to_color, mp)); lines++; } else { - _bake_segment2d(p_where, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines); - _bake_segment2d(p_where, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines); + _bake_segment2d(points, colors, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines); + _bake_segment2d(points, colors, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines); } } @@ -609,7 +610,16 @@ void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 c2 = Vector2(-cp_offset * zoom, 0); int lines = 0; - _bake_segment2d(p_where, 0, 1, p_from, c1, p_to, c2, 0, 3, 9, 8, p_color, p_to_color, lines); + + Vector<Point2> points; + Vector<Color> colors; + points.push_back(p_from); + colors.push_back(p_color); + _bake_segment2d(points, colors, 0, 1, p_from, c1, p_to, c2, 0, 3, 9, 8, p_color, p_to_color, lines); + points.push_back(p_to); + colors.push_back(p_to_color); + + p_where->draw_polyline_colors(points, colors, 2, true); #else diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index 22d053d312..e908829d5f 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -110,7 +110,7 @@ private: bool awaiting_scroll_offset_update; List<Connection> connections; - void _bake_segment2d(CanvasItem *p_where, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const; + void _bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const; void _draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color); diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 31236fa277..e3dad08809 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -131,7 +131,12 @@ void SplitContainer::_resort() { if (ratiomode) { - middle_sep = ms_first[axis] + available / 2; + int first_ratio = first->get_stretch_ratio(); + int second_ratio = second->get_stretch_ratio(); + + float ratio = float(first_ratio) / (first_ratio + second_ratio); + + middle_sep = ms_first[axis] + available * ratio; } else if (expand_first_mode) { @@ -144,12 +149,17 @@ void SplitContainer::_resort() { } else if (ratiomode) { - if (expand_ofs < -(available / 2)) - expand_ofs = -(available / 2); - else if (expand_ofs > (available / 2)) - expand_ofs = (available / 2); + int first_ratio = first->get_stretch_ratio(); + int second_ratio = second->get_stretch_ratio(); + + float ratio = float(first_ratio) / (first_ratio + second_ratio); + + if (expand_ofs < -(available * ratio)) + expand_ofs = -(available * ratio); + else if (expand_ofs > (available * (1.0 - ratio))) + expand_ofs = (available * (1.0 - ratio)); - middle_sep = ms_first[axis] + available / 2 + expand_ofs; + middle_sep = ms_first[axis] + available * ratio + expand_ofs; } else if (expand_first_mode) { diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 0c65c44392..61e563143c 100755 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -37,7 +37,6 @@ #include "viewport.h" VARIANT_ENUM_CAST(Node::PauseMode); -VARIANT_ENUM_CAST(Node::NetworkMode); VARIANT_ENUM_CAST(Node::RPCMode); void Node::_notification(int p_notification) { @@ -77,16 +76,6 @@ void Node::_notification(int p_notification) { data.pause_owner = this; } - if (data.network_mode == NETWORK_MODE_INHERIT) { - - if (data.parent) - data.network_owner = data.parent->data.network_owner; - else - data.network_owner = NULL; - } else { - data.network_owner = this; - } - if (data.input) add_to_group("_vp_input" + itos(get_viewport()->get_instance_ID())); if (data.unhandled_input) @@ -108,7 +97,6 @@ void Node::_notification(int p_notification) { remove_from_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_ID())); data.pause_owner = NULL; - data.network_owner = NULL; if (data.path_cache) { memdelete(data.path_cache); data.path_cache = NULL; @@ -472,69 +460,28 @@ void Node::_propagate_pause_owner(Node *p_owner) { } } -void Node::set_network_mode(NetworkMode p_mode) { +void Node::set_network_master(int p_peer_id, bool p_recursive) { - if (data.network_mode == p_mode) - return; + data.network_master = p_peer_id; - bool prev_inherits = data.network_mode == NETWORK_MODE_INHERIT; - data.network_mode = p_mode; - if (!is_inside_tree()) - return; //pointless - if ((data.network_mode == NETWORK_MODE_INHERIT) == prev_inherits) - return; ///nothing changed - - Node *owner = NULL; - - if (data.network_mode == NETWORK_MODE_INHERIT) { + if (p_recursive) { + for (int i = 0; i < data.children.size(); i++) { - if (data.parent) - owner = data.parent->data.network_owner; - } else { - owner = this; + data.children[i]->set_network_master(p_peer_id, true); + } } - - _propagate_network_owner(owner); } -Node::NetworkMode Node::get_network_mode() const { +int Node::get_network_master() const { - return data.network_mode; + return data.network_master; } bool Node::is_network_master() const { ERR_FAIL_COND_V(!is_inside_tree(), false); - switch (data.network_mode) { - case NETWORK_MODE_INHERIT: { - - if (data.network_owner) - return data.network_owner->is_network_master(); - else - return get_tree()->is_network_server(); - } break; - case NETWORK_MODE_MASTER: { - - return true; - } break; - case NETWORK_MODE_SLAVE: { - return false; - } break; - } - - return false; -} - -void Node::_propagate_network_owner(Node *p_owner) { - - if (data.network_mode != NETWORK_MODE_INHERIT) - return; - data.network_owner = p_owner; - for (int i = 0; i < data.children.size(); i++) { - - data.children[i]->_propagate_network_owner(p_owner); - } + return get_tree()->get_network_unique_id() == data.network_master; } /***** RPC CONFIG ********/ @@ -962,7 +909,7 @@ void Node::rset_unreliable_id(int p_peer_id, const StringName &p_property, const //////////// end of rpc -bool Node::can_call_rpc(const StringName &p_method) const { +bool Node::can_call_rpc(const StringName &p_method, int p_from) const { const Map<StringName, RPCMode>::Element *E = data.rpc_methods.find(p_method); if (E) { @@ -982,7 +929,7 @@ bool Node::can_call_rpc(const StringName &p_method) const { return is_network_master(); } break; case RPC_MODE_SLAVE: { - return !is_network_master(); + return !is_network_master() && p_from == get_network_master(); } break; } } @@ -1006,16 +953,16 @@ bool Node::can_call_rpc(const StringName &p_method) const { return is_network_master(); } break; case ScriptInstance::RPC_MODE_SLAVE: { - return !is_network_master(); + return !is_network_master() && p_from == get_network_master(); } break; } } - ERR_PRINTS("RPC on unauthorized method attempted: " + String(p_method) + " on base: " + String(Variant(this))); + ERR_PRINTS("RPC from " + itos(p_from) + " on unauthorized method attempted: " + String(p_method) + " on base: " + String(Variant(this))); return false; } -bool Node::can_call_rset(const StringName &p_property) const { +bool Node::can_call_rset(const StringName &p_property, int p_from) const { const Map<StringName, RPCMode>::Element *E = data.rpc_properties.find(p_property); if (E) { @@ -1035,7 +982,7 @@ bool Node::can_call_rset(const StringName &p_property) const { return is_network_master(); } break; case RPC_MODE_SLAVE: { - return !is_network_master(); + return !is_network_master() && p_from == get_network_master(); } break; } } @@ -1059,12 +1006,12 @@ bool Node::can_call_rset(const StringName &p_property) const { return is_network_master(); } break; case ScriptInstance::RPC_MODE_SLAVE: { - return !is_network_master(); + return !is_network_master() && p_from == get_network_master(); } break; } } - ERR_PRINTS("RSET on unauthorized property attempted: " + String(p_property) + " on base: " + String(Variant(this))); + ERR_PRINTS("RSET from " + itos(p_from) + " on unauthorized property attempted: " + String(p_property) + " on base: " + String(Variant(this))); return false; } @@ -2845,8 +2792,8 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("request_ready"), &Node::request_ready); - ClassDB::bind_method(D_METHOD("set_network_mode", "mode"), &Node::set_network_mode); - ClassDB::bind_method(D_METHOD("get_network_mode"), &Node::get_network_mode); + ClassDB::bind_method(D_METHOD("set_network_master", "id", "recursive"), &Node::set_network_master, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("get_network_master"), &Node::get_network_master); ClassDB::bind_method(D_METHOD("is_network_master"), &Node::is_network_master); @@ -2902,10 +2849,6 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS); BIND_CONSTANT(NOTIFICATION_INTERNAL_FIXED_PROCESS); - BIND_CONSTANT(NETWORK_MODE_INHERIT); - BIND_CONSTANT(NETWORK_MODE_MASTER); - BIND_CONSTANT(NETWORK_MODE_SLAVE); - BIND_CONSTANT(RPC_MODE_DISABLED); BIND_CONSTANT(RPC_MODE_REMOTE); BIND_CONSTANT(RPC_MODE_SYNC); @@ -2977,8 +2920,7 @@ Node::Node() { data.unhandled_key_input = false; data.pause_mode = PAUSE_MODE_INHERIT; data.pause_owner = NULL; - data.network_mode = NETWORK_MODE_INHERIT; - data.network_owner = NULL; + data.network_master = 1; //server by default data.path_cache = NULL; data.parent_owned = false; data.in_constructor = true; diff --git a/scene/main/node.h b/scene/main/node.h index ffd2b7ce5f..7baa65c022 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -61,13 +61,6 @@ public: DUPLICATE_USE_INSTANCING = 8 }; - enum NetworkMode { - - NETWORK_MODE_INHERIT, - NETWORK_MODE_MASTER, - NETWORK_MODE_SLAVE - }; - enum RPCMode { RPC_MODE_DISABLED, //no rpc for this method, calls to this will be blocked (default) @@ -122,8 +115,7 @@ private: PauseMode pause_mode; Node *pause_owner; - NetworkMode network_mode; - Node *network_owner; + int network_master; Map<StringName, RPCMode> rpc_methods; Map<StringName, RPCMode> rpc_properties; @@ -173,7 +165,6 @@ private: void _propagate_validate_owner(); void _print_stray_nodes(); void _propagate_pause_owner(Node *p_owner); - void _propagate_network_owner(Node *p_owner); Array _get_node_and_resource(const NodePath &p_path); void _duplicate_signals(const Node *p_original, Node *p_copy) const; @@ -393,8 +384,8 @@ public: bool is_displayed_folded() const; /* NETWORK */ - void set_network_mode(NetworkMode p_mode); - NetworkMode get_network_mode() const; + void set_network_master(int p_peer_id, bool p_recursive = true); + int get_network_master() const; bool is_network_master() const; void rpc_config(const StringName &p_method, RPCMode p_mode); // config a local method for RPC @@ -414,8 +405,8 @@ public: void rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value); - bool can_call_rpc(const StringName &p_method) const; - bool can_call_rset(const StringName &p_property) const; + bool can_call_rpc(const StringName &p_method, int p_from) const; + bool can_call_rset(const StringName &p_property, int p_from) const; Node(); ~Node(); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 479abccda6..1e5735de97 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1763,6 +1763,16 @@ int SceneTree::get_network_unique_id() const { return network_peer->get_unique_id(); } +Vector<int> SceneTree::get_network_connected_peers() const { + ERR_FAIL_COND_V(!network_peer.is_valid(), Vector<int>()); + + Vector<int> ret; + for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { + ret.push_back(E->get()); + } + + return ret; +} void SceneTree::set_refuse_new_network_connections(bool p_refuse) { ERR_FAIL_COND(!network_peer.is_valid()); network_peer->set_refuse_new_connections(p_refuse); @@ -1973,6 +1983,7 @@ void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int Node *node = NULL; if (target & 0x80000000) { + //use full path (not cached yet) int ofs = target & 0x7FFFFFFF; ERR_FAIL_COND(ofs >= p_packet_len); @@ -1988,7 +1999,7 @@ void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int ERR_FAIL_COND(node == NULL); } } else { - + //use cached path int id = target; Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from); @@ -2023,7 +2034,7 @@ void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int if (packet_type == NETWORK_COMMAND_REMOTE_CALL) { - if (!node->can_call_rpc(name)) + if (!node->can_call_rpc(name, p_from)) return; int ofs = len_end + 1; @@ -2060,7 +2071,7 @@ void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int } else { - if (!node->can_call_rset(name)) + if (!node->can_call_rset(name, p_from)) return; int ofs = len_end + 1; @@ -2236,6 +2247,7 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_network_peer", "peer:NetworkedMultiplayerPeer"), &SceneTree::set_network_peer); ClassDB::bind_method(D_METHOD("is_network_server"), &SceneTree::is_network_server); ClassDB::bind_method(D_METHOD("has_network_peer"), &SceneTree::has_network_peer); + ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &SceneTree::get_network_connected_peers); ClassDB::bind_method(D_METHOD("get_network_unique_id"), &SceneTree::get_network_unique_id); ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &SceneTree::set_refuse_new_network_connections); ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &SceneTree::is_refusing_new_network_connections); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 2ea79bf945..76a4becdbc 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -451,6 +451,7 @@ public: bool is_network_server() const; bool has_network_peer() const; int get_network_unique_id() const; + Vector<int> get_network_connected_peers() const; void set_refuse_new_network_connections(bool p_refuse); bool is_refusing_new_network_connections() const; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 3934467855..6209f99d9d 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -452,7 +452,7 @@ void SpatialMaterial::_update_shader() { if (features[FEATURE_DEPTH_MAPPING]) { code += "\t{\n"; - code += "\t\tvec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT,BINORMAL,NORMAL));\n"; + code += "\t\tvec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT,-BINORMAL,NORMAL));\n"; //binormal is negative due to mikktpsace if (deep_parallax) { code += "\t\tfloat num_layers = mix(float(depth_max_layers),float(depth_min_layers), abs(dot(vec3(0.0, 0.0, 1.0), view_dir)));\n"; @@ -1265,7 +1265,7 @@ void SpatialMaterial::_bind_methods() { ADD_GROUP("Anisotropy", "anisotropy_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anisotropy_enabled"), "set_feature", "get_feature", FEATURE_ANISOTROPY); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "anisotropy", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_anisotropy", "get_anisotropy"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "anisotropy", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_anisotropy", "get_anisotropy"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anisotropy_flowmap", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_FLOWMAP); ADD_GROUP("Ambient Occlusion", "ao_"); diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 8d058377db..81cfd0e5f0 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -53,7 +53,15 @@ void PrimitiveMesh::_update() { emit_changed(); } -void PrimitiveMesh::_queue_update() { +void PrimitiveMesh::_queue_update(bool p_first_mesh) { + + if (first_mesh && p_first_mesh) { + first_mesh = false; + cache_is_dirty = true; + _update(); + return; + } + if (!cache_is_dirty) { cache_is_dirty = true; call_deferred("_update"); @@ -145,6 +153,7 @@ PrimitiveMesh::PrimitiveMesh() { // make sure we do an update after we've finished constructing our object cache_is_dirty = false; + first_mesh = true; _queue_update(); } @@ -162,7 +171,9 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) { float onethird = 1.0 / 3.0; float twothirds = 2.0 / 3.0; - set_aabb(Rect3(Vector3(-radius, (mid_height * -0.5) - radius, -radius), Vector3(radius * 2.0, mid_height + (2.0 * radius), radius * 2.0))); + // note, this has been aligned with our collision shape but I've left the descriptions as top/middle/bottom + + set_aabb(Rect3(Vector3(-radius, -radius, (mid_height * -0.5) - radius), Vector3(radius * 2.0, radius * 2.0, mid_height + (2.0 * radius)))); PoolVector<Vector3> points; PoolVector<Vector3> normals; @@ -186,19 +197,19 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) { v /= (rings + 1); w = sin(0.5 * Math_PI * v); - y = radius * cos(0.5 * Math_PI * v); + z = radius * cos(0.5 * Math_PI * v); for (i = 0; i <= radial_segments; i++) { u = i; u /= radial_segments; x = sin(u * (Math_PI * 2.0)); - z = cos(u * (Math_PI * 2.0)); + y = -cos(u * (Math_PI * 2.0)); - Vector3 p = Vector3(x * radius * w, y, z * radius * w); - points.push_back(p + Vector3(0.0, 0.5 * mid_height, 0.0)); + Vector3 p = Vector3(x * radius * w, y * radius * w, z); + points.push_back(p + Vector3(0.0, 0.0, 0.5 * mid_height)); normals.push_back(p.normalized()); - ADD_TANGENT(-z, 0.0, x, -1.0) + ADD_TANGENT(y, -x, 0.0, -1.0) uvs.push_back(Vector2(u, v * onethird)); point++; @@ -224,20 +235,20 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) { v = j; v /= (rings + 1); - y = mid_height * v; - y = (mid_height * 0.5) - y; + z = mid_height * v; + z = (mid_height * 0.5) - z; for (i = 0; i <= radial_segments; i++) { u = i; u /= radial_segments; x = sin(u * (Math_PI * 2.0)); - z = cos(u * (Math_PI * 2.0)); + y = -cos(u * (Math_PI * 2.0)); - Vector3 p = Vector3(x * radius, y, z * radius); + Vector3 p = Vector3(x * radius, y * radius, z); points.push_back(p); - normals.push_back(Vector3(x, 0.0, z)); - ADD_TANGENT(-z, 0.0, x, -1.0) + normals.push_back(Vector3(x, y, 0.0)); + ADD_TANGENT(y, -x, 0.0, -1.0) uvs.push_back(Vector2(u, onethird + (v * onethird))); point++; @@ -266,19 +277,19 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) { v /= (rings + 1); v += 1.0; w = sin(0.5 * Math_PI * v); - y = radius * cos(0.5 * Math_PI * v); + z = radius * cos(0.5 * Math_PI * v); for (i = 0; i <= radial_segments; i++) { float u = i; u /= radial_segments; x = sin(u * (Math_PI * 2.0)); - z = cos(u * (Math_PI * 2.0)); + y = -cos(u * (Math_PI * 2.0)); - Vector3 p = Vector3(x * radius * w, y, z * radius * w); - points.push_back(p + Vector3(0.0, -0.5 * mid_height, 0.0)); + Vector3 p = Vector3(x * radius * w, y * radius * w, z); + points.push_back(p + Vector3(0.0, 0.0, -0.5 * mid_height)); normals.push_back(p.normalized()); - ADD_TANGENT(-z, 0.0, x, -1.0) + ADD_TANGENT(y, -x, 0.0, -1.0) uvs.push_back(Vector2(u, twothirds + ((v - 1.0) * onethird))); point++; @@ -350,7 +361,7 @@ int CapsuleMesh::get_radial_segments() const { void CapsuleMesh::set_rings(const int p_rings) { rings = p_rings > 1 ? p_rings : 1; - _queue_update(); + _queue_update(true); //last property set, force update mesh } int CapsuleMesh::get_rings() const { @@ -608,7 +619,7 @@ int CubeMesh::get_subdivide_height() const { void CubeMesh::set_subdivide_depth(const int p_subdivide) { subdivide_d = p_subdivide > 0 ? p_subdivide : 0; - _queue_update(); + _queue_update(true); //last property set, force update mesh } int CubeMesh::get_subdivide_depth() const { @@ -825,7 +836,7 @@ int CylinderMesh::get_radial_segments() const { void CylinderMesh::set_rings(const int p_rings) { rings = p_rings > 0 ? p_rings : 0; - _queue_update(); + _queue_update(true); //last property set, force update mesh } int CylinderMesh::get_rings() const { @@ -942,7 +953,7 @@ int PlaneMesh::get_subdivide_width() const { void PlaneMesh::set_subdivide_depth(const int p_subdivide) { subdivide_d = p_subdivide > 0 ? p_subdivide : 0; - _queue_update(); + _queue_update(true); //last property set, force update mesh } int PlaneMesh::get_subdivide_depth() const { @@ -1232,7 +1243,7 @@ int PrismMesh::get_subdivide_height() const { void PrismMesh::set_subdivide_depth(const int p_divisions) { subdivide_d = p_divisions > 0 ? p_divisions : 0; - _queue_update(); + _queue_update(true); //last property set, force update mesh } int PrismMesh::get_subdivide_depth() const { @@ -1301,6 +1312,7 @@ void QuadMesh::_bind_methods() { QuadMesh::QuadMesh() { primitive_type = PRIMITIVE_TRIANGLE_FAN; + _queue_update(true); } /** @@ -1437,7 +1449,7 @@ int SphereMesh::get_rings() const { void SphereMesh::set_is_hemisphere(const bool p_is_hemisphere) { is_hemisphere = p_is_hemisphere; - _queue_update(); + _queue_update(true); //last property set, force update mesh } bool SphereMesh::get_is_hemisphere() const { diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 91d1af2ee1..5e1387e864 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -51,6 +51,7 @@ private: Ref<Material> material; + bool first_mesh; bool cache_is_dirty; void _update(); @@ -60,7 +61,7 @@ protected: static void _bind_methods(); virtual void _create_mesh_array(Array &p_arr) = 0; - void _queue_update(); + void _queue_update(bool p_first_mesh = false); //pretty bad hack to have the mesh built firt time parameters are set without delay void set_aabb(Rect3 p_aabb); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index b9d2c503e1..dc8f6a0a69 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -57,8 +57,12 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { tile_set_region(id, p_value); else if (what == "shape") tile_set_shape(id, 0, p_value); - else if (what == "shape_offset") - tile_set_shape_offset(id, 0, p_value); + else if (what == "shape_offset") { + Transform2D xform = tile_get_shape_transform(id, 0); + xform.set_origin(p_value); + tile_set_shape_transform(id, 0, xform); + } else if (what == "shape_transform") + tile_set_shape_transform(id, 0, p_value); else if (what == "shape_one_way") tile_set_shape_one_way(id, 0, p_value); else if (what == "shapes") @@ -106,7 +110,9 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { else if (what == "shape") r_ret = tile_get_shape(id, 0); else if (what == "shape_offset") - r_ret = tile_get_shape_offset(id, 0); + r_ret = tile_get_shape_transform(id, 0).get_origin(); + else if (what == "shape_transform") + r_ret = tile_get_shape_transform(id, 0); else if (what == "shape_one_way") r_ret = tile_get_shape_one_way(id, 0); else if (what == "shapes") @@ -143,6 +149,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "navigation_offset")); p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "navigation", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon")); p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "shape_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "shape_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_EDITOR)); p_list->push_back(PropertyInfo(Variant::BOOL, pre + "shape_one_way", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "shapes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); @@ -252,13 +259,13 @@ void TileSet::tile_clear_shapes(int p_id) { tile_map[p_id].shapes_data.clear(); } -void TileSet::tile_add_shape(int p_id, const Ref<Shape2D> &p_shape, const Vector2 &p_offset, bool p_one_way) { +void TileSet::tile_add_shape(int p_id, const Ref<Shape2D> &p_shape, const Transform2D &p_transform, bool p_one_way) { ERR_FAIL_COND(!tile_map.has(p_id)); ShapeData new_data = ShapeData(); new_data.shape = p_shape; - new_data.shape_offset = p_offset; + new_data.shape_transform = p_transform; new_data.one_way_collision = p_one_way; tile_map[p_id].shapes_data.push_back(new_data); @@ -288,22 +295,22 @@ Ref<Shape2D> TileSet::tile_get_shape(int p_id, int p_shape_id) const { return Ref<Shape2D>(); } -void TileSet::tile_set_shape_offset(int p_id, int p_shape_id, const Vector2 &p_offset) { +void TileSet::tile_set_shape_transform(int p_id, int p_shape_id, const Transform2D &p_offset) { ERR_FAIL_COND(!tile_map.has(p_id)); if (tile_map[p_id].shapes_data.size() <= p_shape_id) tile_map[p_id].shapes_data.resize(p_shape_id + 1); - tile_map[p_id].shapes_data[p_shape_id].shape_offset = p_offset; + tile_map[p_id].shapes_data[p_shape_id].shape_transform = p_offset; emit_changed(); } -Vector2 TileSet::tile_get_shape_offset(int p_id, int p_shape_id) const { +Transform2D TileSet::tile_get_shape_transform(int p_id, int p_shape_id) const { - ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2()); + ERR_FAIL_COND_V(!tile_map.has(p_id), Transform2D()); if (tile_map[p_id].shapes_data.size() > p_shape_id) - return tile_map[p_id].shapes_data[p_shape_id].shape_offset; + return tile_map[p_id].shapes_data[p_shape_id].shape_transform; - return Vector2(); + return Transform2D(); } void TileSet::tile_set_shape_one_way(int p_id, int p_shape_id, const bool p_one_way) { @@ -388,7 +395,7 @@ void TileSet::_tile_set_shapes(int p_id, const Array &p_shapes) { ERR_FAIL_COND(!tile_map.has(p_id)); Vector<ShapeData> shapes_data; - Vector2 default_offset = tile_get_shape_offset(p_id, 0); + Transform2D default_transform = tile_get_shape_transform(p_id, 0); bool default_one_way = tile_get_shape_one_way(p_id, 0); for (int i = 0; i < p_shapes.size(); i++) { ShapeData s = ShapeData(); @@ -398,7 +405,7 @@ void TileSet::_tile_set_shapes(int p_id, const Array &p_shapes) { if (shape.is_null()) continue; s.shape = shape; - s.shape_offset = default_offset; + s.shape_transform = default_transform; s.one_way_collision = default_one_way; } else if (p_shapes[i].get_type() == Variant::DICTIONARY) { Dictionary d = p_shapes[i]; @@ -408,10 +415,12 @@ void TileSet::_tile_set_shapes(int p_id, const Array &p_shapes) { else continue; - if (d.has("shape_offset") && d["shape_offset"].get_type() == Variant::VECTOR2) - s.shape_offset = d["shape_offset"]; + if (d.has("shape_transform") && d["shape_transform"].get_type() == Variant::TRANSFORM2D) + s.shape_transform = d["shape_transform"]; + else if (d.has("shape_offset") && d["shape_offset"].get_type() == Variant::VECTOR2) + s.shape_transform = Transform2D(0, (Vector2)d["shape_offset"]); else - s.shape_offset = default_offset; + s.shape_transform = default_transform; if (d.has("one_way") && d["one_way"].get_type() == Variant::BOOL) s.one_way_collision = d["one_way"]; @@ -438,7 +447,7 @@ Array TileSet::_tile_get_shapes(int p_id) const { for (int i = 0; i < data.size(); i++) { Dictionary shape_data; shape_data["shape"] = data[i].shape; - shape_data["shape_offset"] = data[i].shape_offset; + shape_data["shape_transform"] = data[i].shape_transform; shape_data["one_way"] = data[i].one_way_collision; arr.push_back(shape_data); } @@ -520,11 +529,11 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("tile_get_region", "id"), &TileSet::tile_get_region); ClassDB::bind_method(D_METHOD("tile_set_shape", "id", "shape_id", "shape:Shape2D"), &TileSet::tile_set_shape); ClassDB::bind_method(D_METHOD("tile_get_shape:Shape2D", "id", "shape_id"), &TileSet::tile_get_shape); - ClassDB::bind_method(D_METHOD("tile_set_shape_offset", "id", "shape_id", "shape_offset"), &TileSet::tile_set_shape_offset); - ClassDB::bind_method(D_METHOD("tile_get_shape_offset", "id", "shape_id"), &TileSet::tile_get_shape_offset); + ClassDB::bind_method(D_METHOD("tile_set_shape_transform", "id", "shape_id", "shape_transform"), &TileSet::tile_set_shape_transform); + ClassDB::bind_method(D_METHOD("tile_get_shape_transform", "id", "shape_id"), &TileSet::tile_get_shape_transform); ClassDB::bind_method(D_METHOD("tile_set_shape_one_way", "id", "shape_id", "one_way"), &TileSet::tile_set_shape_one_way); ClassDB::bind_method(D_METHOD("tile_get_shape_one_way", "id", "shape_id"), &TileSet::tile_get_shape_one_way); - ClassDB::bind_method(D_METHOD("tile_add_shape", "id", "shape:Shape2D", "shape_offset", "one_way"), &TileSet::tile_add_shape, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("tile_add_shape", "id", "shape:Shape2D", "shape_transform", "one_way"), &TileSet::tile_add_shape, DEFVAL(false)); ClassDB::bind_method(D_METHOD("tile_get_shape_count", "id"), &TileSet::tile_get_shape_count); ClassDB::bind_method(D_METHOD("tile_set_shapes", "id", "shapes"), &TileSet::_tile_set_shapes); ClassDB::bind_method(D_METHOD("tile_get_shapes", "id"), &TileSet::_tile_get_shapes); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index c07d82c75a..99c506390c 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -43,7 +43,7 @@ class TileSet : public Resource { public: struct ShapeData { Ref<Shape2D> shape; - Vector2 shape_offset; + Transform2D shape_transform; bool one_way_collision; ShapeData() { @@ -105,14 +105,14 @@ public: void tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_shape); Ref<Shape2D> tile_get_shape(int p_id, int p_shape_id) const; - void tile_set_shape_offset(int p_id, int p_shape_id, const Vector2 &p_offset); - Vector2 tile_get_shape_offset(int p_id, int p_shape_id) const; + void tile_set_shape_transform(int p_id, int p_shape_id, const Transform2D &p_transform); + Transform2D tile_get_shape_transform(int p_id, int p_shape_id) const; void tile_set_shape_one_way(int p_id, int p_shape_id, bool p_one_way); bool tile_get_shape_one_way(int p_id, int p_shape_id) const; void tile_clear_shapes(int p_id); - void tile_add_shape(int p_id, const Ref<Shape2D> &p_shape, const Vector2 &p_offset, bool p_one_way = false); + void tile_add_shape(int p_id, const Ref<Shape2D> &p_shape, const Transform2D &p_transform, bool p_one_way = false); int tile_get_shape_count(int p_id) const; void tile_set_shapes(int p_id, const Vector<ShapeData> &p_shapes); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 5b60a46ade..69fd097ee8 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -612,6 +612,7 @@ public: enum Type { TYPE_LINE, + TYPE_POLYLINE, TYPE_RECT, TYPE_NINEPATCH, TYPE_PRIMITIVE, @@ -636,6 +637,18 @@ public: bool antialiased; CommandLine() { type = TYPE_LINE; } }; + struct CommandPolyLine : public Command { + + bool antialiased; + Vector<Point2> triangles; + Vector<Color> triangle_colors; + Vector<Point2> lines; + Vector<Color> line_colors; + CommandPolyLine() { + type = TYPE_POLYLINE; + antialiased = false; + } + }; struct CommandRect : public Command { @@ -815,6 +828,31 @@ public: r.position = line->from; r.expand_to(line->to); } break; + case Item::Command::TYPE_POLYLINE: { + + const Item::CommandPolyLine *pline = static_cast<const Item::CommandPolyLine *>(c); + if (pline->triangles.size()) { + for (int j = 0; j < pline->triangles.size(); j++) { + + if (j == 0) { + r.position = pline->triangles[j]; + } else { + r.expand_to(pline->triangles[j]); + } + } + } else { + + for (int j = 0; j < pline->lines.size(); j++) { + + if (j == 0) { + r.position = pline->lines[j]; + } else { + r.expand_to(pline->lines[j]); + } + } + } + + } break; case Item::Command::TYPE_RECT: { const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c); diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 1227863b72..584f45412e 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -392,14 +392,14 @@ void VisualServerCanvas::canvas_item_set_draw_behind_parent(RID p_item, bool p_e canvas_item->behind = p_enable; } -void VisualServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width, bool p_antialiased) { +void VisualServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_colors, float p_width, bool p_antialiased) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandLine *line = memnew(Item::CommandLine); ERR_FAIL_COND(!line); - line->color = p_color; + line->color = p_colors; line->from = p_from; line->to = p_to; line->width = p_width; @@ -409,6 +409,86 @@ void VisualServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from, canvas_item->commands.push_back(line); } +void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { + + ERR_FAIL_COND(p_points.size() < 2); + Item *canvas_item = canvas_item_owner.getornull(p_item); + ERR_FAIL_COND(!canvas_item); + + Item::CommandPolyLine *pline = memnew(Item::CommandPolyLine); + ERR_FAIL_COND(!pline); + + pline->antialiased = p_antialiased; + + if (p_width <= 1) { + pline->lines = p_points; + pline->line_colors = p_colors; + if (pline->line_colors.size() == 0) { + pline->line_colors.push_back(Color(1, 1, 1, 1)); + } else if (pline->line_colors.size() > 1 && pline->line_colors.size() != pline->lines.size()) { + pline->line_colors.resize(1); + } + } else { + //make a trianglestrip for drawing the line... + Vector2 prev_t; + pline->triangles.resize(p_points.size() * 2); + if (p_antialiased) { + pline->lines.resize(p_points.size() * 2); + } + + if (p_colors.size() == 0) { + pline->triangle_colors.push_back(Color(1, 1, 1, 1)); + if (p_antialiased) { + pline->line_colors.push_back(Color(1, 1, 1, 1)); + } + } + if (p_colors.size() == 1) { + pline->triangle_colors = p_colors; + pline->line_colors = p_colors; + } else { + pline->triangle_colors.resize(pline->triangles.size()); + pline->line_colors.resize(pline->lines.size()); + } + + for (int i = 0; i < p_points.size(); i++) { + + Vector2 t; + if (i == p_points.size() - 1) { + t = prev_t; + } else { + t = (p_points[i + 1] - p_points[i]).normalized().tangent(); + if (i == 0) { + prev_t = t; + } + } + + Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5; + + if (p_antialiased) { + pline->lines[i] = p_points[i] + tangent; + pline->lines[p_points.size() * 2 - i - 1] = p_points[i] - tangent; + if (pline->line_colors.size() > 1) { + pline->line_colors[i] = p_colors[i]; + pline->line_colors[p_points.size() * 2 - i - 1] = p_colors[i]; + } + } + + pline->triangles[i * 2 + 0] = p_points[i] + tangent; + pline->triangles[i * 2 + 1] = p_points[i] - tangent; + + if (pline->triangle_colors.size() > 1) { + + pline->triangle_colors[i * 2 + 0] = p_colors[i]; + pline->triangle_colors[i * 2 + 1] = p_colors[i]; + } + + prev_t = t; + } + } + canvas_item->rect_dirty = true; + canvas_item->commands.push_back(pline); +} + void VisualServerCanvas::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) { Item *canvas_item = canvas_item_owner.getornull(p_item); diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 57c7515367..48e3186ece 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -171,6 +171,7 @@ public: void canvas_item_set_draw_behind_parent(RID p_item, bool p_enable); void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); + void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_line, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color); void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID()); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index e201f6a8c0..448af17478 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -1042,6 +1042,7 @@ public: BIND2(canvas_item_set_draw_behind_parent, RID, bool) BIND6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool) + BIND5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) BIND3(canvas_item_add_rect, RID, const Rect2 &, const Color &) BIND4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) BIND7(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID) diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 2c2bd2b167..433b6e945e 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -279,6 +279,7 @@ void VisualServerViewport::draw_viewports() { ERR_CONTINUE(!vp->render_target.is_valid()); bool visible = vp->viewport_to_screen_rect != Rect2() || vp->update_mode == VS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == VS::VIEWPORT_UPDATE_ONCE || (vp->update_mode == VS::VIEWPORT_UPDATE_WHEN_VISIBLE && VSG::storage->render_target_was_used(vp->render_target)); + visible = visible && vp->size.x > 0 && vp->size.y > 0; if (!visible) continue; diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 9f49377fa8..c8afc18740 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -469,6 +469,7 @@ public: FUNC2(canvas_item_set_draw_behind_parent, RID, bool) FUNC6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool) + FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &) FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) FUNC7(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index eb0848ff50..c833f4eabd 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1262,9 +1262,9 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector<uint8_ for (int j = 0; j < p_vertex_len; j++) { - const uint8_t *v = (const uint8_t *)&r[j * total_elem_size + offsets[i]]; + const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]]; for (int k = 0; k < 4; k++) { - w[j * 4 + k] = float(v[k] / 255.0) * 2.0 - 1.0; + w[j * 4 + k] = float(v[k] / 127.0); } } } else { diff --git a/servers/visual_server.h b/servers/visual_server.h index 4d2a983751..06ceb2cf4c 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -787,6 +787,7 @@ public: }; virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false) = 0; + virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0; virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0; virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0; virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID()) = 0; |