diff options
57 files changed, 875 insertions, 326 deletions
diff --git a/SConstruct b/SConstruct index 4ef302cac4..e8f9ec2964 100644 --- a/SConstruct +++ b/SConstruct @@ -491,6 +491,7 @@ else: for x in platform_list: print("\t" + x) print("\nPlease run scons again with argument: platform=<string>") + sys.exit(255) screen = sys.stdout diff --git a/core/SCsub b/core/SCsub index af83b49fea..383aaf0e12 100644 --- a/core/SCsub +++ b/core/SCsub @@ -18,9 +18,8 @@ gd_cpp = '#include "project_settings.h"\n' gd_cpp += gd_inc gd_cpp += "void ProjectSettings::register_global_defaults() {\n" + gd_call + "\n}\n" -f = open("global_defaults.gen.cpp", "w") -f.write(gd_cpp) -f.close() +with open("global_defaults.gen.cpp", "w") as f: + f.write(gd_cpp) # Generate AES256 script encryption key @@ -47,9 +46,8 @@ if ("SCRIPT_AES256_ENCRYPTION_KEY" in os.environ): txt = "0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0" print("Invalid AES256 encryption key, not 64 bits hex: " + e) -f = open("script_encryption_key.gen.cpp", "w") -f.write("#include \"project_settings.h\"\nuint8_t script_encryption_key[32]={" + txt + "};\n") -f.close() +with open("script_encryption_key.gen.cpp", "w") as f: + f.write("#include \"project_settings.h\"\nuint8_t script_encryption_key[32]={" + txt + "};\n") # Add required thirdparty code. Header paths are hardcoded, we don't need to append @@ -68,7 +66,6 @@ thirdparty_sources = [ "md5.cpp", "pcg.cpp", "triangulator.cpp", - "clipper.cpp", ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] env.add_source_files(env.core_sources, thirdparty_sources) diff --git a/core/make_binders.py b/core/make_binders.py index 1e581f8ce3..6a7602cd5d 100644 --- a/core/make_binders.py +++ b/core/make_binders.py @@ -265,10 +265,8 @@ def run(target, source, env): else: text += t - f = open(target[0].path, "w") - f.write(text) - f.close() + with open(target[0].path, "w") as f: + f.write(text) - f = open(target[1].path, "w") - f.write(text_ext) - f.close() + with open(target[1].path, "w") as f: + f.write(text_ext) diff --git a/core/math/math_2d.cpp b/core/math/math_2d.cpp index d2e4101999..3767d298a1 100644 --- a/core/math/math_2d.cpp +++ b/core/math/math_2d.cpp @@ -98,11 +98,6 @@ real_t Vector2::cross(const Vector2 &p_other) const { return x * p_other.y - y * p_other.x; } -Vector2 Vector2::cross(real_t p_other) const { - - return Vector2(p_other * y, -p_other * x); -} - Vector2 Vector2::floor() const { return Vector2(Math::floor(x), Math::floor(y)); diff --git a/core/math/math_2d.h b/core/math/math_2d.h index 8928349a44..02d921b67e 100644 --- a/core/math/math_2d.h +++ b/core/math/math_2d.h @@ -104,7 +104,6 @@ struct Vector2 { real_t dot(const Vector2 &p_other) const; real_t cross(const Vector2 &p_other) const; - Vector2 cross(real_t p_other) const; Vector2 project(const Vector2 &p_vec) const; Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const; diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 427fa77e62..3eb8ad7bf5 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -692,7 +692,10 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const Map<Strin String vstr; VariantWriter::write_to_string(value, vstr); - file->store_string(F->get() + "=" + vstr + "\n"); + if (F->get().find(" ") != -1) + file->store_string(F->get().quote() + "=" + vstr + "\n"); + else + file->store_string(F->get() + "=" + vstr + "\n"); } } diff --git a/core/variant_call.cpp b/core/variant_call.cpp index d1d45f0e7c..cda7dccf0c 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -347,7 +347,7 @@ struct _VariantCall { VCALL_LOCALMEM1R(Vector2, bounce); VCALL_LOCALMEM1R(Vector2, reflect); VCALL_LOCALMEM0R(Vector2, angle); - //VCALL_LOCALMEM1R(Vector2,cross); + VCALL_LOCALMEM1R(Vector2, cross); VCALL_LOCALMEM0R(Vector2, abs); VCALL_LOCALMEM1R(Vector2, clamped); @@ -1517,7 +1517,7 @@ void register_variant_methods() { ADDFUNC1R(VECTOR2, VECTOR2, Vector2, slide, VECTOR2, "n", varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, bounce, VECTOR2, "n", varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, reflect, VECTOR2, "n", varray()); - //ADDFUNC1R(VECTOR2,REAL,Vector2,cross,VECTOR2,"with",varray()); + ADDFUNC1R(VECTOR2, REAL, Vector2, cross, VECTOR2, "with", varray()); ADDFUNC0R(VECTOR2, VECTOR2, Vector2, abs, varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, clamped, REAL, "length", varray()); diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index b158154c49..c1bd8d34eb 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -436,74 +436,109 @@ <constant name="FORMAT_LA8" value="1" enum="Format"> </constant> <constant name="FORMAT_R8" value="2" enum="Format"> + OpenGL texture format RED with a single component and a bitdepth of 8. </constant> <constant name="FORMAT_RG8" value="3" enum="Format"> + OpenGL texture format RG with two components and a bitdepth of 8 for each. </constant> <constant name="FORMAT_RGB8" value="4" enum="Format"> + OpenGL texture format RGB with three components, each with a bitdepth of 8. </constant> <constant name="FORMAT_RGBA8" value="5" enum="Format"> + OpenGL texture format RGBA with four components, each with a bitdepth of 8. </constant> <constant name="FORMAT_RGBA4444" value="6" enum="Format"> + OpenGL texture format RGBA with four components, each with a bitdepth of 4. </constant> <constant name="FORMAT_RGBA5551" value="7" enum="Format"> + OpenGL texture format GL_RGB5_A1 where 5 bits of depth for each component of RGB and one bit for alpha. </constant> <constant name="FORMAT_RF" value="8" enum="Format"> + OpenGL texture format GL_R32F where there's one component, a 32-bit floating-point value. </constant> <constant name="FORMAT_RGF" value="9" enum="Format"> + OpenGL texture format GL_RG32F where there are two components, each a 32-bit floating-point values. </constant> <constant name="FORMAT_RGBF" value="10" enum="Format"> + OpenGL texture format GL_RGB32F where there are three components, each a 32-bit floating-point values. </constant> <constant name="FORMAT_RGBAF" value="11" enum="Format"> + OpenGL texture format GL_RGBA32F where there are four components, each a 32-bit floating-point values. </constant> <constant name="FORMAT_RH" value="12" enum="Format"> + OpenGL texture format GL_R32F where there's one component, a 16-bit "half-precision" floating-point value. </constant> <constant name="FORMAT_RGH" value="13" enum="Format"> + OpenGL texture format GL_RG32F where there's two components, each a 16-bit "half-precision" floating-point value. </constant> <constant name="FORMAT_RGBH" value="14" enum="Format"> + OpenGL texture format GL_RGB32F where there's three components, each a 16-bit "half-precision" floating-point value. </constant> <constant name="FORMAT_RGBAH" value="15" enum="Format"> + OpenGL texture format GL_RGBA32F where there's four components, each a 16-bit "half-precision" floating-point value. </constant> <constant name="FORMAT_RGBE9995" value="16" enum="Format"> + A special OpenGL texture format where the three color components have 9 bits of precision and all three share a single exponent. </constant> <constant name="FORMAT_DXT1" value="17" enum="Format"> + The S3TC texture format that uses Block Compression 1, and is the smallest variation of S3TC, only providing 1 bit of alpha and color data being premultiplied with alpha. More information can be found at https://www.khronos.org/opengl/wiki/S3_Texture_Compression. </constant> <constant name="FORMAT_DXT3" value="18" enum="Format"> + The S3TC texture format that uses Block Compression 2, and color data is interpreted as not having been premultiplied by alpha. Well suited for images with sharp alpha transitions between translucent and opaque areas. </constant> <constant name="FORMAT_DXT5" value="19" enum="Format"> + The S3TC texture format also known as Block Compression 3 or BC3 that contains 64 bits of alpha channel data followed by 64 bits of DXT1-encoded color data. Color data is not premultiplied by alpha, same as DXT3. DXT5 generally produces superior results for transparency gradients than DXT3. </constant> <constant name="FORMAT_RGTC_R" value="20" enum="Format"> + Texture format that uses Red Green Texture Compression, normalizing the red channel data using the same compression algorithm that DXT5 uses for the alpha channel. More information can be found here https://www.khronos.org/opengl/wiki/Red_Green_Texture_Compression. </constant> <constant name="FORMAT_RGTC_RG" value="21" enum="Format"> + Texture format that uses Red Green Texture Compression, normalizing the red and green channel data using the same compression algorithm that DXT5 uses for the alpha channel. </constant> <constant name="FORMAT_BPTC_RGBA" value="22" enum="Format"> + Texture format that uses BPTC compression with unsigned normalized RGBA components. More information can be found at https://www.khronos.org/opengl/wiki/BPTC_Texture_Compression. </constant> <constant name="FORMAT_BPTC_RGBF" value="23" enum="Format"> + Texture format that uses BPTC compression with signed floating-point RGB components. </constant> <constant name="FORMAT_BPTC_RGBFU" value="24" enum="Format"> + Texture format that uses BPTC compression with unsigned floating-point RGB components. </constant> <constant name="FORMAT_PVRTC2" value="25" enum="Format"> + Texture format used on PowerVR-supported mobile platforms, uses 2 bit color depth with no alpha. More information on PVRTC can be found here https://en.wikipedia.org/wiki/PVRTC. </constant> <constant name="FORMAT_PVRTC2A" value="26" enum="Format"> + Same as PVRTC2, but with an alpha component. </constant> <constant name="FORMAT_PVRTC4" value="27" enum="Format"> + Similar to PVRTC2, but with 4 bit color depth and no alpha. </constant> <constant name="FORMAT_PVRTC4A" value="28" enum="Format"> + Same as PVRTC4, but with an alpha component. </constant> <constant name="FORMAT_ETC" value="29" enum="Format"> + Ericsson Texture Compression format, also referred to as 'ETC1', and is part of the OpenGL ES graphics standard. An overview of the format is given at https://en.wikipedia.org/wiki/Ericsson_Texture_Compression#ETC1. </constant> <constant name="FORMAT_ETC2_R11" value="30" enum="Format"> + Ericsson Texture Compression format 2 variant R11_EAC, which provides one channel of unsigned data. </constant> <constant name="FORMAT_ETC2_R11S" value="31" enum="Format"> + Ericsson Texture Compression format 2 variant SIGNED_R11_EAC, which provides one channel of signed data. </constant> <constant name="FORMAT_ETC2_RG11" value="32" enum="Format"> + Ericsson Texture Compression format 2 variant RG11_EAC, which provides two channels of unsigned data. </constant> <constant name="FORMAT_ETC2_RG11S" value="33" enum="Format"> + Ericsson Texture Compression format 2 variant SIGNED_RG11_EAC, which provides two channels of signed data. </constant> <constant name="FORMAT_ETC2_RGB8" value="34" enum="Format"> + Ericsson Texture Compression format 2 variant RGB8, which is a followup of ETC1 and compresses RGB888 data. </constant> <constant name="FORMAT_ETC2_RGBA8" value="35" enum="Format"> + Ericsson Texture Compression format 2 variant RGBA8, which compresses RGBA8888 data with full alpha support. </constant> <constant name="FORMAT_ETC2_RGB8A1" value="36" enum="Format"> + Ericsson Texture Compression format 2 variant RGB8_PUNCHTHROUGH_ALPHA1, which compresses RGBA data to make alpha either fully transparent or fully opaque. </constant> <constant name="FORMAT_MAX" value="37" enum="Format"> </constant> diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index 9df2eb143b..b293ec3368 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -81,6 +81,15 @@ Returns the vector with a maximum length. </description> </method> + <method name="cross"> + <return type="float"> + </return> + <argument index="0" name="b" type="Vector2"> + </argument> + <description> + Returns the 2-dimensional analog of the cross product with [code]b[/code]. + </description> + </method> <method name="cubic_interpolate"> <return type="Vector2"> </return> diff --git a/doc/tools/makemd.py b/doc/tools/makemd.py index a73a4337d0..056f1ca82d 100644 --- a/doc/tools/makemd.py +++ b/doc/tools/makemd.py @@ -93,6 +93,8 @@ def make_class_list(class_list, columns): s += '\n' f.write(s) + f.close() + def dokuize_text(txt): @@ -330,6 +332,8 @@ def make_doku_class(node): f.write('\n') f.write(dokuize_text(d.text.strip())) f.write('\n') + + f.close() for file in input_list: diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py index 9e767bf3d6..8074ce45ea 100644 --- a/doc/tools/makerst.py +++ b/doc/tools/makerst.py @@ -104,6 +104,7 @@ def make_class_list(class_list, columns): f.write("--+-------+") f.write("\n") + f.close() def rstize_text(text, cclass): # Linebreak + tabs in the XML should become two line breaks unless in a "codeblock" @@ -572,6 +573,8 @@ def make_rst_class(node): f.write("\n\n") f.write('\n') + f.close() + file_list = [] diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 3732fe77b1..ca39d9f966 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -415,4 +415,5 @@ RasterizerGLES3::~RasterizerGLES3() { memdelete(storage); memdelete(canvas); + memdelete(scene); } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 5bb332816d..02d851288a 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -5118,3 +5118,23 @@ void RasterizerSceneGLES3::finalize() { RasterizerSceneGLES3::RasterizerSceneGLES3() { } + +RasterizerSceneGLES3::~RasterizerSceneGLES3() { + + memdelete(default_material.get_data()); + memdelete(default_material_twosided.get_data()); + memdelete(default_shader.get_data()); + memdelete(default_shader_twosided.get_data()); + + memdelete(default_worldcoord_material.get_data()); + memdelete(default_worldcoord_material_twosided.get_data()); + memdelete(default_worldcoord_shader.get_data()); + memdelete(default_worldcoord_shader_twosided.get_data()); + + memdelete(default_overdraw_material.get_data()); + memdelete(default_overdraw_shader.get_data()); + + memfree(state.spot_array_tmp); + memfree(state.omni_array_tmp); + memfree(state.reflection_array_tmp); +} diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 1b99e119ce..a6faeef473 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -852,6 +852,7 @@ public: void initialize(); void finalize(); RasterizerSceneGLES3(); + ~RasterizerSceneGLES3(); }; #endif // RASTERIZERSCENEGLES3_H diff --git a/editor/SCsub b/editor/SCsub index 8f87e12cb9..4ca6b9e3fd 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -4,6 +4,7 @@ Import('env') env.editor_sources = [] import os +import os.path from compat import encode_utf8, byte_to_str, open_utf8, escape_string @@ -29,6 +30,9 @@ def make_certs_header(target, source, env): g.write("};\n") g.write("#endif") + g.close() + f.close() + def make_doc_header(target, source, env): @@ -41,8 +45,8 @@ def make_doc_header(target, source, env): src = s.srcnode().abspath if not src.endswith(".xml"): continue - f = open_utf8(src, "r") - content = f.read() + with open_utf8(src, "r") as f: + content = f.read() buf += content buf = encode_utf8(docbegin + buf + docend) @@ -62,6 +66,8 @@ def make_doc_header(target, source, env): g.write("#endif") + g.close() + def make_fonts_header(target, source, env): @@ -76,9 +82,8 @@ def make_fonts_header(target, source, env): # saving uncompressed, since freetype will reference from memory pointer xl_names = [] for i in range(len(source)): - f = open(source[i].srcnode().abspath, "rb") - buf = f.read() - import os.path + with open(source[i].srcnode().abspath, "rb")as f: + buf = f.read() name = os.path.splitext(os.path.basename(source[i].srcnode().abspath))[0] @@ -91,6 +96,8 @@ def make_fonts_header(target, source, env): g.write("#endif") + g.close() + def make_translations_header(target, source, env): @@ -110,8 +117,8 @@ def make_translations_header(target, source, env): xl_names = [] for i in range(len(sorted_paths)): - f = open(sorted_paths[i], "rb") - buf = f.read() + with open(sorted_paths[i], "rb") as f: + buf = f.read() decomp_size = len(buf) buf = zlib.compress(buf) name = os.path.splitext(os.path.basename(sorted_paths[i]))[0] @@ -138,6 +145,9 @@ def make_translations_header(target, source, env): g.write("#endif") + g.close() + + def make_authors_header(target, source, env): sections = ["Project Founders", "Lead Developer", "Project Manager", "Developers"] @@ -180,6 +190,9 @@ def make_authors_header(target, source, env): g.write("#endif\n") + g.close() + f.close() + def make_donors_header(target, source, env): sections = ["Platinum sponsors", "Gold sponsors", "Mini sponsors", "Gold donors", "Silver donors", "Bronze donors"] @@ -222,6 +235,10 @@ def make_donors_header(target, source, env): g.write("#endif\n") + g.close() + f.close() + + def make_license_header(target, source, env): src_copyright = source[0].srcnode().abspath @@ -387,17 +404,23 @@ def make_license_header(target, source, env): g.write("#endif\n") + g.close() + fc.close() + f.close() + def _make_doc_data_class_path(to_path): - g = open_utf8(os.path.join(to_path,"doc_data_class_path.gen.h"), "w") - g.write("static const int _doc_data_class_path_count = " + str(len(env.doc_class_path)) + ";\n") - g.write("struct _DocDataClassPath { const char* name; const char* path; };\n") + g = open_utf8(os.path.join(to_path,"doc_data_class_path.gen.h"), "w") + g.write("static const int _doc_data_class_path_count = " + str(len(env.doc_class_path)) + ";\n") + g.write("struct _DocDataClassPath { const char* name; const char* path; };\n") + + g.write("static const _DocDataClassPath _doc_data_class_paths[" + str(len(env.doc_class_path) + 1) + "] = {\n"); + for c in sorted(env.doc_class_path): + g.write("\t{\"" + c + "\", \"" + env.doc_class_path[c] + "\"},\n") + g.write("\t{NULL, NULL}\n") + g.write("};\n") - g.write("static const _DocDataClassPath _doc_data_class_paths[" + str(len(env.doc_class_path) + 1) + "] = {\n"); - for c in sorted(env.doc_class_path): - g.write("\t{\"" + c + "\", \"" + env.doc_class_path[c] + "\"},\n") - g.write("\t{NULL, NULL}\n") - g.write("};\n") + g.close() if env['tools']: @@ -409,10 +432,9 @@ if env['tools']: reg_exporters += '\tregister_' + e + '_exporter();\n' reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n' reg_exporters += '}\n' - f = open_utf8("register_exporters.gen.cpp", "w") - f.write(reg_exporters_inc) - f.write(reg_exporters) - f.close() + with open_utf8("register_exporters.gen.cpp", "w") as f: + f.write(reg_exporters_inc) + f.write(reg_exporters) # API documentation docs = [] @@ -466,6 +488,7 @@ if env['tools']: env.add_source_files(env.editor_sources, "*.cpp") + env.add_source_files(env.editor_sources, ["#thirdparty/misc/clipper.cpp"]) SConscript('collada/SCsub') SConscript('doc/SCsub') diff --git a/editor/animation_editor.cpp b/editor/animation_editor.cpp index 1b97a24968..439ec37e71 100644 --- a/editor/animation_editor.cpp +++ b/editor/animation_editor.cpp @@ -1149,14 +1149,12 @@ void AnimationKeyEditor::_track_editor_draw() { get_icon("KeyCall", "EditorIcons") }; + Ref<Texture> valid_icon = get_icon("KeyValid", "EditorIcons"); Ref<Texture> invalid_icon = get_icon("KeyInvalid", "EditorIcons"); - Ref<Texture> invalid_icon_hover = get_icon("KeyInvalidHover", "EditorIcons"); + const Color modulate_selected = Color(0x84 / 255.0, 0xc2 / 255.0, 0xff / 255.0); Ref<Texture> hsize_icon = get_icon("Hsize", "EditorIcons"); - Ref<Texture> type_hover = get_icon("KeyHover", "EditorIcons"); - Ref<Texture> type_selected = get_icon("KeySelected", "EditorIcons"); - int right_separator_ofs = right_data_size_cache; int h = font->get_height() + sep; @@ -1268,8 +1266,21 @@ void AnimationKeyEditor::_track_editor_draw() { int decimals = 2; bool step_found = false; + const int period_width = font->get_char_size('.').width; + int max_digit_width = font->get_char_size('0').width; + for (int i = 1; i <= 9; i++) { + const int digit_width = font->get_char_size('0' + i).width; + max_digit_width = MAX(digit_width, max_digit_width); + } + const int max_sc = int(Math::ceil(zoomw / scale)); + const int max_sc_width = String::num(max_sc).length() * max_digit_width; + while (!step_found) { + min = max_sc_width; + if (decimals > 0) + min += period_width + max_digit_width * decimals; + static const int _multp[3] = { 1, 2, 5 }; for (int i = 0; i < 3; i++) { @@ -1464,6 +1475,10 @@ void AnimationKeyEditor::_track_editor_draw() { float x = key_hofs + name_limit + (time - keys_from) * zoom_scale; Ref<Texture> tex = type_icon[tt]; + Color modulate = Color(1, 1, 1); + + bool is_hover = false; + bool is_selected = false; SelectedKey sk; sk.key = i; @@ -1472,13 +1487,33 @@ void AnimationKeyEditor::_track_editor_draw() { if (click.click == ClickOver::CLICK_MOVE_KEYS) continue; - tex = type_selected; + is_selected = true; } if (mouse_over.over == MouseOver::OVER_KEY && mouse_over.track == idx && mouse_over.over_key == i) - tex = type_hover; + is_hover = true; Variant value = animation->track_get_key_value(idx, i); + + if (prop_exists && !Variant::can_convert(value.get_type(), valid_type)) { + + tex = invalid_icon; + if (is_hover) + modulate = Color(1.5, 1.5, 1.5); + else + modulate = Color(1, 1, 1); + } else if (is_selected) { + + tex = valid_icon; + modulate = modulate_selected; + if (is_hover) + modulate = modulate.lightened(0.2); + } else if (is_hover) { + + tex = valid_icon; + modulate = Color(1, 1, 1); + } + if (first && i > 0 && value == animation->track_get_key_value(idx, i - 1)) { te->draw_line(ofs + Vector2(name_limit, y + h / 2), ofs + Point2(x, y + h / 2), color); @@ -1491,19 +1526,7 @@ void AnimationKeyEditor::_track_editor_draw() { te->draw_line(ofs + Point2(x_n, y + h / 2), ofs + Point2(x, y + h / 2), color); } - if (prop_exists && !Variant::can_convert(value.get_type(), valid_type)) { - te->draw_texture(invalid_icon, ofs + Point2(x, y + key_vofs).floor()); - } - - if (prop_exists && !Variant::can_convert(value.get_type(), valid_type)) { - if (tex == type_hover) - te->draw_texture(invalid_icon_hover, ofs + Point2(x, y + key_vofs).floor()); - else - te->draw_texture(invalid_icon, ofs + Point2(x, y + key_vofs).floor()); - } else { - - te->draw_texture(tex, ofs + Point2(x, y + key_vofs).floor()); - } + te->draw_texture(tex, ofs + Point2(x, y + key_vofs).floor(), modulate); first = false; } @@ -1539,8 +1562,8 @@ void AnimationKeyEditor::_track_editor_draw() { continue; int y = h + i * h + sep; - float key_vofs = Math::floor((float)(h - type_selected->get_height()) / 2); - float key_hofs = -Math::floor((float)type_selected->get_height() / 2); + float key_vofs = Math::floor((float)(h - valid_icon->get_height()) / 2); + float key_hofs = -Math::floor((float)valid_icon->get_height() / 2); float time = animation->track_get_key_time(idx, E->key().key); float diff = time - from_t; @@ -1554,7 +1577,7 @@ void AnimationKeyEditor::_track_editor_draw() { x += name_limit; - te->draw_texture(type_selected, ofs + Point2(x + key_hofs, y + key_vofs).floor()); + te->draw_texture(valid_icon, ofs + Point2(x + key_hofs, y + key_vofs).floor(), modulate_selected); } } break; default: {}; @@ -2930,8 +2953,8 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input) Ref<InputEventPanGesture> pan_gesture = p_input; if (pan_gesture.is_valid()) { - h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * pan_gesture->get_delta().x / 8); - v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * pan_gesture->get_delta().y / 8); + h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * pan_gesture->get_delta().x / 8); + v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8); } } @@ -3998,6 +4021,7 @@ AnimationKeyEditor::AnimationKeyEditor() { //key_edit->ke_dialog=key_edit_dialog; type_menu = memnew(PopupMenu); + type_menu->set_pass_on_modal_close_click(false); add_child(type_menu); for (int i = 0; i < Variant::VARIANT_MAX; i++) type_menu->add_item(Variant::get_type_name(Variant::Type(i)), i); @@ -4038,6 +4062,7 @@ AnimationKeyEditor::AnimationKeyEditor() { add_child(track_name); track_name->connect("text_entered", this, "_track_name_changed"); track_menu = memnew(PopupMenu); + track_menu->set_pass_on_modal_close_click(false); add_child(track_menu); track_menu->connect("id_pressed", this, "_track_menu_selected"); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 0e9b7b74fd..a2f5c1aa1a 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -643,10 +643,10 @@ EditorAutoloadSettings::EditorAutoloadSettings() { tree->set_column_title(2, TTR("Singleton")); tree->set_column_expand(2, false); - tree->set_column_min_width(2, 80); + tree->set_column_min_width(2, 80 * EDSCALE); tree->set_column_expand(3, false); - tree->set_column_min_width(3, 120); + tree->set_column_min_width(3, 120 * EDSCALE); tree->connect("cell_selected", this, "_autoload_selected"); tree->connect("item_edited", this, "_autoload_edited"); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index dca32d7492..15aa2c3a0e 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1316,6 +1316,9 @@ void EditorFileSystem::update_file(const String &p_file) { fs->files[cpos]->deps = _get_dependencies(p_file); fs->files[cpos]->import_valid = ResourceLoader::is_import_valid(p_file); + // Update preview + EditorResourcePreview::get_singleton()->check_for_invalidation(p_file); + call_deferred("emit_signal", "filesystem_changed"); //update later } diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index e301d12214..158eedfb0f 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -88,6 +88,7 @@ void EditorLog::_notification(int p_what) { void EditorLog::_clear_request() { log->clear(); + tool_button->set_icon(Ref<Texture>()); } void EditorLog::clear() { @@ -103,9 +104,7 @@ void EditorLog::add_message(const String &p_msg, bool p_error) { Ref<Texture> icon = get_icon("Error", "EditorIcons"); log->add_image(icon); log->add_text(" "); - //button->set_icon(icon); - } else { - //button->set_icon(Ref<Texture>()); + tool_button->set_icon(icon); } log->add_text(p_msg); @@ -115,6 +114,10 @@ void EditorLog::add_message(const String &p_msg, bool p_error) { log->pop(); } +void EditorLog::set_tool_button(ToolButton *p_tool_button) { + tool_button = p_tool_button; +} + /* void EditorLog::_dragged(const Point2& p_ofs) { diff --git a/editor/editor_log.h b/editor/editor_log.h index 42137f71cc..f9bc82de7d 100644 --- a/editor/editor_log.h +++ b/editor/editor_log.h @@ -51,6 +51,7 @@ class EditorLog : public VBoxContainer { RichTextLabel *log; HBoxContainer *title_hb; //PaneDrag *pd; + ToolButton *tool_button; static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, ErrorHandlerType p_type); @@ -68,6 +69,7 @@ protected: public: void add_message(const String &p_msg, bool p_error = false); + void set_tool_button(ToolButton *p_tool_button); void deinit(); void clear(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 8132575479..309a3b42ab 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -597,6 +597,7 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS); if (err != OK) { + current_option = -1; accept->set_text(TTR("Error saving resource!")); accept->popup_centered_minsize(); return; @@ -1194,6 +1195,7 @@ void EditorNode::_dialog_action(String p_file) { Error err = ResourceSaver::save(p_file, ml); if (err) { + current_option = -1; accept->get_ok()->set_text(TTR("I see..")); accept->set_text(TTR("Error saving MeshLibrary!")); accept->popup_centered_minsize(); @@ -1228,6 +1230,7 @@ void EditorNode::_dialog_action(String p_file) { Error err = ResourceSaver::save(p_file, ml); if (err) { + current_option = -1; accept->get_ok()->set_text(TTR("I see..")); accept->set_text(TTR("Error saving TileSet!")); accept->popup_centered_minsize(); @@ -5557,7 +5560,8 @@ EditorNode::EditorNode() { bottom_panel_vb->add_child(bottom_panel_hb); log = memnew(EditorLog); - add_bottom_panel_item(TTR("Output"), log); + ToolButton *output_button = add_bottom_panel_item(TTR("Output"), log); + log->set_tool_button(output_button); old_split_ofs = 0; diff --git a/editor/icons/SCsub b/editor/icons/SCsub index 64992a9f90..7f94073e01 100644 --- a/editor/icons/SCsub +++ b/editor/icons/SCsub @@ -82,10 +82,9 @@ def make_editor_icons_action(target, source, env): s.write("#endif\n") + with open(dst, "w") as f: + f.write(s.getvalue()) - f = open(dst, "w") - f.write(s.getvalue()) - f.close() s.close() icons_string.close() diff --git a/editor/icons/icon_key_selected.svg b/editor/icons/icon_key_selected.svg deleted file mode 100644 index c73d31981d..0000000000 --- a/editor/icons/icon_key_selected.svg +++ /dev/null @@ -1,5 +0,0 @@ -<svg width="8" height="8" version="1.1" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1044.4)"> -<rect transform="rotate(-45)" x="-741.53" y="741.08" width="6.1027" height="6.1027" ry=".76286" fill="#84c2ff"/> -</g> -</svg> diff --git a/editor/icons/icon_key_hover.svg b/editor/icons/icon_key_valid.svg index 4a3fab4754..4a3fab4754 100644 --- a/editor/icons/icon_key_hover.svg +++ b/editor/icons/icon_key_valid.svg diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index c22e1cd88b..04c9246aed 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -1011,6 +1011,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set) { player->seek_delta(pos, pos - cpos); } else { + player->stop(true); player->seek(pos, true); } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index ba68259599..3bb9dca95f 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1615,10 +1615,10 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { if (drag_type == DRAG_NONE) { if (b.is_valid() && - ((b->get_button_index() == BUTTON_LEFT && b->get_alt() && tool == TOOL_SELECT) || + ((b->get_button_index() == BUTTON_RIGHT && b->get_alt() && tool == TOOL_SELECT) || (b->get_button_index() == BUTTON_LEFT && tool == TOOL_LIST_SELECT))) { // Popup the selection menu list - Point2 click = transform.xform(b->get_position()); + Point2 click = transform.affine_inverse().xform(b->get_position()); Node *scene = editor->get_edited_scene(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index aeba0ff930..c8ea2f79fe 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -349,7 +349,12 @@ void ScriptTextEditor::_convert_case(CaseStyle p_case) { int end_col = te->get_selection_to_column(); for (int i = begin; i <= end; i++) { - String new_line = te->get_line(i); + int len = te->get_line(i).length(); + if (i == end) + len -= len - end_col; + if (i == begin) + len -= begin_col; + String new_line = te->get_line(i).substr(i == begin ? begin_col : 0, len); switch (p_case) { case UPPER: { @@ -364,10 +369,10 @@ void ScriptTextEditor::_convert_case(CaseStyle p_case) { } if (i == begin) { - new_line = te->get_line(i).left(begin_col) + new_line.right(begin_col); + new_line = te->get_line(i).left(begin_col) + new_line; } if (i == end) { - new_line = new_line.left(end_col) + te->get_line(i).right(end_col); + new_line = new_line + te->get_line(i).right(end_col); } te->set_line(i, new_line); } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 9625bc19c0..096d9c1a90 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -137,12 +137,12 @@ void ProjectSettingsEditor::_action_edited() { if (new_name == old_name) return; - if (new_name.find("/") != -1 || new_name.find(":") != -1 || new_name == "") { + if (new_name.find("/") != -1 || new_name.find(":") != -1 || new_name.find("\"") != -1 || new_name == "") { ti->set_text(0, old_name); add_at = "input/" + old_name; - message->set_text(TTR("Invalid action (anything goes but '/' or ':').")); + message->set_text(TTR("Invalid action (anything goes but '/', ':' or '\"').")); message->popup_centered(Size2(300, 100) * EDSCALE); return; } @@ -830,9 +830,9 @@ void ProjectSettingsEditor::_action_check(String p_action) { action_add->set_disabled(true); } else { - if (p_action.find("/") != -1 || p_action.find(":") != -1) { + if (p_action.find("/") != -1 || p_action.find(":") != -1 || p_action.find("\"") != -1) { - action_add_error->set_text(TTR("Can't contain '/' or ':'")); + action_add_error->set_text(TTR("Can't contain '/', ':' or '\"'")); action_add_error->show(); action_add->set_disabled(true); return; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 9f0f62592b..002d702bac 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1411,6 +1411,7 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node) { Node *n = p_node; Node *newnode = p_by_node; + Node *default_oldnode = Object::cast_to<Node>(ClassDB::instance(n->get_class())); List<PropertyInfo> pinfo; n->get_property_list(&pinfo); @@ -1419,8 +1420,11 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node) { continue; if (E->get().name == "__meta__") continue; - newnode->set(E->get().name, n->get(E->get().name)); + if (default_oldnode->get(E->get().name) != n->get(E->get().name)) { + newnode->set(E->get().name, n->get(E->get().name)); + } } + memdelete(default_oldnode); editor->push_item(NULL); diff --git a/editor/translations/extract.py b/editor/translations/extract.py index bbc157788d..4b3f416343 100755 --- a/editor/translations/extract.py +++ b/editor/translations/extract.py @@ -52,11 +52,7 @@ msgstr "" "Content-Transfer-Encoding: 8-bit\\n" """ -print("Updating the editor.pot template...") - -for fname in matches: - - f = open(fname, "rb") +def process_file(f, fname): l = f.readline() lc = 1 @@ -100,12 +96,14 @@ for fname in matches: l = f.readline() lc += 1 - f.close() +print("Updating the editor.pot template...") +for fname in matches: + with open(fname, "rb") as f: + process_file(f, fname) -f = open("editor.pot", "wb") -f.write(main_po) -f.close() +with open("editor.pot", "wb") as f: + f.write(main_po) if (os.name == "posix"): print("Wrapping template at 79 characters for compatibility with Weblate.") diff --git a/main/SCsub b/main/SCsub index 5748bc38d2..aa9092ca51 100644 --- a/main/SCsub +++ b/main/SCsub @@ -8,60 +8,59 @@ def make_splash(target, source, env): src = source[0].srcnode().abspath dst = target[0].srcnode().abspath - f = open(src, "rb") - g = open(dst, "w") - buf = f.read() + with open(src, "rb") as f: + buf = f.read() - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef BOOT_SPLASH_H\n") - g.write("#define BOOT_SPLASH_H\n") - g.write('static const Color boot_splash_bg_color = Color::html("#232323");\n') - g.write("static const unsigned char boot_splash_png[] = {\n") - for i in range(len(buf)): - g.write(byte_to_str(buf[i]) + ",\n") - g.write("};\n") - g.write("#endif") + with open(dst, "w") as g: + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef BOOT_SPLASH_H\n") + g.write("#define BOOT_SPLASH_H\n") + g.write('static const Color boot_splash_bg_color = Color::html("#232323");\n') + g.write("static const unsigned char boot_splash_png[] = {\n") + for i in range(len(buf)): + g.write(byte_to_str(buf[i]) + ",\n") + g.write("};\n") + g.write("#endif") def make_splash_editor(target, source, env): src = source[0].srcnode().abspath dst = target[0].srcnode().abspath - f = open(src, "rb") - g = open(dst, "w") - buf = f.read() - - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef BOOT_SPLASH_EDITOR_H\n") - g.write("#define BOOT_SPLASH_EDITOR_H\n") - g.write('static const Color boot_splash_editor_bg_color = Color::html("#232323");\n') - g.write("static const unsigned char boot_splash_editor_png[] = {\n") - for i in range(len(buf)): - g.write(byte_to_str(buf[i]) + ",\n") - g.write("};\n") - g.write("#endif") + with open(src, "rb") as f: + buf = f.read() + with open(dst, "w") as g: + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef BOOT_SPLASH_EDITOR_H\n") + g.write("#define BOOT_SPLASH_EDITOR_H\n") + g.write('static const Color boot_splash_editor_bg_color = Color::html("#232323");\n') + g.write("static const unsigned char boot_splash_editor_png[] = {\n") + for i in range(len(buf)): + g.write(byte_to_str(buf[i]) + ",\n") + g.write("};\n") + g.write("#endif") def make_app_icon(target, source, env): src = source[0].srcnode().abspath dst = target[0].srcnode().abspath - f = open(src, "rb") - g = open(dst, "w") - - buf = f.read() - - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef APP_ICON_H\n") - g.write("#define APP_ICON_H\n") - g.write("static const unsigned char app_icon_png[] = {\n") - for i in range(len(buf)): - g.write(byte_to_str(buf[i]) + ",\n") - g.write("};\n") - g.write("#endif") + + with open(src, "rb") as f: + buf = f.read() + + with open(dst, "w") as g: + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef APP_ICON_H\n") + g.write("#define APP_ICON_H\n") + g.write("static const unsigned char app_icon_png[] = {\n") + for i in range(len(buf)): + g.write(byte_to_str(buf[i]) + ",\n") + g.write("};\n") + g.write("#endif") env.main_sources = [] diff --git a/methods.py b/methods.py index 42679610af..6f03f79be3 100644 --- a/methods.py +++ b/methods.py @@ -597,6 +597,9 @@ def parse_cg_file(fname, uniforms, sizes, conditionals): line = fs.readline() + fs.close() + + import glob @@ -644,8 +647,8 @@ void unregister_module_types() { } """ - f = open("modules/register_module_types.gen.cpp", "w") - f.write(modules_cpp) + with open("modules/register_module_types.gen.cpp", "w") as f: + f.write(modules_cpp) return module_list @@ -744,18 +747,18 @@ def android_add_default_config(self, config): def android_add_to_manifest(self, file): base_path = self.Dir(".").abspath + "/modules/" + self.current_module + "/" + file - f = open(base_path, "r") - self.android_manifest_chunk += f.read() + with open(base_path, "r") as f: + self.android_manifest_chunk += f.read() def android_add_to_permissions(self, file): base_path = self.Dir(".").abspath + "/modules/" + self.current_module + "/" + file - f = open(base_path, "r") - self.android_permission_chunk += f.read() + with open(base_path, "r") as f: + self.android_permission_chunk += f.read() def android_add_to_attributes(self, file): base_path = self.Dir(".").abspath + "/modules/" + self.current_module + "/" + file - f = open(base_path, "r") - self.android_appattributes_chunk += f.read() + with open(base_path, "r") as f: + self.android_appattributes_chunk += f.read() def disable_module(self): self.disabled_modules.append(self.current_module) @@ -886,9 +889,11 @@ def save_active_platforms(apnames, ap): str += "};\n" + pngf.close() + wf = x + "/" + name + ".gen.h" - pngw = open(wf, "w") - pngw.write(str) + with open(wf, "w") as pngw: + pngw.write(str) def no_verbose(sys, env): @@ -1048,8 +1053,8 @@ def generate_cpp_hint_file(filename): pass else: try: - fd = open(filename, "w") - fd.write("#define GDCLASS(m_class, m_inherits)\n") + with open(filename, "w") as fd: + fd.write("#define GDCLASS(m_class, m_inherits)\n") except IOError: print("Could not write cpp.hint file.") diff --git a/misc/scripts/fix_headers.py b/misc/scripts/fix_headers.py index 809820c20f..48b9628b1f 100644 --- a/misc/scripts/fix_headers.py +++ b/misc/scripts/fix_headers.py @@ -92,9 +92,11 @@ while (fname != ""): fileread.close() # Write - fileread = open(fname.strip(), "wb") - fileread.write(text) - fileread.close() + filewrite = open(fname.strip(), "wb") + filewrite.write(text) + filewrite.close() # Next file fname = files.readline() + +files.close()
\ No newline at end of file diff --git a/misc/scripts/make_glwrapper.py b/misc/scripts/make_glwrapper.py index 5694d2327e..15b66a950b 100644 --- a/misc/scripts/make_glwrapper.py +++ b/misc/scripts/make_glwrapper.py @@ -16,9 +16,7 @@ READ_CONSTANTS = 2 read_what = READ_TYPES -for x in (range(len(sys.argv) - 1)): - f = open(sys.argv[x + 1], "r") - +def read_file(f): while(True): line = f.readline() @@ -86,6 +84,9 @@ for x in (range(len(sys.argv) - 1)): functions.append(funcdata) print(funcdata) +for path in sys.argv[1:]: + with open(path, "r") as f: + read_file(f) # print(types) # print(constants) @@ -156,6 +157,7 @@ f.write("void glWrapperInit( GLWrapperFuncPtr (*wrapperFunc)(const char*) );\n") f.write("#ifdef __cplusplus\n}\n#endif\n") f.write("#endif\n\n") +f.close() f = open("glwrapper.c", "w") @@ -176,3 +178,4 @@ for x in functions: f.write("\n\n") f.write("}\n") f.write("\n\n") +f.close() diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp index 3cc362b5d6..d592c19b97 100644 --- a/modules/hdr/image_loader_hdr.cpp +++ b/modules/hdr/image_loader_hdr.cpp @@ -42,14 +42,18 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force ERR_FAIL_COND_V(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED); while (true) { - String format = f->get_token(); + String line = f->get_line(); ERR_FAIL_COND_V(f->eof_reached(), ERR_FILE_UNRECOGNIZED); - if (format.begins_with("FORMAT=") && format != "FORMAT=32-bit_rle_rgbe") { - ERR_EXPLAIN("Only 32-bit_rle_rgbe is supported for .hdr files."); - return ERR_FILE_UNRECOGNIZED; - } - if (format == "FORMAT=32-bit_rle_rgbe") + if (line == "") // empty line indicates end of header break; + if (line.begins_with("FORMAT=")) { // leave option to implement other commands + if (line != "FORMAT=32-bit_rle_rgbe") { + ERR_EXPLAIN("Only 32-bit_rle_rgbe is supported for HDR files."); + return ERR_FILE_UNRECOGNIZED; + } + } else if (!line.begins_with("#")) { // not comment + WARN_PRINTS("Ignoring unsupported header information in HDR : " + line); + } } String token = f->get_token(); diff --git a/modules/webm/SCsub b/modules/webm/SCsub index 2f1a28a54c..33561da098 100644 --- a/modules/webm/SCsub +++ b/modules/webm/SCsub @@ -18,6 +18,10 @@ thirdparty_libsimplewebm_sources = [thirdparty_libsimplewebm_dir + file for file env_webm.add_source_files(env.modules_sources, thirdparty_libsimplewebm_sources) env_webm.Append(CPPPATH=[thirdparty_libsimplewebm_dir, thirdparty_libsimplewebm_dir + "libwebm/"]) +# upstream uses c++11 +if (not env_webm.msvc): + env_webm.Append(CCFLAGS="-std=c++11") + # also requires libogg, libvorbis and libopus if env['builtin_libogg']: env_webm.Append(CPPPATH=["#thirdparty/libogg"]) diff --git a/platform/SCsub b/platform/SCsub index e624f8e90f..2019a30be7 100644 --- a/platform/SCsub +++ b/platform/SCsub @@ -18,11 +18,10 @@ for platform in env.platform_apis: reg_apis_inc += '\n' reg_apis += '}\n\n' unreg_apis += '}\n' -f = open_utf8('register_platform_apis.gen.cpp', 'w') -f.write(reg_apis_inc) -f.write(reg_apis) -f.write(unreg_apis) -f.close() +with open_utf8('register_platform_apis.gen.cpp', 'w') as f: + f.write(reg_apis_inc) + f.write(reg_apis) + f.write(unreg_apis) platform_sources.append('register_platform_apis.gen.cpp') lib = env.add_library('platform', platform_sources) diff --git a/platform/android/SCsub b/platform/android/SCsub index d2285a82dd..8c08289932 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -41,10 +41,8 @@ prog = None abspath = env.Dir(".").abspath -gradle_basein = open_utf8(abspath + "/build.gradle.template", "r") -gradle_baseout = open_utf8(abspath + "/java/build.gradle", "w") - -gradle_text = gradle_basein.read() +with open_utf8(abspath + "/build.gradle.template", "r") as gradle_basein: + gradle_text = gradle_basein.read() gradle_maven_flat_text = "" if len(env.android_flat_dirs) > 0: @@ -131,17 +129,19 @@ gradle_text = gradle_text.replace("$$GRADLE_DEFAULT_CONFIG$$", gradle_default_co gradle_text = gradle_text.replace("$$GRADLE_PLUGINS$$", gradle_plugins) gradle_text = gradle_text.replace("$$GRADLE_CLASSPATH$$", gradle_classpath) -gradle_baseout.write(gradle_text) -gradle_baseout.close() +with open_utf8(abspath + "/java/build.gradle", "w") as gradle_baseout: + gradle_baseout.write(gradle_text) + +with open_utf8(abspath + "/AndroidManifest.xml.template", "r") as pp_basein: + manifest = pp_basein.read() -pp_basein = open_utf8(abspath + "/AndroidManifest.xml.template", "r") -pp_baseout = open_utf8(abspath + "/java/AndroidManifest.xml", "w") -manifest = pp_basein.read() manifest = manifest.replace("$$ADD_APPLICATION_CHUNKS$$", env.android_manifest_chunk) manifest = manifest.replace("$$ADD_PERMISSION_CHUNKS$$", env.android_permission_chunk) manifest = manifest.replace("$$ADD_APPATTRIBUTE_CHUNKS$$", env.android_appattributes_chunk) -pp_baseout.write(manifest) + +with open_utf8(abspath + "/java/AndroidManifest.xml", "w") as pp_baseout: + pp_baseout.write(manifest) lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"]) diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h index d205c7da83..d9fd61fb6e 100644 --- a/platform/iphone/platform_config.h +++ b/platform/iphone/platform_config.h @@ -30,6 +30,7 @@ #include <alloca.h> +#define GLES2_INCLUDE_H <ES2/gl.h> #define GLES3_INCLUDE_H <ES3/gl.h> #define PLATFORM_REFCOUNT diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index 0dd02a982c..67f016ae79 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -121,7 +121,15 @@ void Sprite::set_texture(const Ref<Texture> &p_texture) { if (p_texture == texture) return; + + if (texture.is_valid()) + texture->remove_change_receptor(this); + texture = p_texture; + + if (texture.is_valid()) + texture->add_change_receptor(this); + update(); emit_signal("texture_changed"); item_rect_changed(); @@ -281,13 +289,39 @@ bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc Rect2 src_rect, dst_rect; bool filter_clip; _get_rects(src_rect, dst_rect, filter_clip); + dst_rect.size = dst_rect.size.abs(); if (!dst_rect.has_point(p_point)) return false; - Vector2 q = ((p_point - dst_rect.position) / dst_rect.size) * src_rect.size + src_rect.position; + Vector2 q = (p_point - dst_rect.position) / dst_rect.size; + if (hflip) + q.x = 1.0f - q.x; + if (vflip) + q.y = 1.0f - q.y; + q = q * src_rect.size + src_rect.position; + + Ref<Image> image; + Ref<AtlasTexture> atlasTexture = texture; + if (atlasTexture.is_null()) { + image = texture->get_data(); + } else { + ERR_FAIL_COND_V(atlasTexture->get_atlas().is_null(), false); + + image = atlasTexture->get_atlas()->get_data(); + + Rect2 region = atlasTexture->get_region(); + Rect2 margin = atlasTexture->get_margin(); + + q -= margin.position; + + if ((q.x > region.size.width) || (q.y > region.size.height)) { + return false; + } + + q += region.position; + } - Ref<Image> image = texture->get_data(); ERR_FAIL_COND_V(image.is_null(), false); image->lock(); @@ -336,6 +370,15 @@ void Sprite::_validate_property(PropertyInfo &property) const { } } +void Sprite::_changed_callback(Object *p_changed, const char *p_prop) { + + // Changes to the texture need to trigger an update to make + // the editor redraw the sprite with the updated texture. + if (texture.is_valid() && texture.ptr() == p_changed) { + update(); + } +} + void Sprite::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite::set_texture); @@ -410,3 +453,8 @@ Sprite::Sprite() { vframes = 1; hframes = 1; } + +Sprite::~Sprite() { + if (texture.is_valid()) + texture->remove_change_receptor(this); +} diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h index dd3719099f..abd04515ec 100644 --- a/scene/2d/sprite.h +++ b/scene/2d/sprite.h @@ -64,6 +64,8 @@ protected: virtual void _validate_property(PropertyInfo &property) const; + virtual void _changed_callback(Object *p_changed, const char *p_prop); + public: virtual Dictionary _edit_get_state() const; virtual void _edit_set_state(const Dictionary &p_state); @@ -113,6 +115,7 @@ public: Rect2 get_rect() const; Sprite(); + ~Sprite(); }; #endif // SPRITE_H diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 2aa55e2825..3af77bfcc7 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -142,16 +142,20 @@ void TileMap::_update_quadrant_transform() { void TileMap::set_tileset(const Ref<TileSet> &p_tileset) { - if (tile_set.is_valid()) + if (tile_set.is_valid()) { tile_set->disconnect("changed", this, "_recreate_quadrants"); + tile_set->remove_change_receptor(this); + } _clear_quadrants(); tile_set = p_tileset; - if (tile_set.is_valid()) + if (tile_set.is_valid()) { tile_set->connect("changed", this, "_recreate_quadrants"); - else + tile_set->add_change_receptor(this); + } else { clear(); + } _recreate_quadrants(); emit_signal("settings_changed"); @@ -1573,6 +1577,12 @@ void TileMap::_bind_methods() { BIND_ENUM_CONSTANT(TILE_ORIGIN_BOTTOM_LEFT); } +void TileMap::_changed_callback(Object *p_changed, const char *p_prop) { + if (tile_set.is_valid() && tile_set.ptr() == p_changed) { + emit_signal("settings_changed"); + } +} + TileMap::TileMap() { rect_cache_dirty = true; @@ -1601,5 +1611,8 @@ TileMap::TileMap() { TileMap::~TileMap() { + if (tile_set.is_valid()) + tile_set->remove_change_receptor(this); + clear(); } diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 973e527b42..104842d52f 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -217,6 +217,8 @@ protected: void _notification(int p_what); static void _bind_methods(); + virtual void _changed_callback(Object *p_changed, const char *p_prop); + public: enum { INVALID_CELL = -1 diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 9db4a5fb04..04e7d5cc10 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1010,6 +1010,7 @@ void AnimationPlayer::stop(bool p_reset) { c.blend.clear(); if (p_reset) { c.current.from = NULL; + c.current.speed_scale = 1; } _set_process(false); queued.clear(); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 30bcc48149..31be18612f 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -77,8 +77,7 @@ void ColorPicker::_notification(int p_what) { void ColorPicker::set_focus_on_line_edit() { - c_text->grab_focus(); - c_text->select(); + c_text->call_deferred("grab_focus"); } void ColorPicker::_update_controls() { @@ -159,14 +158,16 @@ void ColorPicker::_update_color() { updating = true; for (int i = 0; i < 4; i++) { - scroll[i]->set_max(255); scroll[i]->set_step(0.01); if (raw_mode_enabled) { + scroll[i]->set_max(100); if (i == 3) scroll[i]->set_max(1); scroll[i]->set_value(color.components[i]); } else { - scroll[i]->set_value(color.components[i] * 255); + const int byte_value = color.components[i] * 255; + scroll[i]->set_max(next_power_of_2(MAX(255, byte_value)) - 1); + scroll[i]->set_value(byte_value); } } @@ -242,6 +243,7 @@ bool ColorPicker::is_raw_mode() const { } void ColorPicker::_update_text_value() { + bool visible = true; if (text_is_constructor) { String t = "Color(" + String::num(color.r) + "," + String::num(color.g) + "," + String::num(color.b); if (edit_alpha && color.a < 1) @@ -250,8 +252,13 @@ void ColorPicker::_update_text_value() { t += ")"; c_text->set_text(t); } else { - c_text->set_text(color.to_html(edit_alpha && color.a < 1)); + if (color.r > 1 || color.g > 1 || color.b > 1 || color.r < 0 || color.g < 0 || color.b < 0) { + visible = false; + } else { + c_text->set_text(color.to_html(edit_alpha && color.a < 1)); + } } + c_text->set_visible(visible); } void ColorPicker::_sample_draw() { @@ -462,6 +469,31 @@ void ColorPicker::_screen_pick_pressed() { screen->show_modal(); } +void ColorPicker::_focus_enter() { + if (c_text->has_focus()) { + c_text->select_all(); + return; + } + for (int i = 0; i < 4; i++) { + if (values[i]->get_line_edit()->has_focus()) { + values[i]->get_line_edit()->select_all(); + break; + } + } +} + +void ColorPicker::_focus_exit() { + for (int i = 0; i < 4; i++) { + values[i]->get_line_edit()->select(0, 0); + } + c_text->select(0, 0); +} + +void ColorPicker::_html_focus_exit() { + _html_entered(c_text->get_text()); + _focus_exit(); +} + void ColorPicker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPicker::set_pick_color); @@ -483,6 +515,9 @@ void ColorPicker::_bind_methods() { ClassDB::bind_method(D_METHOD("_w_input"), &ColorPicker::_w_input); ClassDB::bind_method(D_METHOD("_preset_input"), &ColorPicker::_preset_input); ClassDB::bind_method(D_METHOD("_screen_input"), &ColorPicker::_screen_input); + ClassDB::bind_method(D_METHOD("_focus_enter"), &ColorPicker::_focus_enter); + ClassDB::bind_method(D_METHOD("_focus_exit"), &ColorPicker::_focus_exit); + ClassDB::bind_method(D_METHOD("_html_focus_exit"), &ColorPicker::_html_focus_exit); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha"); @@ -559,11 +594,14 @@ ColorPicker::ColorPicker() : scroll[i] = memnew(HSlider); scroll[i]->set_v_size_flags(SIZE_SHRINK_CENTER); + scroll[i]->set_focus_mode(FOCUS_NONE); hbc->add_child(scroll[i]); values[i] = memnew(SpinBox); scroll[i]->share(values[i]); hbc->add_child(values[i]); + values[i]->get_line_edit()->connect("focus_entered", this, "_focus_enter"); + values[i]->get_line_edit()->connect("focus_exited", this, "_focus_exit"); scroll[i]->set_min(0); scroll[i]->set_page(0); @@ -589,6 +627,9 @@ ColorPicker::ColorPicker() : c_text = memnew(LineEdit); hhb->add_child(c_text); c_text->connect("text_entered", this, "_html_entered"); + c_text->connect("focus_entered", this, "_focus_enter"); + c_text->connect("focus_exited", this, "_html_focus_exit"); + text_type->set_text("#"); c_text->set_h_size_flags(SIZE_EXPAND_FILL); diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 01ae1cc464..40ded4fff5 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -88,6 +88,9 @@ private: void _screen_input(const Ref<InputEvent> &p_event); void _add_preset_pressed(); void _screen_pick_pressed(); + void _focus_enter(); + void _focus_exit(); + void _html_focus_exit(); protected: void _notification(int); diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index c2b8a7dfab..9948672097 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -36,10 +36,10 @@ void GridContainer::_notification(int p_what) { case NOTIFICATION_SORT_CHILDREN: { - Map<int, int> col_minw; - Map<int, int> row_minh; - Set<int> col_expanded; - Set<int> row_expanded; + Map<int, int> col_minw; // max of min_width of all controls in each col (indexed by col) + Map<int, int> row_minh; // max of min_height of all controls in each row (indexed by row) + Set<int> col_expanded; // columns which have the SIZE_EXPAND flag set + Set<int> row_expanded; // rows which have the SIZE_EXPAND flag set int hsep = get_constant("hseparation"); int vsep = get_constant("vseparation"); @@ -88,13 +88,13 @@ void GridContainer::_notification(int p_what) { remaining_space.width -= hsep * (max_col - 1); bool can_fit = false; - while (!can_fit) { + while (!can_fit && col_expanded.size() > 0) { // Check if all minwidth constraints are ok if we use the remaining space can_fit = true; - int max_index = 0; + int max_index = col_expanded.front()->get(); for (Set<int>::Element *E = col_expanded.front(); E; E = E->next()) { if (col_minw[E->get()] > col_minw[max_index]) { - max_index = col_minw[E->get()]; + max_index = E->get(); } if (can_fit && (remaining_space.width / col_expanded.size()) < col_minw[E->get()]) { can_fit = false; @@ -109,13 +109,13 @@ void GridContainer::_notification(int p_what) { } can_fit = false; - while (!can_fit) { + while (!can_fit && row_expanded.size() > 0) { // Check if all minwidth constraints are ok if we use the remaining space can_fit = true; - int max_index = 0; + int max_index = row_expanded.front()->get(); for (Set<int>::Element *E = row_expanded.front(); E; E = E->next()) { if (row_minh[E->get()] > row_minh[max_index]) { - max_index = row_minh[E->get()]; + max_index = E->get(); } if (can_fit && (remaining_space.height / row_expanded.size()) < row_minh[E->get()]) { can_fit = false; @@ -130,8 +130,8 @@ void GridContainer::_notification(int p_what) { } // Finally, fit the nodes - int col_expand = remaining_space.width / col_expanded.size(); - int row_expand = remaining_space.height / row_expanded.size(); + int col_expand = col_expanded.size() > 0 ? remaining_space.width / col_expanded.size() : 0; + int row_expand = row_expanded.size() > 0 ? remaining_space.height / row_expanded.size() : 0; int col_ofs = 0; int row_ofs = 0; diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index f7574ca2cd..50041ffd89 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -1465,6 +1465,8 @@ void ItemList::_bind_methods() { ClassDB::bind_method(D_METHOD("set_auto_height", "enable"), &ItemList::set_auto_height); ClassDB::bind_method(D_METHOD("has_auto_height"), &ItemList::has_auto_height); + ClassDB::bind_method(D_METHOD("is_anything_selected"), &ItemList::is_anything_selected); + ClassDB::bind_method(D_METHOD("get_item_at_position", "position", "exact"), &ItemList::get_item_at_position, DEFVAL(false)); ClassDB::bind_method(D_METHOD("ensure_current_is_visible"), &ItemList::ensure_current_is_visible); diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp index 4a419098a0..4b3ba6df3c 100644 --- a/scene/gui/texture_progress.cpp +++ b/scene/gui/texture_progress.cpp @@ -117,22 +117,45 @@ Point2 TextureProgress::unit_val_to_uv(float val) { Point2 p = get_relative_center(); - if (val < 0.125) - return Point2(p.x + (1 - p.x) * val * 8, 0); - if (val < 0.25) - return Point2(1, p.y * (val - 0.125) * 8); - if (val < 0.375) - return Point2(1, p.y + (1 - p.y) * (val - 0.25) * 8); - if (val < 0.5) - return Point2(1 - (1 - p.x) * (val - 0.375) * 8, 1); - if (val < 0.625) - return Point2(p.x * (1 - (val - 0.5) * 8), 1); - if (val < 0.75) - return Point2(0, 1 - ((1 - p.y) * (val - 0.625) * 8)); - if (val < 0.875) - return Point2(0, p.y - p.y * (val - 0.75) * 8); - else - return Point2(p.x * (val - 0.875) * 8, 0); + // Minimal version of Liang-Barsky clipping algorithm + float angle = (val * Math_TAU) - Math_PI * 0.5; + Point2 dir = Vector2(Math::cos(angle), Math::sin(angle)); + float t1 = 1.0; + float cp; + float cq; + float cr; + float edgeLeft = 0.0; + float edgeRight = 1.0; + float edgeBottom = 0.0; + float edgeTop = 1.0; + + for (int edge = 0; edge < 4; edge++) { + if (edge == 0) { + if (dir.x > 0) + continue; + cp = -dir.x; + cq = -(edgeLeft - p.x); + } else if (edge == 1) { + if (dir.x < 0) + continue; + cp = dir.x; + cq = (edgeRight - p.x); + } else if (edge == 2) { + if (dir.y > 0) + continue; + cp = -dir.y; + cq = -(edgeBottom - p.y); + } else if (edge == 3) { + if (dir.y < 0) + continue; + cp = dir.y; + cq = (edgeTop - p.y); + } + cr = cq / cp; + if (cr >= 0 && cr < t1) + t1 = cr; + } + return (p + t1 * dir); } Point2 TextureProgress::get_relative_center() { diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp index 7fba8acebd..d49c1b8376 100644 --- a/servers/physics_2d/joints_2d_sw.cpp +++ b/servers/physics_2d/joints_2d_sw.cpp @@ -146,14 +146,19 @@ bool PinJoint2DSW::setup(real_t p_step) { return true; } +inline Vector2 custom_cross(const Vector2 &p_vec, real_t p_other) { + + return Vector2(p_other * p_vec.y, -p_other * p_vec.x); +} + void PinJoint2DSW::solve(real_t p_step) { // compute relative velocity - Vector2 vA = A->get_linear_velocity() - rA.cross(A->get_angular_velocity()); + Vector2 vA = A->get_linear_velocity() - custom_cross(rA, A->get_angular_velocity()); Vector2 rel_vel; if (B) - rel_vel = B->get_linear_velocity() - rB.cross(B->get_angular_velocity()) - vA; + rel_vel = B->get_linear_velocity() - custom_cross(rB, B->get_angular_velocity()) - vA; else rel_vel = -vA; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 1f66b0ba9d..f5c926c093 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -124,6 +124,9 @@ const char *ShaderLanguage::token_names[TK_MAX] = { "TYPE_ISAMPLER2D", "TYPE_USAMPLER2D", "TYPE_SAMPLERCUBE", + "INTERPOLATION_FLAT", + "INTERPOLATION_NO_PERSPECTIVE", + "INTERPOLATION_SMOOTH", "PRECISION_LOW", "PRECISION_MID", "PRECISION_HIGH", @@ -1608,7 +1611,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } }, { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } }, { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_BOOL, TYPE_VOID } }, - { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_BVEC3, TYPE_VOID } }, + { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_BVEC4, TYPE_VOID } }, { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID } }, { "step", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID } }, diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 64a3502e40..fca3126604 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -205,4 +205,5 @@ VisualServerRaster::~VisualServerRaster() { memdelete(VSG::canvas); memdelete(VSG::viewport); memdelete(VSG::rasterizer); + memdelete(VSG::scene); } diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 0920fa748b..884489375f 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -3333,6 +3333,7 @@ VisualServerScene::~VisualServerScene() { #ifndef NO_THREADS probe_bake_thread_exit = true; + probe_bake_sem->post(); Thread::wait_to_finish(probe_bake_thread); memdelete(probe_bake_thread); memdelete(probe_bake_sem); diff --git a/thirdparty/libsimplewebm/libwebm/README.libvpx b/thirdparty/libsimplewebm/libwebm/README.libvpx index ae62f36525..1aa93b75aa 100644 --- a/thirdparty/libsimplewebm/libwebm/README.libvpx +++ b/thirdparty/libsimplewebm/libwebm/README.libvpx @@ -1,5 +1,5 @@ URL: https://chromium.googlesource.com/webm/libwebm -Version: 32d5ac49414a8914ec1e1f285f3f927c6e8ec29d +Version: d7c62173ff6b4a5e0a2f86683a5b67db98cf09bf License: BSD License File: LICENSE.txt diff --git a/thirdparty/libsimplewebm/libwebm/common/webmids.h b/thirdparty/libsimplewebm/libwebm/common/webmids.h index 32a0c5fb91..89d722a71b 100644 --- a/thirdparty/libsimplewebm/libwebm/common/webmids.h +++ b/thirdparty/libsimplewebm/libwebm/common/webmids.h @@ -124,6 +124,14 @@ enum MkvId { kMkvLuminanceMin = 0x55DA, // end mastering metadata // end colour + // projection + kMkvProjection = 0x7670, + kMkvProjectionType = 0x7671, + kMkvProjectionPrivate = 0x7672, + kMkvProjectionPoseYaw = 0x7673, + kMkvProjectionPosePitch = 0x7674, + kMkvProjectionPoseRoll = 0x7675, + // end projection // audio kMkvAudio = 0xE1, kMkvSamplingFrequency = 0xB5, diff --git a/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.cc b/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.cc index d2375edb3b..e7b76f7da1 100644 --- a/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.cc +++ b/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.cc @@ -12,51 +12,30 @@ #define MSC_COMPAT #endif -#include <assert.h> -#include <float.h> -#include <limits.h> -#include <math.h> -#include <string.h> +#include <cassert> +#include <cfloat> +#include <climits> +#include <cmath> +#include <cstring> +#include <memory> +#include <new> #include "common/webmids.h" namespace mkvparser { +const long long kStringElementSizeLimit = 20 * 1000 * 1000; const float MasteringMetadata::kValueNotPresent = FLT_MAX; const long long Colour::kValueNotPresent = LLONG_MAX; +const float Projection::kValueNotPresent = FLT_MAX; #ifdef MSC_COMPAT inline bool isnan(double val) { return !!_isnan(val); } inline bool isinf(double val) { return !_finite(val); } +#else +inline bool isnan(double val) { return std::isnan(val); } +inline bool isinf(double val) { return std::isinf(val); } #endif // MSC_COMPAT -template<typename T> -class my_auto_ptr { - my_auto_ptr(const my_auto_ptr &); - T *operator =(const my_auto_ptr &); - - T *m_ptr; -public: - my_auto_ptr(T *ptr) : - m_ptr(ptr) - {} - my_auto_ptr() : - m_ptr(NULL) - {} - ~my_auto_ptr() { - delete m_ptr; - } - - T *release() { - T *ptr = m_ptr; - m_ptr = NULL; - return ptr; - } - - T *operator ->() const { - return m_ptr; - } -}; - IMkvReader::~IMkvReader() {} template <typename Type> @@ -72,7 +51,7 @@ Type* SafeArrayAlloc(unsigned long long num_elements, if (num_bytes != static_cast<size_t>(num_bytes)) return NULL; - return new Type[static_cast<size_t>(num_bytes)]; + return new (std::nothrow) Type[static_cast<size_t>(num_bytes)]; } void GetVersion(int& major, int& minor, int& build, int& revision) { @@ -304,7 +283,7 @@ long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_, result = d; } - if (isinf(result) || isnan(result)) + if (mkvparser::isinf(result) || mkvparser::isnan(result)) return E_FILE_FORMAT_INVALID; return 0; @@ -347,7 +326,7 @@ long UnserializeString(IMkvReader* pReader, long long pos, long long size, delete[] str; str = NULL; - if (size >= LONG_MAX || size < 0) + if (size >= LONG_MAX || size < 0 || size > kStringElementSizeLimit) return E_FILE_FORMAT_INVALID; // +1 for '\0' terminator @@ -818,7 +797,9 @@ long long Segment::CreateInstance(IMkvReader* pReader, long long pos, else if ((pos + size) > total) size = -1; - pSegment = new Segment(pReader, idpos, pos, size); + pSegment = new (std::nothrow) Segment(pReader, idpos, pos, size); + if (pSegment == NULL) + return E_PARSE_FAILED; return 0; // success } @@ -954,7 +935,11 @@ long long Segment::ParseHeaders() { if (m_pInfo) return E_FILE_FORMAT_INVALID; - m_pInfo = new SegmentInfo(this, pos, size, element_start, element_size); + m_pInfo = new (std::nothrow) + SegmentInfo(this, pos, size, element_start, element_size); + + if (m_pInfo == NULL) + return -1; const long status = m_pInfo->Parse(); @@ -964,7 +949,11 @@ long long Segment::ParseHeaders() { if (m_pTracks) return E_FILE_FORMAT_INVALID; - m_pTracks = new Tracks(this, pos, size, element_start, element_size); + m_pTracks = new (std::nothrow) + Tracks(this, pos, size, element_start, element_size); + + if (m_pTracks == NULL) + return -1; const long status = m_pTracks->Parse(); @@ -972,11 +961,19 @@ long long Segment::ParseHeaders() { return status; } else if (id == libwebm::kMkvCues) { if (m_pCues == NULL) { - m_pCues = new Cues(this, pos, size, element_start, element_size); + m_pCues = new (std::nothrow) + Cues(this, pos, size, element_start, element_size); + + if (m_pCues == NULL) + return -1; } } else if (id == libwebm::kMkvSeekHead) { if (m_pSeekHead == NULL) { - m_pSeekHead = new SeekHead(this, pos, size, element_start, element_size); + m_pSeekHead = new (std::nothrow) + SeekHead(this, pos, size, element_start, element_size); + + if (m_pSeekHead == NULL) + return -1; const long status = m_pSeekHead->Parse(); @@ -985,7 +982,11 @@ long long Segment::ParseHeaders() { } } else if (id == libwebm::kMkvChapters) { if (m_pChapters == NULL) { - m_pChapters = new Chapters(this, pos, size, element_start, element_size); + m_pChapters = new (std::nothrow) + Chapters(this, pos, size, element_start, element_size); + + if (m_pChapters == NULL) + return -1; const long status = m_pChapters->Parse(); @@ -994,7 +995,11 @@ long long Segment::ParseHeaders() { } } else if (id == libwebm::kMkvTags) { if (m_pTags == NULL) { - m_pTags = new Tags(this, pos, size, element_start, element_size); + m_pTags = new (std::nothrow) + Tags(this, pos, size, element_start, element_size); + + if (m_pTags == NULL) + return -1; const long status = m_pTags->Parse(); @@ -1136,7 +1141,9 @@ long Segment::DoLoadCluster(long long& pos, long& len) { if (m_pCues == NULL) { const long long element_size = (pos - idpos) + size; - m_pCues = new Cues(this, pos, size, idpos, element_size); + m_pCues = new (std::nothrow) Cues(this, pos, size, idpos, element_size); + if (m_pCues == NULL) + return -1; } m_pos = pos + size; // consume payload @@ -1284,9 +1291,7 @@ long Segment::DoLoadCluster(long long& pos, long& len) { pos += cluster_size; m_pos = pos; - // -- GODOT start -- - delete pCluster; - // -- GODOT end -- + if (segment_stop > 0 && m_pos > segment_stop) return E_FILE_FORMAT_INVALID; @@ -1344,7 +1349,9 @@ bool Segment::AppendCluster(Cluster* pCluster) { if (count >= size) { const long n = (size <= 0) ? 2048 : 2 * size; - Cluster** const qq = new Cluster*[n]; + Cluster** const qq = new (std::nothrow) Cluster*[n]; + if (qq == NULL) + return false; Cluster** q = qq; Cluster** p = m_clusters; @@ -1399,7 +1406,9 @@ bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) { if (count >= size) { const long n = (size <= 0) ? 2048 : 2 * size; - Cluster** const qq = new Cluster*[n]; + Cluster** const qq = new (std::nothrow) Cluster*[n]; + if (qq == NULL) + return false; Cluster** q = qq; Cluster** p = m_clusters; @@ -1468,6 +1477,8 @@ long Segment::Load() { } } +SeekHead::Entry::Entry() : id(0), pos(0), element_start(0), element_size(0) {} + SeekHead::SeekHead(Segment* pSegment, long long start, long long size_, long long element_start, long long element_size) : m_pSegment(pSegment), @@ -1518,9 +1529,19 @@ long SeekHead::Parse() { if (pos != stop) return E_FILE_FORMAT_INVALID; - m_entries = new Entry[entry_count]; + if (entry_count > 0) { + m_entries = new (std::nothrow) Entry[entry_count]; - m_void_elements = new VoidElement[void_element_count]; + if (m_entries == NULL) + return -1; + } + + if (void_element_count > 0) { + m_void_elements = new (std::nothrow) VoidElement[void_element_count]; + + if (m_void_elements == NULL) + return -1; + } // now parse the entries and void elements @@ -1539,14 +1560,14 @@ long SeekHead::Parse() { if (status < 0) // error return status; - if (id == libwebm::kMkvSeek) { + if (id == libwebm::kMkvSeek && entry_count > 0) { if (ParseEntry(pReader, pos, size, pEntry)) { Entry& e = *pEntry++; e.element_start = idpos; e.element_size = (pos + size) - idpos; } - } else if (id == libwebm::kMkvVoid) { + } else if (id == libwebm::kMkvVoid && void_element_count > 0) { VoidElement& e = *pVoidElement++; e.element_start = idpos; @@ -1708,7 +1729,10 @@ long Segment::ParseCues(long long off, long long& pos, long& len) { const long long element_size = element_stop - element_start; - m_pCues = new Cues(this, pos, size, element_start, element_size); + m_pCues = + new (std::nothrow) Cues(this, pos, size, element_start, element_size); + if (m_pCues == NULL) + return -1; return 0; // success } @@ -1750,18 +1774,7 @@ bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_, if ((pos + seekIdSize) > stop) return false; - // Note that the SeekId payload really is serialized - // as a "Matroska integer", not as a plain binary value. - // In fact, Matroska requires that ID values in the - // stream exactly match the binary representation as listed - // in the Matroska specification. - // - // This parser is more liberal, and permits IDs to have - // any width. (This could make the representation in the stream - // different from what's in the spec, but it doesn't matter here, - // since we always normalize "Matroska integer" values.) - - pEntry->id = ReadUInt(pReader, pos, len); // payload + pEntry->id = ReadID(pReader, pos, len); // payload if (pEntry->id <= 0) return false; @@ -1900,7 +1913,9 @@ bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const { if (m_preload_count >= cue_points_size) { const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size; - CuePoint** const qq = new CuePoint*[n]; + CuePoint** const qq = new (std::nothrow) CuePoint*[n]; + if (qq == NULL) + return false; CuePoint** q = qq; // beginning of target @@ -1916,7 +1931,9 @@ bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const { cue_points_size = n; } - CuePoint* const pCP = new CuePoint(m_preload_count, pos); + CuePoint* const pCP = new (std::nothrow) CuePoint(m_preload_count, pos); + if (pCP == NULL) + return false; m_cue_points[m_preload_count++] = pCP; return true; @@ -2322,7 +2339,9 @@ bool CuePoint::Load(IMkvReader* pReader) { // << " timecode=" << m_timecode // << endl; - m_track_positions = new TrackPosition[m_track_positions_count]; + m_track_positions = new (std::nothrow) TrackPosition[m_track_positions_count]; + if (m_track_positions == NULL) + return false; // Now parse track positions @@ -2412,7 +2431,9 @@ bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_, } const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const { - assert(pTrack); + if (pTrack == NULL) { + return NULL; + } const long long n = pTrack->GetNumber(); @@ -2917,7 +2938,10 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) { const long long element_size = element_stop - element_start; if (m_pCues == NULL) { - m_pCues = new Cues(this, pos, size, element_start, element_size); + m_pCues = new (std::nothrow) + Cues(this, pos, size, element_start, element_size); + if (m_pCues == NULL) + return false; } pos += size; // consume payload @@ -3268,7 +3292,10 @@ bool Chapters::ExpandEditionsArray() { const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size; - Edition* const editions = new Edition[size]; + Edition* const editions = new (std::nothrow) Edition[size]; + + if (editions == NULL) + return false; for (int idx = 0; idx < m_editions_count; ++idx) { m_editions[idx].ShallowCopy(editions[idx]); @@ -3380,7 +3407,10 @@ bool Chapters::Edition::ExpandAtomsArray() { const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size; - Atom* const atoms = new Atom[size]; + Atom* const atoms = new (std::nothrow) Atom[size]; + + if (atoms == NULL) + return false; for (int idx = 0; idx < m_atoms_count; ++idx) { m_atoms[idx].ShallowCopy(atoms[idx]); @@ -3565,7 +3595,10 @@ bool Chapters::Atom::ExpandDisplaysArray() { const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size; - Display* const displays = new Display[size]; + Display* const displays = new (std::nothrow) Display[size]; + + if (displays == NULL) + return false; for (int idx = 0; idx < m_displays_count; ++idx) { m_displays[idx].ShallowCopy(displays[idx]); @@ -3725,7 +3758,10 @@ bool Tags::ExpandTagsArray() { const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size; - Tag* const tags = new Tag[size]; + Tag* const tags = new (std::nothrow) Tag[size]; + + if (tags == NULL) + return false; for (int idx = 0; idx < m_tags_count; ++idx) { m_tags[idx].ShallowCopy(tags[idx]); @@ -3836,7 +3872,10 @@ bool Tags::Tag::ExpandSimpleTagsArray() { const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size; - SimpleTag* const displays = new SimpleTag[size]; + SimpleTag* const displays = new (std::nothrow) SimpleTag[size]; + + if (displays == NULL) + return false; for (int idx = 0; idx < m_simple_tags_count; ++idx) { m_simple_tags[idx].ShallowCopy(displays[idx]); @@ -3994,7 +4033,7 @@ long SegmentInfo::Parse() { } const double rollover_check = m_duration * m_timecodeScale; - if (rollover_check > LLONG_MAX) + if (rollover_check > static_cast<double>(LLONG_MAX)) return E_FILE_FORMAT_INVALID; if (pos != stop) @@ -4085,7 +4124,7 @@ ContentEncoding::~ContentEncoding() { } const ContentEncoding::ContentCompression* - ContentEncoding::GetCompressionByIndex(unsigned long idx) const { +ContentEncoding::GetCompressionByIndex(unsigned long idx) const { const ptrdiff_t count = compression_entries_end_ - compression_entries_; assert(count >= 0); @@ -4181,12 +4220,20 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size, return -1; if (compression_count > 0) { - compression_entries_ = new ContentCompression*[compression_count]; + compression_entries_ = + new (std::nothrow) ContentCompression*[compression_count]; + if (!compression_entries_) + return -1; compression_entries_end_ = compression_entries_; } if (encryption_count > 0) { - encryption_entries_ = new ContentEncryption*[encryption_count]; + encryption_entries_ = + new (std::nothrow) ContentEncryption*[encryption_count]; + if (!encryption_entries_) { + delete[] compression_entries_; + return -1; + } encryption_entries_end_ = encryption_entries_; } @@ -4206,7 +4253,10 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size, } else if (id == libwebm::kMkvContentEncodingType) { encoding_type_ = UnserializeUInt(pReader, pos, size); } else if (id == libwebm::kMkvContentCompression) { - ContentCompression* const compression = new ContentCompression(); + ContentCompression* const compression = + new (std::nothrow) ContentCompression(); + if (!compression) + return -1; status = ParseCompressionEntry(pos, size, pReader, compression); if (status) { @@ -4215,7 +4265,10 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size, } *compression_entries_end_++ = compression; } else if (id == libwebm::kMkvContentEncryption) { - ContentEncryption* const encryption = new ContentEncryption(); + ContentEncryption* const encryption = + new (std::nothrow) ContentEncryption(); + if (!encryption) + return -1; status = ParseEncryptionEntry(pos, size, pReader, encryption); if (status) { @@ -4421,7 +4474,11 @@ long Track::Create(Segment* pSegment, const Info& info, long long element_start, if (pResult) return -1; - Track* const pTrack = new Track(pSegment, element_start, element_size); + Track* const pTrack = + new (std::nothrow) Track(pSegment, element_start, element_size); + + if (pTrack == NULL) + return -1; // generic error const int status = info.Copy(pTrack->m_info); @@ -4873,7 +4930,10 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) { if (count <= 0) return -1; - content_encoding_entries_ = new ContentEncoding*[count]; + content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count]; + if (!content_encoding_entries_) + return -1; + content_encoding_entries_end_ = content_encoding_entries_; pos = start; @@ -4885,7 +4945,10 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) { // pos now designates start of element if (id == libwebm::kMkvContentEncoding) { - ContentEncoding* const content_encoding = new ContentEncoding(); + ContentEncoding* const content_encoding = + new (std::nothrow) ContentEncoding(); + if (!content_encoding) + return -1; status = content_encoding->ParseContentEncodingEntry(pos, size, pReader); if (status) { @@ -4919,20 +4982,27 @@ bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos, if (!reader) return false; - my_auto_ptr<PrimaryChromaticity> chromaticity_ptr(*chromaticity ? *chromaticity : new PrimaryChromaticity()); + if (!*chromaticity) + *chromaticity = new PrimaryChromaticity(); + + if (!*chromaticity) + return false; - float* value = is_x ? &chromaticity_ptr->x : &chromaticity_ptr->y; + PrimaryChromaticity* pc = *chromaticity; + float* value = is_x ? &pc->x : &pc->y; double parser_value = 0; - const long long value_parse_status = + const long long parse_status = UnserializeFloat(reader, read_pos, value_size, parser_value); - *value = static_cast<float>(parser_value); - - if (value_parse_status < 0 || *value < 0.0 || *value > 1.0) + // Valid range is [0, 1]. Make sure the double is representable as a float + // before casting. + if (parse_status < 0 || parser_value < 0.0 || parser_value > 1.0 || + (parser_value > 0.0 && parser_value < FLT_MIN)) return false; - *chromaticity = chromaticity_ptr.release(); + *value = static_cast<float>(parser_value); + return true; } @@ -4941,7 +5011,9 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start, if (!reader || *mm) return false; - my_auto_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata()); + std::unique_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata()); + if (!mm_ptr.get()) + return false; const long long mm_end = mm_start + mm_size; long long read_pos = mm_start; @@ -4959,6 +5031,10 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start, double value = 0; const long long value_parse_status = UnserializeFloat(reader, read_pos, child_size, value); + if (value < -FLT_MAX || value > FLT_MAX || + (value > 0.0 && value < FLT_MIN)) { + return false; + } mm_ptr->luminance_max = static_cast<float>(value); if (value_parse_status < 0 || mm_ptr->luminance_max < 0.0 || mm_ptr->luminance_max > 9999.99) { @@ -4968,6 +5044,10 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start, double value = 0; const long long value_parse_status = UnserializeFloat(reader, read_pos, child_size, value); + if (value < -FLT_MAX || value > FLT_MAX || + (value > 0.0 && value < FLT_MIN)) { + return false; + } mm_ptr->luminance_min = static_cast<float>(value); if (value_parse_status < 0 || mm_ptr->luminance_min < 0.0 || mm_ptr->luminance_min > 999.9999) { @@ -5020,7 +5100,9 @@ bool Colour::Parse(IMkvReader* reader, long long colour_start, if (!reader || *colour) return false; - my_auto_ptr<Colour> colour_ptr(new Colour()); + std::unique_ptr<Colour> colour_ptr(new Colour()); + if (!colour_ptr.get()) + return false; const long long colour_end = colour_start + colour_size; long long read_pos = colour_start; @@ -5111,11 +5193,94 @@ bool Colour::Parse(IMkvReader* reader, long long colour_start, return true; } +bool Projection::Parse(IMkvReader* reader, long long start, long long size, + Projection** projection) { + if (!reader || *projection) + return false; + + std::unique_ptr<Projection> projection_ptr(new Projection()); + if (!projection_ptr.get()) + return false; + + const long long end = start + size; + long long read_pos = start; + + while (read_pos < end) { + long long child_id = 0; + long long child_size = 0; + + const long long status = + ParseElementHeader(reader, read_pos, end, child_id, child_size); + if (status < 0) + return false; + + if (child_id == libwebm::kMkvProjectionType) { + long long projection_type = kTypeNotPresent; + projection_type = UnserializeUInt(reader, read_pos, child_size); + if (projection_type < 0) + return false; + + projection_ptr->type = static_cast<ProjectionType>(projection_type); + } else if (child_id == libwebm::kMkvProjectionPrivate) { + unsigned char* data = SafeArrayAlloc<unsigned char>(1, child_size); + + if (data == NULL) + return false; + + const int status = + reader->Read(read_pos, static_cast<long>(child_size), data); + + if (status) { + delete[] data; + return false; + } + + projection_ptr->private_data = data; + projection_ptr->private_data_length = static_cast<size_t>(child_size); + } else { + double value = 0; + const long long value_parse_status = + UnserializeFloat(reader, read_pos, child_size, value); + // Make sure value is representable as a float before casting. + if (value_parse_status < 0 || value < -FLT_MAX || value > FLT_MAX || + (value > 0.0 && value < FLT_MIN)) { + return false; + } + + switch (child_id) { + case libwebm::kMkvProjectionPoseYaw: + projection_ptr->pose_yaw = static_cast<float>(value); + break; + case libwebm::kMkvProjectionPosePitch: + projection_ptr->pose_pitch = static_cast<float>(value); + break; + case libwebm::kMkvProjectionPoseRoll: + projection_ptr->pose_roll = static_cast<float>(value); + break; + default: + return false; + } + } + + read_pos += child_size; + if (read_pos > end) + return false; + } + + *projection = projection_ptr.release(); + return true; +} + VideoTrack::VideoTrack(Segment* pSegment, long long element_start, long long element_size) - : Track(pSegment, element_start, element_size), m_colour(NULL) {} + : Track(pSegment, element_start, element_size), + m_colour(NULL), + m_projection(NULL) {} -VideoTrack::~VideoTrack() { delete m_colour; } +VideoTrack::~VideoTrack() { + delete m_colour; + delete m_projection; +} long VideoTrack::Parse(Segment* pSegment, const Info& info, long long element_start, long long element_size, @@ -5147,6 +5312,7 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info, const long long stop = pos + s.size; Colour* colour = NULL; + Projection* projection = NULL; while (pos < stop) { long long id, size; @@ -5197,6 +5363,9 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info, } else if (id == libwebm::kMkvColour) { if (!Colour::Parse(pReader, pos, size, &colour)) return E_FILE_FORMAT_INVALID; + } else if (id == libwebm::kMkvProjection) { + if (!Projection::Parse(pReader, pos, size, &projection)) + return E_FILE_FORMAT_INVALID; } pos += size; // consume payload @@ -5207,7 +5376,11 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info, if (pos != stop) return E_FILE_FORMAT_INVALID; - VideoTrack* const pTrack = new VideoTrack(pSegment, element_start, element_size); + VideoTrack* const pTrack = + new (std::nothrow) VideoTrack(pSegment, element_start, element_size); + + if (pTrack == NULL) + return -1; // generic error const int status = info.Copy(pTrack->m_info); @@ -5224,6 +5397,7 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info, pTrack->m_stereo_mode = stereo_mode; pTrack->m_rate = rate; pTrack->m_colour = colour; + pTrack->m_projection = projection; pResult = pTrack; return 0; // success @@ -5324,6 +5498,8 @@ long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const { Colour* VideoTrack::GetColour() const { return m_colour; } +Projection* VideoTrack::GetProjection() const { return m_projection; } + long long VideoTrack::GetWidth() const { return m_width; } long long VideoTrack::GetHeight() const { return m_height; } @@ -5406,7 +5582,11 @@ long AudioTrack::Parse(Segment* pSegment, const Info& info, if (pos != stop) return E_FILE_FORMAT_INVALID; - AudioTrack* const pTrack = new AudioTrack(pSegment, element_start, element_size); + AudioTrack* const pTrack = + new (std::nothrow) AudioTrack(pSegment, element_start, element_size); + + if (pTrack == NULL) + return -1; // generic error const int status = info.Copy(pTrack->m_info); @@ -5474,7 +5654,11 @@ long Tracks::Parse() { if (count <= 0) return 0; // success - m_trackEntries = new Track*[count]; + m_trackEntries = new (std::nothrow) Track*[count]; + + if (m_trackEntries == NULL) + return -1; + m_trackEntriesEnd = m_trackEntries; pos = m_start; @@ -6577,7 +6761,10 @@ Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) { const long long element_start = pSegment->m_start + off; - return new Cluster(pSegment, idx, element_start); + Cluster* const pCluster = + new (std::nothrow) Cluster(pSegment, idx, element_start); + + return pCluster; } Cluster::Cluster() @@ -6606,8 +6793,10 @@ Cluster::Cluster(Segment* pSegment, long idx, long long element_start {} Cluster::~Cluster() { - if (m_entries_count <= 0) + if (m_entries_count <= 0) { + delete[] m_entries; return; + } BlockEntry** i = m_entries; BlockEntry** const j = m_entries + m_entries_count; @@ -6920,7 +7109,9 @@ long Cluster::CreateBlock(long long id, assert(m_entries_size == 0); m_entries_size = 1024; - m_entries = new BlockEntry*[m_entries_size]; + m_entries = new (std::nothrow) BlockEntry*[m_entries_size]; + if (m_entries == NULL) + return -1; m_entries_count = 0; } else { @@ -6931,7 +7122,9 @@ long Cluster::CreateBlock(long long id, if (m_entries_count >= m_entries_size) { const long entries_size = 2 * m_entries_size; - BlockEntry** const entries = new BlockEntry*[entries_size]; + BlockEntry** const entries = new (std::nothrow) BlockEntry*[entries_size]; + if (entries == NULL) + return -1; BlockEntry** src = m_entries; BlockEntry** const src_end = src + m_entries_count; @@ -7040,7 +7233,11 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size, BlockEntry** const ppEntry = m_entries + idx; BlockEntry*& pEntry = *ppEntry; - pEntry = new BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding); + pEntry = new (std::nothrow) + BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding); + + if (pEntry == NULL) + return -1; // generic error BlockGroup* const p = static_cast<BlockGroup*>(pEntry); @@ -7068,7 +7265,10 @@ long Cluster::CreateSimpleBlock(long long st, long long sz) { BlockEntry** const ppEntry = m_entries + idx; BlockEntry*& pEntry = *ppEntry; - pEntry = new SimpleBlock(this, idx, st, sz); + pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz); + + if (pEntry == NULL) + return -1; // generic error SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry); @@ -7463,7 +7663,9 @@ long Block::Parse(const Cluster* pCluster) { return E_FILE_FORMAT_INVALID; m_frame_count = 1; - m_frames = new Frame[m_frame_count]; + m_frames = new (std::nothrow) Frame[m_frame_count]; + if (m_frames == NULL) + return -1; Frame& f = m_frames[0]; f.pos = pos; @@ -7494,7 +7696,9 @@ long Block::Parse(const Cluster* pCluster) { m_frame_count = int(biased_count) + 1; - m_frames = new Frame[m_frame_count]; + m_frames = new (std::nothrow) Frame[m_frame_count]; + if (m_frames == NULL) + return -1; if (!m_frames) return E_FILE_FORMAT_INVALID; @@ -7703,6 +7907,10 @@ long Block::Parse(const Cluster* pCluster) { return E_FILE_FORMAT_INVALID; curr.len = static_cast<long>(frame_size); + // Check if size + curr.len could overflow. + if (size > LLONG_MAX - curr.len) { + return E_FILE_FORMAT_INVALID; + } size += curr.len; // contribution of this frame --frame_count; @@ -7743,7 +7951,6 @@ long Block::Parse(const Cluster* pCluster) { pf = m_frames; while (pf != pf_end) { Frame& f = *pf++; - assert((pos + f.len) <= stop); if ((pos + f.len) > stop) return E_FILE_FORMAT_INVALID; @@ -7765,6 +7972,11 @@ long long Block::GetTimeCode(const Cluster* pCluster) const { const long long tc0 = pCluster->GetTimeCode(); assert(tc0 >= 0); + // Check if tc0 + m_timecode would overflow. + if (tc0 < 0 || LLONG_MAX - tc0 < m_timecode) { + return -1; + } + const long long tc = tc0 + m_timecode; return tc; // unscaled timecode units @@ -7782,6 +7994,10 @@ long long Block::GetTime(const Cluster* pCluster) const { const long long scale = pInfo->GetTimeCodeScale(); assert(scale >= 1); + // Check if tc * scale could overflow. + if (tc != 0 && scale > LLONG_MAX / tc) { + return -1; + } const long long ns = tc * scale; return ns; diff --git a/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.h b/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.h index 1ef274b162..6dce7e50ba 100644 --- a/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.h +++ b/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.h @@ -8,7 +8,7 @@ #ifndef MKVPARSER_MKVPARSER_H_ #define MKVPARSER_MKVPARSER_H_ -#include <stddef.h> +#include <cstddef> namespace mkvparser { @@ -21,6 +21,7 @@ class IMkvReader { virtual int Read(long long pos, long len, unsigned char* buf) = 0; virtual int Length(long long* total, long long* available) = 0; + public: virtual ~IMkvReader(); }; @@ -472,6 +473,34 @@ struct Colour { MasteringMetadata* mastering_metadata; }; +struct Projection { + enum ProjectionType { + kTypeNotPresent = -1, + kRectangular = 0, + kEquirectangular = 1, + kCubeMap = 2, + kMesh = 3, + }; + static const float kValueNotPresent; + Projection() + : type(kTypeNotPresent), + private_data(NULL), + private_data_length(0), + pose_yaw(kValueNotPresent), + pose_pitch(kValueNotPresent), + pose_roll(kValueNotPresent) {} + ~Projection() { delete[] private_data; } + static bool Parse(IMkvReader* reader, long long element_start, + long long element_size, Projection** projection); + + ProjectionType type; + unsigned char* private_data; + size_t private_data_length; + float pose_yaw; + float pose_pitch; + float pose_roll; +}; + class VideoTrack : public Track { VideoTrack(const VideoTrack&); VideoTrack& operator=(const VideoTrack&); @@ -496,6 +525,8 @@ class VideoTrack : public Track { Colour* GetColour() const; + Projection* GetProjection() const; + private: long long m_width; long long m_height; @@ -507,6 +538,7 @@ class VideoTrack : public Track { double m_rate; Colour* m_colour; + Projection* m_projection; }; class AudioTrack : public Track { @@ -812,6 +844,8 @@ class SeekHead { long Parse(); struct Entry { + Entry(); + // the SeekHead entry payload long long id; long long pos; |