diff options
119 files changed, 2408 insertions, 1108 deletions
diff --git a/core/image.cpp b/core/image.cpp index 7778169995..08bb9a35c3 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1133,20 +1133,23 @@ template <class Component, int CC, bool renormalize, static void _generate_po2_mipmap(const Component *p_src, Component *p_dst, uint32_t p_width, uint32_t p_height) { //fast power of 2 mipmap generation - uint32_t dst_w = p_width >> 1; - uint32_t dst_h = p_height >> 1; + uint32_t dst_w = MAX(p_width >> 1, 1); + uint32_t dst_h = MAX(p_height >> 1, 1); + + int right_step = (p_width == 1) ? 0 : CC; + int down_step = (p_height == 1) ? 0 : (p_width * CC); for (uint32_t i = 0; i < dst_h; i++) { - const Component *rup_ptr = &p_src[i * 2 * p_width * CC]; - const Component *rdown_ptr = rup_ptr + p_width * CC; + const Component *rup_ptr = &p_src[i * 2 * down_step]; + const Component *rdown_ptr = rup_ptr + down_step; Component *dst_ptr = &p_dst[i * dst_w * CC]; uint32_t count = dst_w; while (count--) { for (int j = 0; j < CC; j++) { - average_func(dst_ptr[j], rup_ptr[j], rup_ptr[j + CC], rdown_ptr[j], rdown_ptr[j + CC]); + average_func(dst_ptr[j], rup_ptr[j], rup_ptr[j + right_step], rdown_ptr[j], rdown_ptr[j + right_step]); } if (renormalize) { @@ -1154,8 +1157,8 @@ static void _generate_po2_mipmap(const Component *p_src, Component *p_dst, uint3 } dst_ptr += CC; - rup_ptr += CC * 2; - rdown_ptr += CC * 2; + rup_ptr += right_step * 2; + rdown_ptr += right_step * 2; } } } @@ -1313,7 +1316,7 @@ Error Image::generate_mipmaps(bool p_renormalize) { int prev_h = height; int prev_w = width; - for (int i = 1; i < mmcount; i++) { + for (int i = 1; i <= mmcount; i++) { int ofs, w, h; _get_mipmap_offset_and_size(i, ofs, w, h); diff --git a/core/math/quat.cpp b/core/math/quat.cpp index 67c9048a41..2251571146 100644 --- a/core/math/quat.cpp +++ b/core/math/quat.cpp @@ -134,7 +134,7 @@ Quat Quat::normalized() const { } bool Quat::is_normalized() const { - return Math::is_equal_approx(length(), 1.0); + return Math::is_equal_approx(length_squared(), 1.0); } Quat Quat::inverse() const { diff --git a/core/object.cpp b/core/object.cpp index e83abaece7..24a31930a0 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -1916,7 +1916,11 @@ void *Object::get_script_instance_binding(int p_script_language_index) { //as it should not really affect performance much (won't be called too often), as in far most caes the condition below will be false afterwards if (!_script_instance_bindings[p_script_language_index]) { - _script_instance_bindings[p_script_language_index] = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this); + void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this); + if (script_data) { + atomic_increment(&instance_binding_count); + _script_instance_bindings[p_script_language_index] = script_data; + } } return _script_instance_bindings[p_script_language_index]; @@ -1931,6 +1935,7 @@ Object::Object() { _instance_ID = ObjectDB::add_instance(this); _can_translate = true; _is_queued_for_deletion = false; + instance_binding_count = 0; memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS); script_instance = NULL; #ifdef TOOLS_ENABLED diff --git a/core/object.h b/core/object.h index d741371306..43e1cf4785 100644 --- a/core/object.h +++ b/core/object.h @@ -490,10 +490,12 @@ private: void _set_indexed_bind(const NodePath &p_name, const Variant &p_value); Variant _get_indexed_bind(const NodePath &p_name) const; - void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS]; - void property_list_changed_notify(); + friend class Reference; + uint32_t instance_binding_count; + void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS]; + protected: virtual void _initialize_classv() { initialize_class(); } virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; }; diff --git a/core/os/os.h b/core/os/os.h index 6f9a72d451..100af95ef1 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -256,7 +256,7 @@ public: virtual String get_executable_path() const; virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false) = 0; - virtual Error kill(const ProcessID &p_pid, const int p_max_wait_msec = -1) = 0; + virtual Error kill(const ProcessID &p_pid) = 0; virtual int get_process_id() const; virtual Error shell_open(String p_uri); diff --git a/core/reference.cpp b/core/reference.cpp index c33a7c683c..6e1520d81d 100644 --- a/core/reference.cpp +++ b/core/reference.cpp @@ -66,8 +66,17 @@ int Reference::reference_get_count() const { bool Reference::reference() { bool success = refcount.ref(); - if (success && get_script_instance()) { - get_script_instance()->refcount_incremented(); + if (success && refcount.get() <= 2 /* higher is not relevant */) { + if (get_script_instance()) { + get_script_instance()->refcount_incremented(); + } + if (instance_binding_count > 0) { + for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { + if (_script_instance_bindings[i]) { + ScriptServer::get_language(i)->refcount_incremented_instance_binding(this); + } + } + } } return success; @@ -77,9 +86,19 @@ bool Reference::unreference() { bool die = refcount.unref(); - if (get_script_instance()) { - bool script_ret = get_script_instance()->refcount_decremented(); - die = die && script_ret; + if (refcount.get() <= 1 /* higher is not relevant */) { + if (get_script_instance()) { + bool script_ret = get_script_instance()->refcount_decremented(); + die = die && script_ret; + } + if (instance_binding_count > 0) { + for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { + if (_script_instance_bindings[i]) { + bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this); + die = die && script_ret; + } + } + } } return die; diff --git a/core/script_language.h b/core/script_language.h index 71b705e960..573e7b4fa1 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -311,6 +311,8 @@ public: virtual void *alloc_instance_binding_data(Object *p_object) { return NULL; } //optional, not used by all languages virtual void free_instance_binding_data(void *p_data) {} //optional, not used by all languages + virtual void refcount_incremented_instance_binding(Object *p_object) {} //optional, not used by all languages + virtual bool refcount_decremented_instance_binding(Object *p_object) { return true; } //return true if it can die //optional, not used by all languages virtual void frame(); diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 358b7292a5..5f828550b9 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -658,6 +658,9 @@ </member> <member name="rendering/quality/driver/driver_name" type="String" setter="" getter=""> </member> + <member name="rendering/quality/driver/driver_fallback" type="String" setter="" getter=""> + Whether to allow falling back to other graphics drivers if the preferred driver is not available. Best means use the best working driver (this is the default). Never means never fall back to another driver even if it does not work. This means the project will not run if the preferred driver does not function. + </member> <member name="rendering/quality/filters/anisotropic_filter_level" type="int" setter="" getter=""> Maximum Anisotropic filter level used for textures when anisotropy enabled. </member> diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index 689f1f462d..45d62e797f 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -331,55 +331,57 @@ bool AudioDriverCoreAudio::try_lock() { } void AudioDriverCoreAudio::finish() { - OSStatus result; + if (audio_unit) { + OSStatus result; - lock(); + lock(); - AURenderCallbackStruct callback; - zeromem(&callback, sizeof(AURenderCallbackStruct)); - result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); - if (result != noErr) { - ERR_PRINT("AudioUnitSetProperty failed"); - } - - if (active) { - result = AudioOutputUnitStop(audio_unit); + AURenderCallbackStruct callback; + zeromem(&callback, sizeof(AURenderCallbackStruct)); + result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); if (result != noErr) { - ERR_PRINT("AudioOutputUnitStop failed"); + ERR_PRINT("AudioUnitSetProperty failed"); } - active = false; - } + if (active) { + result = AudioOutputUnitStop(audio_unit); + if (result != noErr) { + ERR_PRINT("AudioOutputUnitStop failed"); + } - result = AudioUnitUninitialize(audio_unit); - if (result != noErr) { - ERR_PRINT("AudioUnitUninitialize failed"); - } + active = false; + } + + result = AudioUnitUninitialize(audio_unit); + if (result != noErr) { + ERR_PRINT("AudioUnitUninitialize failed"); + } #ifdef OSX_ENABLED - AudioObjectPropertyAddress prop; - prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - prop.mScope = kAudioObjectPropertyScopeGlobal; - prop.mElement = kAudioObjectPropertyElementMaster; + AudioObjectPropertyAddress prop; + prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = kAudioObjectPropertyElementMaster; - result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); - if (result != noErr) { - ERR_PRINT("AudioObjectRemovePropertyListener failed"); - } + result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); + if (result != noErr) { + ERR_PRINT("AudioObjectRemovePropertyListener failed"); + } #endif - result = AudioComponentInstanceDispose(audio_unit); - if (result != noErr) { - ERR_PRINT("AudioComponentInstanceDispose failed"); - } + result = AudioComponentInstanceDispose(audio_unit); + if (result != noErr) { + ERR_PRINT("AudioComponentInstanceDispose failed"); + } - unlock(); + unlock(); + } if (mutex) { memdelete(mutex); mutex = NULL; } -}; +} Error AudioDriverCoreAudio::capture_start() { @@ -576,6 +578,7 @@ String AudioDriverCoreAudio::capture_get_device() { #endif AudioDriverCoreAudio::AudioDriverCoreAudio() { + audio_unit = NULL; active = false; mutex = NULL; diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index e39ec915fc..0381d3f0c1 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -789,6 +789,10 @@ public: void end_frame(bool p_swap_buffers) {} void finalize() {} + static Error is_viable() { + return OK; + } + static Rasterizer *_create_current() { return memnew(RasterizerDummy); } diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index c926f2bcc4..76ee80aa07 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -136,26 +136,21 @@ RasterizerScene *RasterizerGLES2::get_scene() { return scene; } -void RasterizerGLES2::initialize() { - - print_verbose("Using GLES2 video driver"); +Error RasterizerGLES2::is_viable() { #ifdef GLAD_ENABLED if (!gladLoadGL()) { ERR_PRINT("Error initializing GLAD"); + return ERR_UNAVAILABLE; } // GLVersion seems to be used for both GL and GL ES, so we need different version checks for them #ifdef OPENGL_ENABLED // OpenGL 2.1 Profile required - if (GLVersion.major < 2) { -#else // OpenGL ES 3.0 + if (GLVersion.major < 2 || (GLVersion.major == 2 && GLVersion.minor < 1)) { +#else // OpenGL ES 2.0 if (GLVersion.major < 2) { #endif - ERR_PRINT("Your system's graphic drivers seem not to support OpenGL 2.1 / OpenGL ES 2.0, sorry :(\n" - "Try a drivers update, buy a new GPU or try software rendering on Linux; Godot will now crash with a segmentation fault."); - OS::get_singleton()->alert("Your system's graphic drivers seem not to support OpenGL 2.1 / OpenGL ES 2.0, sorry :(\n" - "Godot Engine will self-destruct as soon as you acknowledge this error message.", - "Fatal error: Insufficient OpenGL / GLES driver support"); + return ERR_UNAVAILABLE; } #ifdef GLES_OVER_GL @@ -181,14 +176,21 @@ void RasterizerGLES2::initialize() { glGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameterivEXT; glGenerateMipmap = glGenerateMipmapEXT; } else { - ERR_PRINT("Your system's graphic drivers seem not to support GL_ARB(EXT)_framebuffer_object OpenGL extension, sorry :(\n" - "Try a drivers update, buy a new GPU or try software rendering on Linux; Godot will now crash with a segmentation fault."); - OS::get_singleton()->alert("Your system's graphic drivers seem not to support GL_ARB(EXT)_framebuffer_object OpenGL extension, sorry :(\n" - "Godot Engine will self-destruct as soon as you acknowledge this error message.", - "Fatal error: Insufficient OpenGL / GLES driver support"); + return ERR_UNAVAILABLE; } } #endif + +#endif // GLAD_ENABLED + + return OK; +} + +void RasterizerGLES2::initialize() { + + print_verbose("Using GLES2 video driver"); + +#ifdef GLAD_ENABLED if (true || OS::get_singleton()->is_stdout_verbose()) { if (GLAD_GL_ARB_debug_output) { glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); @@ -198,7 +200,6 @@ void RasterizerGLES2::initialize() { print_line("OpenGL debugging not supported!"); } } - #endif // GLAD_ENABLED // For debugging diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index f727af39dd..98c73b776b 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -61,9 +61,10 @@ public: virtual void end_frame(bool p_swap_buffers); virtual void finalize(); + static Error is_viable(); static void make_current(); - static void register_config(); + RasterizerGLES2(); ~RasterizerGLES2(); }; diff --git a/drivers/gles2/shaders/blend_shape.glsl b/drivers/gles2/shaders/blend_shape.glsl index d019062ba0..a1e954e33d 100644 --- a/drivers/gles2/shaders/blend_shape.glsl +++ b/drivers/gles2/shaders/blend_shape.glsl @@ -1,3 +1,4 @@ +/* clang-format off */ [vertex] /* @@ -23,6 +24,7 @@ ARRAY_INDEX=8, /* INPUT ATTRIBS */ layout(location = 0) in highp VFORMAT vertex_attrib; +/* clang-format on */ layout(location = 1) in vec3 normal_attrib; #ifdef ENABLE_TANGENT @@ -183,8 +185,10 @@ void main() { gl_Position = vec4(0.0); } +/* clang-format off */ [fragment] void main() { } +/* clang-format on */ diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index cee68a58ff..ba69ca9b6e 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -1,3 +1,4 @@ +/* clang-format off */ [vertex] #ifdef USE_GLES_OVER_GL @@ -9,6 +10,7 @@ precision mediump int; #endif uniform highp mat4 projection_matrix; +/* clang-format on */ uniform highp mat4 modelview_matrix; uniform highp mat4 extra_matrix; attribute highp vec2 vertex; // attrib:0 @@ -29,8 +31,12 @@ uniform vec4 src_rect; uniform highp float time; +/* clang-format off */ + VERTEX_SHADER_GLOBALS +/* clang-format on */ + vec2 select(vec2 a, vec2 b, bvec2 c) { vec2 ret; @@ -74,17 +80,21 @@ void main() { #endif -{ - vec2 src_vtx = outvec.xy; + { + vec2 src_vtx = outvec.xy; + /* clang-format off */ + VERTEX_SHADER_CODE -} + /* clang-format on */ + } color_interp = color; gl_Position = projection_matrix * modelview_matrix * outvec; } +/* clang-format off */ [fragment] #ifdef USE_GLES_OVER_GL @@ -96,6 +106,7 @@ precision mediump int; #endif uniform sampler2D color_texture; // texunit:-1 +/* clang-format on */ uniform highp vec2 color_texpixel_size; uniform mediump sampler2D normal_texture; // texunit:-2 @@ -118,8 +129,12 @@ uniform vec2 screen_pixel_size; #endif +/* clang-format off */ + FRAGMENT_SHADER_GLOBALS +/* clang-format on */ + void main() { vec4 color = color_interp; @@ -129,11 +144,13 @@ void main() { #ifdef SCREEN_UV_USED vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; #endif -{ + { + /* clang-format off */ FRAGMENT_SHADER_CODE -} + /* clang-format on */ + } color *= final_modulate; diff --git a/drivers/gles2/shaders/canvas_shadow.glsl b/drivers/gles2/shaders/canvas_shadow.glsl index 81af486101..e3c8140e31 100644 --- a/drivers/gles2/shaders/canvas_shadow.glsl +++ b/drivers/gles2/shaders/canvas_shadow.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] uniform highp mat4 projection_matrix; +/* clang-format on */ uniform highp mat4 light_matrix; uniform highp mat4 world_matrix; uniform highp float distance_norm; @@ -15,9 +17,11 @@ void main() { position_interp = gl_Position; } +/* clang-format off */ [fragment] in highp vec4 position_interp; +/* clang-format on */ #ifdef USE_RGBA_SHADOWS diff --git a/drivers/gles2/shaders/copy.glsl b/drivers/gles2/shaders/copy.glsl index 6e9aad2a5d..16bbde196d 100644 --- a/drivers/gles2/shaders/copy.glsl +++ b/drivers/gles2/shaders/copy.glsl @@ -1,3 +1,4 @@ +/* clang-format off */ [vertex] #ifdef USE_GLES_OVER_GL @@ -9,6 +10,7 @@ precision mediump int; #endif attribute highp vec4 vertex_attrib; // attrib:0 +/* clang-format on */ #if defined(USE_CUBEMAP) || defined(USE_PANORAMA) attribute vec3 cube_in; // attrib:4 @@ -46,6 +48,7 @@ void main() { #endif } +/* clang-format off */ [fragment] #define M_PI 3.14159265359 @@ -63,6 +66,7 @@ varying vec3 cube_interp; #else varying vec2 uv_interp; #endif +/* clang-format on */ #ifdef USE_CUBEMAP uniform samplerCube source_cube; // texunit:0 diff --git a/drivers/gles2/shaders/cube_to_dp.glsl b/drivers/gles2/shaders/cube_to_dp.glsl index b44aab8946..3d24c36336 100644 --- a/drivers/gles2/shaders/cube_to_dp.glsl +++ b/drivers/gles2/shaders/cube_to_dp.glsl @@ -1,3 +1,4 @@ +/* clang-format off */ [vertex] #ifdef USE_GLES_OVER_GL @@ -9,6 +10,7 @@ precision mediump int; #endif attribute highp vec4 vertex_attrib; // attrib:0 +/* clang-format on */ attribute vec2 uv_in; // attrib:4 varying vec2 uv_interp; @@ -19,6 +21,7 @@ void main() { gl_Position = vertex_attrib; } +/* clang-format off */ [fragment] #ifdef USE_GLES_OVER_GL @@ -30,6 +33,7 @@ precision mediump int; #endif uniform highp samplerCube source_cube; //texunit:0 +/* clang-format on */ varying vec2 uv_interp; uniform bool z_flip; diff --git a/drivers/gles2/shaders/cubemap_filter.glsl b/drivers/gles2/shaders/cubemap_filter.glsl index 0d60104480..2a1ad8d8f2 100644 --- a/drivers/gles2/shaders/cubemap_filter.glsl +++ b/drivers/gles2/shaders/cubemap_filter.glsl @@ -1,3 +1,4 @@ +/* clang-format off */ [vertex] #ifdef USE_GLES_OVER_GL @@ -9,6 +10,7 @@ precision mediump int; #endif attribute highp vec2 vertex; // attrib:0 +/* clang-format on */ attribute highp vec2 uv; // attrib:4 varying highp vec2 uv_interp; @@ -19,6 +21,7 @@ void main() { gl_Position = vec4(vertex, 0, 1); } +/* clang-format off */ [fragment] #extension GL_ARB_shader_texture_lod : enable @@ -41,6 +44,7 @@ uniform sampler2D source_panorama; //texunit:0 #else uniform samplerCube source_cube; //texunit:0 #endif +/* clang-format on */ uniform int face_id; uniform float roughness; diff --git a/drivers/gles2/shaders/effect_blur.glsl b/drivers/gles2/shaders/effect_blur.glsl index 0e2d28af20..a531802c75 100644 --- a/drivers/gles2/shaders/effect_blur.glsl +++ b/drivers/gles2/shaders/effect_blur.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -22,6 +24,7 @@ void main() { #endif } +/* clang-format off */ [fragment] #if !defined(GLES_OVER_GL) @@ -29,6 +32,7 @@ precision mediump float; #endif in vec2 uv_interp; +/* clang-format on */ uniform sampler2D source_color; //texunit:0 #ifdef SSAO_MERGE diff --git a/drivers/gles2/shaders/exposure.glsl b/drivers/gles2/shaders/exposure.glsl index 18fff1ae36..759adcda06 100644 --- a/drivers/gles2/shaders/exposure.glsl +++ b/drivers/gles2/shaders/exposure.glsl @@ -1,15 +1,19 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ void main() { gl_Position = vertex_attrib; } +/* clang-format off */ [fragment] uniform highp sampler2D source_exposure; //texunit:0 +/* clang-format on */ #ifdef EXPOSURE_BEGIN diff --git a/drivers/gles2/shaders/particles.glsl b/drivers/gles2/shaders/particles.glsl index 5af4b65b28..5974050fc1 100644 --- a/drivers/gles2/shaders/particles.glsl +++ b/drivers/gles2/shaders/particles.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 color; +/* clang-format on */ layout(location = 1) in highp vec4 velocity_active; layout(location = 2) in highp vec4 custom; layout(location = 3) in highp vec4 xform_1; @@ -45,16 +47,22 @@ out highp vec4 out_xform_3; //tfb: #if defined(USE_MATERIAL) +/* clang-format off */ layout(std140) uniform UniformData { //ubo:0 MATERIAL_UNIFORMS }; +/* clang-format on */ #endif +/* clang-format off */ + VERTEX_SHADER_GLOBALS +/* clang-format on */ + uint hash(uint x) { x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b); @@ -165,9 +173,11 @@ void main() { //execute shader { + /* clang-format off */ VERTEX_SHADER_CODE + /* clang-format on */ } #if !defined(DISABLE_FORCE) @@ -223,6 +233,7 @@ VERTEX_SHADER_CODE #endif //PARTICLES_COPY } +/* clang-format off */ [fragment] //any code here is never executed, stuff is filled just so it works @@ -240,12 +251,16 @@ MATERIAL_UNIFORMS FRAGMENT_SHADER_GLOBALS void main() { - { + LIGHT_SHADER_CODE + } { + FRAGMENT_SHADER_CODE + } } +/* clang-format on */ diff --git a/drivers/gles2/shaders/resolve.glsl b/drivers/gles2/shaders/resolve.glsl index 05bb922eec..5c6f5d6561 100644 --- a/drivers/gles2/shaders/resolve.glsl +++ b/drivers/gles2/shaders/resolve.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -11,6 +13,7 @@ void main() { gl_Position = vertex_attrib; } +/* clang-format off */ [fragment] #if !defined(GLES_OVER_GL) @@ -18,6 +21,7 @@ precision mediump float; #endif in vec2 uv_interp; +/* clang-format on */ uniform sampler2D source_specular; //texunit:0 uniform sampler2D source_ssr; //texunit:1 diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index 8bcb3b5f1d..906c089170 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -1,3 +1,4 @@ +/* clang-format off */ [vertex] #ifdef USE_GLES_OVER_GL @@ -15,6 +16,7 @@ precision mediump int; // attribute highp vec4 vertex_attrib; // attrib:0 +/* clang-format on */ attribute vec3 normal_attrib; // attrib:1 #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) @@ -108,8 +110,12 @@ varying vec2 uv_interp; varying vec2 uv2_interp; #endif +/* clang-format off */ + VERTEX_SHADER_GLOBALS +/* clang-format on */ + void main() { highp vec4 vertex = vertex_attrib; @@ -206,11 +212,13 @@ void main() { #define world_transform world_matrix -{ + { + /* clang-format off */ VERTEX_SHADER_CODE -} + /* clang-format on */ + } vec4 outvec = vertex; @@ -254,6 +262,7 @@ VERTEX_SHADER_CODE gl_Position = projection_matrix * vec4(vertex_interp, 1.0); } +/* clang-format off */ [fragment] #extension GL_ARB_shader_texture_lod : enable @@ -279,6 +288,7 @@ precision mediump int; // uniform mat4 camera_matrix; +/* clang-format on */ uniform mat4 camera_inverse_matrix; uniform mat4 projection_matrix; uniform mat4 projection_inverse_matrix; @@ -390,8 +400,12 @@ vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) { return mix(vec3(dielectric), albedo, metallic); // TODO: reference? } +/* clang-format off */ + FRAGMENT_SHADER_GLOBALS +/* clang-format on */ + #ifdef LIGHT_PASS void light_compute( vec3 N, @@ -504,11 +518,13 @@ void main() { vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; #endif -{ + { + /* clang-format off */ FRAGMENT_SHADER_CODE -} + /* clang-format on */ + } #if defined(ENABLE_NORMALMAP) normalmap.xy = normalmap.xy * 2.0 - 1.0; diff --git a/drivers/gles2/shaders/screen_space_reflection.glsl b/drivers/gles2/shaders/screen_space_reflection.glsl index 77af874ee4..a11da10b61 100644 --- a/drivers/gles2/shaders/screen_space_reflection.glsl +++ b/drivers/gles2/shaders/screen_space_reflection.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -13,9 +15,11 @@ void main() { pos_interp.xy = gl_Position.xy; } +/* clang-format off */ [fragment] in vec2 uv_interp; +/* clang-format on */ in vec2 pos_interp; uniform sampler2D source_diffuse; //texunit:0 diff --git a/drivers/gles2/shaders/ssao.glsl b/drivers/gles2/shaders/ssao.glsl index 8dbe8c6ba9..82eea8f274 100644 --- a/drivers/gles2/shaders/ssao.glsl +++ b/drivers/gles2/shaders/ssao.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ void main() { @@ -8,6 +10,7 @@ void main() { gl_Position.z = 1.0; } +/* clang-format off */ [fragment] #define TWO_PI 6.283185307179586476925286766559 @@ -53,6 +56,7 @@ const int ROTATIONS[] = int[]( 29, 21, 19, 27, 31, 29, 21, 18, 17, 29, 31, 31, 23, 18, 25, 26, 25, 23, 19, 34, 19, 27, 21, 25, 39, 29, 17, 21, 27); +/* clang-format on */ //#define NUM_SPIRAL_TURNS (7) const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES - 1]; diff --git a/drivers/gles2/shaders/ssao_blur.glsl b/drivers/gles2/shaders/ssao_blur.glsl index 82b735a2b4..e4133ad534 100644 --- a/drivers/gles2/shaders/ssao_blur.glsl +++ b/drivers/gles2/shaders/ssao_blur.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ void main() { @@ -8,9 +10,11 @@ void main() { gl_Position.z = 1.0; } +/* clang-format off */ [fragment] uniform sampler2D source_ssao; //texunit:0 +/* clang-format on */ uniform sampler2D source_depth; //texunit:1 uniform sampler2D source_normal; //texunit:3 @@ -43,7 +47,7 @@ const float gaussian[R + 1] = //float[](0.356642, 0.239400, 0.072410, 0.009869); //float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 - //float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 +//float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 /** (1, 0) or (0, 1)*/ uniform ivec2 axis; diff --git a/drivers/gles2/shaders/ssao_minify.glsl b/drivers/gles2/shaders/ssao_minify.glsl index 777a0069fc..272f3e236e 100644 --- a/drivers/gles2/shaders/ssao_minify.glsl +++ b/drivers/gles2/shaders/ssao_minify.glsl @@ -1,12 +1,15 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ void main() { gl_Position = vertex_attrib; } +/* clang-format off */ [fragment] #ifdef MINIFY_START @@ -14,6 +17,7 @@ void main() { #define SDEPTH_TYPE highp sampler2D uniform float camera_z_far; uniform float camera_z_near; +/* clang-format on */ #else diff --git a/drivers/gles2/shaders/subsurf_scattering.glsl b/drivers/gles2/shaders/subsurf_scattering.glsl index fb7908f06a..f40fb3a244 100644 --- a/drivers/gles2/shaders/subsurf_scattering.glsl +++ b/drivers/gles2/shaders/subsurf_scattering.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -11,6 +13,7 @@ void main() { gl_Position = vertex_attrib; } +/* clang-format off */ [fragment] //#define QUALIFIER uniform // some guy on the interweb says it may be faster with this @@ -18,6 +21,7 @@ void main() { #ifdef USE_25_SAMPLES const int kernel_size = 25; +/* clang-format on */ QUALIFIER vec2 kernel[25] = vec2[]( vec2(0.530605, 0.0), vec2(0.000973794, -3.0), diff --git a/drivers/gles2/shaders/tonemap.glsl b/drivers/gles2/shaders/tonemap.glsl index f3f6a85565..eae3b5a1ca 100644 --- a/drivers/gles2/shaders/tonemap.glsl +++ b/drivers/gles2/shaders/tonemap.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -14,6 +16,7 @@ void main() { #endif } +/* clang-format off */ [fragment] #if !defined(GLES_OVER_GL) @@ -21,6 +24,7 @@ precision mediump float; #endif in vec2 uv_interp; +/* clang-format on */ uniform highp sampler2D source; //texunit:0 @@ -115,7 +119,7 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - 0.5) * pixel_size; return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) + - (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod))); + (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod))); } #define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod) diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 0d42635194..e4824695d5 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -136,28 +136,32 @@ typedef void (*DEBUGPROCARB)(GLenum source, typedef void (*DebugMessageCallbackARB)(DEBUGPROCARB callback, const void *userParam); -void RasterizerGLES3::initialize() { - - print_verbose("Using GLES3 video driver"); +Error RasterizerGLES3::is_viable() { #ifdef GLAD_ENABLED if (!gladLoadGL()) { ERR_PRINT("Error initializing GLAD"); + return ERR_UNAVAILABLE; } // GLVersion seems to be used for both GL and GL ES, so we need different version checks for them #ifdef OPENGL_ENABLED // OpenGL 3.3 Core Profile required - if (GLVersion.major < 3 && GLVersion.minor < 3) { + if (GLVersion.major < 3 || (GLVersion.major == 3 && GLVersion.minor < 3)) { #else // OpenGL ES 3.0 if (GLVersion.major < 3) { #endif - ERR_PRINT("Your system's graphic drivers seem not to support OpenGL 3.3 / OpenGL ES 3.0, sorry :(\n" - "Try a drivers update, buy a new GPU or try software rendering on Linux; Godot will now crash with a segmentation fault."); - OS::get_singleton()->alert("Your system's graphic drivers seem not to support OpenGL 3.3 / OpenGL ES 3.0, sorry :(\n" - "Godot Engine will self-destruct as soon as you acknowledge this error message.", - "Fatal error: Insufficient OpenGL / GLES driver support"); + return ERR_UNAVAILABLE; } +#endif // GLAD_ENABLED + return OK; +} + +void RasterizerGLES3::initialize() { + + print_verbose("Using GLES3 video driver"); + +#ifdef GLAD_ENABLED if (OS::get_singleton()->is_stdout_verbose()) { if (GLAD_GL_ARB_debug_output) { glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); @@ -167,7 +171,6 @@ void RasterizerGLES3::initialize() { print_line("OpenGL debugging not supported!"); } } - #endif // GLAD_ENABLED /* // For debugging diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index f4449ac0f9..0a264caf8f 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -62,9 +62,10 @@ public: virtual void end_frame(bool p_swap_buffers); virtual void finalize(); + static Error is_viable(); static void make_current(); - static void register_config(); + RasterizerGLES3(); ~RasterizerGLES3(); }; diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index eebdbe9493..88f14890ef 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1008,7 +1008,10 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) { light_instance->light = p_light; light_instance->light_ptr = storage->light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light_instance->light_ptr, RID()); + if (!light_instance->light_ptr) { + memdelete(light_instance); + ERR_FAIL_COND_V(!light_instance->light_ptr, RID()); + } light_instance->self = light_instance_owner.make_rid(light_instance); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 3697cccef4..0bb0e12b8e 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -6998,7 +6998,10 @@ RID RasterizerStorageGLES3::canvas_light_shadow_buffer_create(int p_width) { //printf("errnum: %x\n",status); glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); - ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID()); + if (status != GL_FRAMEBUFFER_COMPLETE) { + memdelete(cls); + ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID()); + } return canvas_light_shadow_owner.make_rid(cls); } diff --git a/drivers/gles3/shaders/blend_shape.glsl b/drivers/gles3/shaders/blend_shape.glsl index d019062ba0..a1e954e33d 100644 --- a/drivers/gles3/shaders/blend_shape.glsl +++ b/drivers/gles3/shaders/blend_shape.glsl @@ -1,3 +1,4 @@ +/* clang-format off */ [vertex] /* @@ -23,6 +24,7 @@ ARRAY_INDEX=8, /* INPUT ATTRIBS */ layout(location = 0) in highp VFORMAT vertex_attrib; +/* clang-format on */ layout(location = 1) in vec3 normal_attrib; #ifdef ENABLE_TANGENT @@ -183,8 +185,10 @@ void main() { gl_Position = vec4(0.0); } +/* clang-format off */ [fragment] void main() { } +/* clang-format on */ diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 9e99305fe7..53f563303a 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec2 vertex; +/* clang-format on */ layout(location = 3) in vec4 color_attrib; #ifdef USE_SKELETON @@ -97,16 +99,22 @@ uniform int v_frames; #if defined(USE_MATERIAL) +/* clang-format off */ layout(std140) uniform UniformData { //ubo:2 MATERIAL_UNIFORMS }; +/* clang-format on */ #endif +/* clang-format off */ + VERTEX_SHADER_GLOBALS +/* clang-format on */ + void main() { vec4 color = color_attrib; @@ -151,11 +159,13 @@ void main() { #define extra_matrix extra_matrix2 -{ + { + /* clang-format off */ VERTEX_SHADER_CODE -} + /* clang-format on */ + } #ifdef USE_NINEPATCH @@ -188,29 +198,29 @@ VERTEX_SHADER_CODE highp mat2x4 m; m = mat2x4( texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) - * bone_weights.x; + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) * + bone_weights.x; tex_ofs = ivec2(bone_indicesi.y % 256, (bone_indicesi.y / 256) * 2); m += mat2x4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) - * bone_weights.y; + texelFetch(skeleton_texture, tex_ofs, 0), + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) * + bone_weights.y; tex_ofs = ivec2(bone_indicesi.z % 256, (bone_indicesi.z / 256) * 2); m += mat2x4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) - * bone_weights.z; + texelFetch(skeleton_texture, tex_ofs, 0), + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) * + bone_weights.z; tex_ofs = ivec2(bone_indicesi.w % 256, (bone_indicesi.w / 256) * 2); m += mat2x4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) - * bone_weights.w; + texelFetch(skeleton_texture, tex_ofs, 0), + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) * + bone_weights.w; mat4 bone_matrix = skeleton_transform * transpose(mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))) * skeleton_transform_inverse; @@ -246,9 +256,11 @@ VERTEX_SHADER_CODE #endif } +/* clang-format off */ [fragment] uniform mediump sampler2D color_texture; // texunit:0 +/* clang-format on */ uniform highp vec2 color_texpixel_size; uniform mediump sampler2D normal_texture; // texunit:1 @@ -313,16 +325,22 @@ layout(location = 0) out mediump vec4 frag_color; #if defined(USE_MATERIAL) +/* clang-format off */ layout(std140) uniform UniformData { MATERIAL_UNIFORMS }; +/* clang-format on */ #endif +/* clang-format off */ + FRAGMENT_SHADER_GLOBALS +/* clang-format on */ + void light_compute( inout vec4 light, inout vec2 light_vec, @@ -339,8 +357,12 @@ void light_compute( #if defined(USE_LIGHT_SHADER_CODE) + /* clang-format off */ + LIGHT_SHADER_CODE + /* clang-format on */ + #endif } @@ -472,8 +494,12 @@ void main() { vec3 normal_map = vec3(0.0, 0.0, 1.0); #endif + /* clang-format off */ + FRAGMENT_SHADER_CODE + /* clang-format on */ + #if defined(NORMALMAP_USED) normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth); #endif diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl index b06e9076d9..68d0713385 100644 --- a/drivers/gles3/shaders/canvas_shadow.glsl +++ b/drivers/gles3/shaders/canvas_shadow.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] uniform highp mat4 projection_matrix; +/* clang-format on */ uniform highp mat4 light_matrix; uniform highp mat4 world_matrix; uniform highp float distance_norm; @@ -15,9 +17,11 @@ void main() { position_interp = gl_Position; } +/* clang-format off */ [fragment] in highp vec4 position_interp; +/* clang-format on */ #ifdef USE_RGBA_SHADOWS layout(location = 0) out lowp vec4 distance_buf; diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index e17b71df27..a5637537d2 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ #if defined(USE_CUBEMAP) || defined(USE_PANORAMA) layout(location = 4) in vec3 cube_in; #else @@ -45,6 +47,7 @@ void main() { #endif } +/* clang-format off */ [fragment] #define M_PI 3.14159265359 @@ -58,6 +61,7 @@ in vec3 cube_interp; #else in vec2 uv_interp; #endif +/* clang-format on */ #ifdef USE_ASYM_PANO uniform highp mat4 pano_transform; diff --git a/drivers/gles3/shaders/cube_to_dp.glsl b/drivers/gles3/shaders/cube_to_dp.glsl index 2911746bb7..2b74f054f9 100644 --- a/drivers/gles3/shaders/cube_to_dp.glsl +++ b/drivers/gles3/shaders/cube_to_dp.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -11,9 +13,11 @@ void main() { gl_Position = vertex_attrib; } +/* clang-format off */ [fragment] uniform highp samplerCube source_cube; //texunit:0 +/* clang-format on */ in vec2 uv_interp; uniform bool z_flip; diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl index 7f2dc5057c..f65f798ff0 100644 --- a/drivers/gles3/shaders/cubemap_filter.glsl +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec2 vertex; +/* clang-format on */ layout(location = 4) in highp vec2 uv; @@ -12,9 +14,11 @@ void main() { gl_Position = vec4(vertex, 0, 1); } +/* clang-format off */ [fragment] precision highp float; +/* clang-format on */ precision highp int; #ifdef USE_SOURCE_PANORAMA diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl index 3872ee8d1d..b67d06bc10 100644 --- a/drivers/gles3/shaders/effect_blur.glsl +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -22,11 +24,13 @@ void main() { #endif } +/* clang-format off */ [fragment] #if !defined(GLES_OVER_GL) precision mediump float; #endif +/* clang-format on */ in vec2 uv_interp; uniform sampler2D source_color; //texunit:0 diff --git a/drivers/gles3/shaders/exposure.glsl b/drivers/gles3/shaders/exposure.glsl index 18fff1ae36..759adcda06 100644 --- a/drivers/gles3/shaders/exposure.glsl +++ b/drivers/gles3/shaders/exposure.glsl @@ -1,15 +1,19 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ void main() { gl_Position = vertex_attrib; } +/* clang-format off */ [fragment] uniform highp sampler2D source_exposure; //texunit:0 +/* clang-format on */ #ifdef EXPOSURE_BEGIN diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl index 56e5545efe..8523c08597 100644 --- a/drivers/gles3/shaders/particles.glsl +++ b/drivers/gles3/shaders/particles.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 color; +/* clang-format on */ layout(location = 1) in highp vec4 velocity_active; layout(location = 2) in highp vec4 custom; layout(location = 3) in highp vec4 xform_1; @@ -45,16 +47,22 @@ out highp vec4 out_xform_3; //tfb: #if defined(USE_MATERIAL) +/* clang-format off */ layout(std140) uniform UniformData { //ubo:0 MATERIAL_UNIFORMS }; +/* clang-format on */ #endif +/* clang-format off */ + VERTEX_SHADER_GLOBALS +/* clang-format on */ + uint hash(uint x) { x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b); @@ -165,7 +173,11 @@ void main() { //execute shader { + /* clang-format off */ + VERTEX_SHADER_CODE + + /* clang-format on */ } #if !defined(DISABLE_FORCE) @@ -221,6 +233,7 @@ VERTEX_SHADER_CODE #endif //PARTICLES_COPY } +/* clang-format off */ [fragment] // any code here is never executed, stuff is filled just so it works @@ -240,10 +253,15 @@ FRAGMENT_SHADER_GLOBALS void main() { { + LIGHT_SHADER_CODE + } { + FRAGMENT_SHADER_CODE + } } +/* clang-format on */ diff --git a/drivers/gles3/shaders/resolve.glsl b/drivers/gles3/shaders/resolve.glsl index d860fa544f..d64d8308c1 100644 --- a/drivers/gles3/shaders/resolve.glsl +++ b/drivers/gles3/shaders/resolve.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -11,11 +13,13 @@ void main() { gl_Position = vertex_attrib; } +/* clang-format off */ [fragment] #if !defined(GLES_OVER_GL) precision mediump float; #endif +/* clang-format on */ in vec2 uv_interp; uniform sampler2D source_specular; // texunit:0 diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index cacce93dc5..12cbe02d0c 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1,3 +1,4 @@ +/* clang-format off */ [vertex] #define M_PI 3.14159265359 @@ -21,6 +22,7 @@ ARRAY_INDEX=8, /* INPUT ATTRIBS */ layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 1) in vec3 normal_attrib; #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) layout(location = 2) in vec4 tangent_attrib; @@ -226,16 +228,22 @@ out vec3 binormal_interp; #if defined(USE_MATERIAL) +/* clang-format off */ layout(std140) uniform UniformData { // ubo:1 MATERIAL_UNIFORMS }; +/* clang-format on */ #endif +/* clang-format off */ + VERTEX_SHADER_GLOBALS +/* clang-format on */ + #ifdef RENDER_DEPTH_DUAL_PARABOLOID out highp float dp_clip; @@ -340,32 +348,32 @@ void main() { m = mat3x4( texelFetch(skeleton_texture, tex_ofs, 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) - * bone_weights.x; + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) * + bone_weights.x; tex_ofs = ivec2(bone_indicesi.y % 256, (bone_indicesi.y / 256) * 3); m += mat3x4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) - * bone_weights.y; + texelFetch(skeleton_texture, tex_ofs, 0), + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) * + bone_weights.y; tex_ofs = ivec2(bone_indicesi.z % 256, (bone_indicesi.z / 256) * 3); m += mat3x4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) - * bone_weights.z; + texelFetch(skeleton_texture, tex_ofs, 0), + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) * + bone_weights.z; tex_ofs = ivec2(bone_indicesi.w % 256, (bone_indicesi.w / 256) * 3); m += mat3x4( - texelFetch(skeleton_texture, tex_ofs, 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) - * bone_weights.w; + texelFetch(skeleton_texture, tex_ofs, 0), + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) * + bone_weights.w; mat4 bone_matrix = transpose(mat4(m[0], m[1], m[2], vec4(0.0, 0.0, 0.0, 1.0))); @@ -374,11 +382,13 @@ void main() { #endif mat4 modelview = camera_inverse_matrix * world_matrix; -{ + { + /* clang-format off */ VERTEX_SHADER_CODE -} + /* clang-format on */ + } // using local coordinates (default) #if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED) @@ -501,6 +511,7 @@ VERTEX_SHADER_CODE #endif // USE_VERTEX_LIGHTING } +/* clang-format off */ [fragment] /* texture unit usage, N is max_texture_unity-N @@ -519,6 +530,7 @@ VERTEX_SHADER_CODE */ uniform highp mat4 world_transform; +/* clang-format on */ #define M_PI 3.14159265359 @@ -552,7 +564,6 @@ layout(std140) uniform Radiance { // ubo:2 mat4 radiance_inverse_xform; float radiance_ambient_contribution; - }; #define RADIANCE_MAX_LOD 5.0 @@ -608,16 +619,22 @@ vec3 textureDualParaboloid(sampler2D p_tex, vec3 p_vec, float p_roughness) { #if defined(USE_MATERIAL) +/* clang-format off */ layout(std140) uniform UniformData { MATERIAL_UNIFORMS }; +/* clang-format on */ #endif +/* clang-format off */ + FRAGMENT_SHADER_GLOBALS +/* clang-format on */ + layout(std140) uniform SceneData { highp mat4 projection_matrix; @@ -663,7 +680,7 @@ layout(std140) uniform SceneData { highp float fog_height_curve; }; -//directional light data + //directional light data #ifdef USE_LIGHT_DIRECTIONAL @@ -701,7 +718,6 @@ struct LightData { mediump vec4 light_clamp; mediump vec4 shadow_color_contact; highp mat4 shadow_matrix; - }; layout(std140) uniform OmniLightData { // ubo:4 @@ -916,8 +932,12 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec vec3 light = L; vec3 view = V; + /* clang-format off */ + LIGHT_SHADER_CODE + /* clang-format on */ + #else float NdotL = dot(N, L); float cNdotL = max(NdotL, 0.0); // clamped NdotL @@ -1599,11 +1619,13 @@ void main() { float sss_strength = 0.0; #endif -{ + { + /* clang-format off */ FRAGMENT_SHADER_CODE -} + /* clang-format on */ + } #if defined(ALPHA_SCISSOR_USED) if (alpha < alpha_scissor) { diff --git a/drivers/gles3/shaders/screen_space_reflection.glsl b/drivers/gles3/shaders/screen_space_reflection.glsl index 73b1ddbb0e..86546319a0 100644 --- a/drivers/gles3/shaders/screen_space_reflection.glsl +++ b/drivers/gles3/shaders/screen_space_reflection.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -13,9 +15,11 @@ void main() { pos_interp.xy = gl_Position.xy; } +/* clang-format off */ [fragment] in vec2 uv_interp; +/* clang-format on */ in vec2 pos_interp; uniform sampler2D source_diffuse; //texunit:0 diff --git a/drivers/gles3/shaders/ssao.glsl b/drivers/gles3/shaders/ssao.glsl index 2eeeac31c3..be44365169 100644 --- a/drivers/gles3/shaders/ssao.glsl +++ b/drivers/gles3/shaders/ssao.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ void main() { @@ -8,6 +10,7 @@ void main() { gl_Position.z = 1.0; } +/* clang-format off */ [fragment] #define TWO_PI 6.283185307179586476925286766559 @@ -46,8 +49,8 @@ const int ROTATIONS[] = int[]( 13, 17, 11, 17, 19, 18, 25, 18, 19, 19, 29, 21, 19, 27, 31, 29, 21, 18, 17, 29, 31, 31, 23, 18, 25, 26, 25, 23, 19, 34, - 19, 27, 21, 25, 39, 29, 17, 21, 27 -); + 19, 27, 21, 25, 39, 29, 17, 21, 27); +/* clang-format on */ //#define NUM_SPIRAL_TURNS (7) const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES - 1]; diff --git a/drivers/gles3/shaders/ssao_blur.glsl b/drivers/gles3/shaders/ssao_blur.glsl index 5526d0de18..c49ea1e957 100644 --- a/drivers/gles3/shaders/ssao_blur.glsl +++ b/drivers/gles3/shaders/ssao_blur.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ void main() { @@ -8,9 +10,11 @@ void main() { gl_Position.z = 1.0; } +/* clang-format off */ [fragment] uniform sampler2D source_ssao; //texunit:0 +/* clang-format on */ uniform sampler2D source_depth; //texunit:1 uniform sampler2D source_normal; //texunit:3 @@ -36,16 +40,14 @@ uniform int filter_scale; /** Filter radius in pixels. This will be multiplied by SCALE. */ #define R (4) - ////////////////////////////////////////////////////////////////////////////////////////////// - // Gaussian coefficients const float gaussian[R + 1] = -// float[](0.356642, 0.239400, 0.072410, 0.009869); -// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 - float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 -// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 + //float[](0.356642, 0.239400, 0.072410, 0.009869); + //float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 + float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 +//float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 /** (1, 0) or (0, 1) */ uniform ivec2 axis; diff --git a/drivers/gles3/shaders/ssao_minify.glsl b/drivers/gles3/shaders/ssao_minify.glsl index 777a0069fc..1696648dae 100644 --- a/drivers/gles3/shaders/ssao_minify.glsl +++ b/drivers/gles3/shaders/ssao_minify.glsl @@ -1,18 +1,22 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ void main() { gl_Position = vertex_attrib; } +/* clang-format off */ [fragment] #ifdef MINIFY_START #define SDEPTH_TYPE highp sampler2D uniform float camera_z_far; +/* clang-format on */ uniform float camera_z_near; #else diff --git a/drivers/gles3/shaders/subsurf_scattering.glsl b/drivers/gles3/shaders/subsurf_scattering.glsl index af0d5a0e62..f40fb3a244 100644 --- a/drivers/gles3/shaders/subsurf_scattering.glsl +++ b/drivers/gles3/shaders/subsurf_scattering.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -11,6 +13,7 @@ void main() { gl_Position = vertex_attrib; } +/* clang-format off */ [fragment] //#define QUALIFIER uniform // some guy on the interweb says it may be faster with this @@ -18,7 +21,8 @@ void main() { #ifdef USE_25_SAMPLES const int kernel_size = 25; -QUALIFIER vec2 kernel[25] = vec2[] ( +/* clang-format on */ +QUALIFIER vec2 kernel[25] = vec2[]( vec2(0.530605, 0.0), vec2(0.000973794, -3.0), vec2(0.00333804, -2.52083), @@ -43,8 +47,7 @@ QUALIFIER vec2 kernel[25] = vec2[] ( vec2(0.00700976, 1.6875), vec2(0.00500364, 2.08333), vec2(0.00333804, 2.52083), - vec2(0.000973794, 3.0) -); + vec2(0.000973794, 3.0)); #endif //USE_25_SAMPLES #ifdef USE_17_SAMPLES @@ -66,11 +69,9 @@ QUALIFIER vec2 kernel[17] = vec2[]( vec2(0.0216301, 0.78125), vec2(0.0144609, 1.125), vec2(0.0100386, 1.53125), - vec2(0.00317394, 2.0) -); + vec2(0.00317394, 2.0)); #endif //USE_17_SAMPLES - #ifdef USE_11_SAMPLES const int kernel_size = 11; QUALIFIER vec2 kernel[11] = vec2[]( @@ -84,8 +85,7 @@ QUALIFIER vec2 kernel[11] = vec2[]( vec2(0.0821904, 0.32), vec2(0.03639, 0.72), vec2(0.0192831, 1.28), - vec2(0.00471691, 2.0) -); + vec2(0.00471691, 2.0)); #endif //USE_11_SAMPLES uniform float max_radius; diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index 56876bdb72..e4aa8d5730 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -1,6 +1,8 @@ +/* clang-format off */ [vertex] layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -15,11 +17,13 @@ void main() { #endif } +/* clang-format off */ [fragment] #if !defined(GLES_OVER_GL) precision mediump float; #endif +/* clang-format on */ in vec2 uv_interp; @@ -110,10 +114,8 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5f)) * pixel_size; vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * pixel_size; - return g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + - g1x * textureLod(tex, p1, lod)) + - g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + - g1x * textureLod(tex, p3, lod)); + return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) + + (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod))); } #define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod) diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 8aab4cb521..05dfd69f58 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -329,7 +329,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo return OK; } -Error OS_Unix::kill(const ProcessID &p_pid, const int p_max_wait_msec) { +Error OS_Unix::kill(const ProcessID &p_pid) { int ret = ::kill(p_pid, SIGKILL); if (!ret) { diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index c5240231fa..95b74d23ff 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -91,7 +91,7 @@ public: virtual uint64_t get_ticks_usec() const; virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false); - virtual Error kill(const ProcessID &p_pid, const int p_max_wait_msec = -1); + virtual Error kill(const ProcessID &p_pid); virtual int get_process_id() const; virtual bool has_environment(const String &p_var) const; diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp index bbd18306a2..62870ab35c 100644 --- a/editor/editor_run.cpp +++ b/editor/editor_run.cpp @@ -196,8 +196,8 @@ Error EditorRun::run(const String &p_scene, const String p_custom_args, const Li void EditorRun::stop() { if (status != STATUS_STOP && pid != 0) { - const int max_wait_msec = GLOBAL_DEF("editor/stop_max_wait_msec", 10000); - OS::get_singleton()->kill(pid, max_wait_msec); + + OS::get_singleton()->kill(pid); } status = STATUS_STOP; diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp index 211bb7bcc9..db16f20ade 100644 --- a/editor/import/resource_importer_layered_texture.cpp +++ b/editor/import/resource_importer_layered_texture.cpp @@ -52,6 +52,7 @@ String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const { void ResourceImporterLayeredTexture::get_import_options(List<ImportOption> *r_options, int p_preset) const { r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Video RAM,Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 1 : 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/no_bptc_if_rgb"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirrored"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/filter"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/mipmaps"), p_preset == PRESET_COLOR_CORRECT ? 0 : 1)); diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index 27a16fd3dd..f282d391ff 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -429,7 +429,7 @@ bool SpatialMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) c Ref<SpatialMaterial> mat = p_resource; return mat.is_valid(); } -Ref<Resource> SpatialMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) { +Ref<Resource> SpatialMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { Ref<SpatialMaterial> mat = p_resource; ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); @@ -475,7 +475,7 @@ bool ParticlesMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) Ref<ParticlesMaterial> mat = p_resource; return mat.is_valid(); } -Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) { +Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { Ref<ParticlesMaterial> mat = p_resource; ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); @@ -513,7 +513,7 @@ bool CanvasItemMaterialConversionPlugin::handles(const Ref<Resource> &p_resource Ref<CanvasItemMaterial> mat = p_resource; return mat.is_valid(); } -Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) { +Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { Ref<CanvasItemMaterial> mat = p_resource; ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index 80a5c535b8..31a927d83f 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -109,7 +109,7 @@ class SpatialMaterialConversionPlugin : public EditorResourceConversionPlugin { public: virtual String converts_to() const; virtual bool handles(const Ref<Resource> &p_resource) const; - virtual Ref<Resource> convert(const Ref<Resource> &p_resource); + virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const; }; class ParticlesMaterialConversionPlugin : public EditorResourceConversionPlugin { @@ -117,7 +117,7 @@ class ParticlesMaterialConversionPlugin : public EditorResourceConversionPlugin public: virtual String converts_to() const; virtual bool handles(const Ref<Resource> &p_resource) const; - virtual Ref<Resource> convert(const Ref<Resource> &p_resource); + virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const; }; class CanvasItemMaterialConversionPlugin : public EditorResourceConversionPlugin { @@ -125,7 +125,7 @@ class CanvasItemMaterialConversionPlugin : public EditorResourceConversionPlugin public: virtual String converts_to() const; virtual bool handles(const Ref<Resource> &p_resource) const; - virtual Ref<Resource> convert(const Ref<Resource> &p_resource); + virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const; }; #endif // MATERIAL_EDITOR_PLUGIN_H diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 1bb7c98114..fa034c97c0 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1692,7 +1692,6 @@ void ScriptEditor::_update_script_names() { if (restoring_layout) return; - waiting_update_names = false; Set<Ref<Script> > used; Node *edited = EditorNode::get_singleton()->get_edited_scene(); if (edited) { @@ -1816,8 +1815,12 @@ void ScriptEditor::_update_script_names() { } } - _update_members_overview(); - _update_help_overview(); + if (!waiting_update_names) { + _update_members_overview(); + _update_help_overview(); + } else { + waiting_update_names = false; + } _update_members_overview_visibility(); _update_help_overview_visibility(); _update_script_colors(); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 4a9cbfe535..4390b94ece 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -356,8 +356,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { undo_redo->add_do_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region()); undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", rect_prev); } else if (node_ninepatch) { - // FIXME: Is this intentional? - } else if (node_ninepatch) { undo_redo->add_do_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect()); undo_redo->add_undo_method(node_ninepatch, "set_region_rect", rect_prev); } else if (obj_styleBox.is_valid()) { @@ -521,6 +519,10 @@ void TextureRegionEditor::_set_snap_mode(int p_mode) { else hb_grid->hide(); + if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) { + _update_autoslice(); + } + edit_draw->update(); } @@ -562,7 +564,8 @@ void TextureRegionEditor::_zoom_in() { } void TextureRegionEditor::_zoom_reset() { - if (draw_zoom == 1) return; + if (draw_zoom == 1) + return; draw_zoom = 1; edit_draw->update(); } @@ -585,25 +588,91 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) { atlas_tex->set_region(rect); } -void TextureRegionEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_PROCESS: { - if (node_sprite) { - if (node_sprite->is_region()) { +void TextureRegionEditor::_update_autoslice() { + autoslice_is_dirty = false; + autoslice_cache.clear(); - set_process(false); - EditorNode::get_singleton()->make_bottom_panel_item_visible(this); + Ref<Texture> texture = NULL; + if (node_sprite) + texture = node_sprite->get_texture(); + else if (node_ninepatch) + texture = node_ninepatch->get_texture(); + else if (obj_styleBox.is_valid()) + texture = obj_styleBox->get_texture(); + else if (atlas_tex.is_valid()) + texture = atlas_tex->get_atlas(); + + if (texture.is_null()) { + return; + } + + for (int y = 0; y < texture->get_height(); y++) { + for (int x = 0; x < texture->get_width(); x++) { + if (texture->is_pixel_opaque(x, y)) { + bool found = false; + for (List<Rect2>::Element *E = autoslice_cache.front(); E; E = E->next()) { + Rect2 grown = E->get().grow(1.5); + if (grown.has_point(Point2(x, y))) { + E->get().expand_to(Point2(x, y)); + E->get().expand_to(Point2(x + 1, y + 1)); + x = E->get().position.x + E->get().size.x - 1; + bool merged = true; + while (merged) { + merged = false; + bool queue_erase = false; + for (List<Rect2>::Element *F = autoslice_cache.front(); F; F = F->next()) { + if (queue_erase) { + autoslice_cache.erase(F->prev()); + queue_erase = false; + } + if (F == E) + continue; + if (E->get().grow(1).intersects(F->get())) { + E->get().expand_to(F->get().position); + E->get().expand_to(F->get().position + F->get().size); + if (F->prev()) { + F = F->prev(); + autoslice_cache.erase(F->next()); + } else { + queue_erase = true; + // Can't delete the first rect in the list. + } + merged = true; + } + } + } + found = true; + break; + } + } + if (!found) { + Rect2 new_rect(x, y, 1, 1); + autoslice_cache.push_back(new_rect); } - } else { - set_process(false); } - } break; - case NOTIFICATION_THEME_CHANGED: + } + } + cache_map[texture->get_rid()] = autoslice_cache; +} + +void TextureRegionEditor::_notification(int p_what) { + switch (p_what) { case NOTIFICATION_READY: { zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons")); zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons")); zoom_in->set_icon(get_icon("ZoomMore", "EditorIcons")); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) { + _update_autoslice(); + } + } break; + case MainLoop::NOTIFICATION_WM_FOCUS_IN: { + // This happens when the user leaves the Editor and returns, + // he/she could have changed the textures, so the cache is cleared + cache_map.clear(); + _edit_region(); + } break; } } @@ -709,57 +778,15 @@ void TextureRegionEditor::_edit_region() { return; } - autoslice_cache.clear(); - Ref<Image> i; - i.instance(); - if (i->load(texture->get_path()) == OK) { - BitMap bm; - bm.create_from_image_alpha(i); - for (int y = 0; y < i->get_height(); y++) { - for (int x = 0; x < i->get_width(); x++) { - if (bm.get_bit(Point2(x, y))) { - bool found = false; - for (List<Rect2>::Element *E = autoslice_cache.front(); E; E = E->next()) { - Rect2 grown = E->get().grow(1.5); - if (grown.has_point(Point2(x, y))) { - E->get().expand_to(Point2(x, y)); - E->get().expand_to(Point2(x + 1, y + 1)); - x = E->get().position.x + E->get().size.x - 1; - bool merged = true; - while (merged) { - merged = false; - bool queue_erase = false; - for (List<Rect2>::Element *F = autoslice_cache.front(); F; F = F->next()) { - if (queue_erase) { - autoslice_cache.erase(F->prev()); - queue_erase = false; - } - if (F == E) - continue; - if (E->get().grow(1).intersects(F->get())) { - E->get().expand_to(F->get().position); - E->get().expand_to(F->get().position + F->get().size); - if (F->prev()) { - F = F->prev(); - autoslice_cache.erase(F->next()); - } else { - queue_erase = true; - //Can't delete the first rect in the list. - } - merged = true; - } - } - } - found = true; - break; - } - } - if (!found) { - Rect2 new_rect(x, y, 1, 1); - autoslice_cache.push_back(new_rect); - } - } - } + if (cache_map.has(texture->get_rid())) { + autoslice_cache = cache_map[texture->get_rid()]; + autoslice_is_dirty = false; + return; + } else { + if (is_visible() && snap_mode == SNAP_AUTOSLICE) { + _update_autoslice(); + } else { + autoslice_is_dirty = true; } } diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index 670cc86bbb..61ef769f89 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -92,7 +92,9 @@ class TextureRegionEditor : public Control { Rect2 rect_prev; float prev_margin; int edited_margin; + Map<RID, List<Rect2> > cache_map; List<Rect2> autoslice_cache; + bool autoslice_is_dirty; bool drag; bool creating; @@ -110,6 +112,7 @@ class TextureRegionEditor : public Control { void _zoom_reset(); void _zoom_out(); void apply_rect(const Rect2 &rect); + void _update_autoslice(); protected: void _notification(int p_what); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 34dd36692c..598f7034d8 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -457,36 +457,38 @@ void TileMapEditor::_update_palette() { palette->select(0); } - if ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE) { + if (sel_tile != TileMap::INVALID_CELL) { + if ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE) { - const Map<Vector2, uint16_t> &tiles = tileset->autotile_get_bitmask_map(sel_tile); + const Map<Vector2, uint16_t> &tiles = tileset->autotile_get_bitmask_map(sel_tile); - Vector<Vector2> entries; - for (const Map<Vector2, uint16_t>::Element *E = tiles.front(); E; E = E->next()) { - entries.push_back(E->key()); - } - entries.sort(); + Vector<Vector2> entries; + for (const Map<Vector2, uint16_t>::Element *E = tiles.front(); E; E = E->next()) { + entries.push_back(E->key()); + } + entries.sort(); - Ref<Texture> tex = tileset->tile_get_texture(sel_tile); + Ref<Texture> tex = tileset->tile_get_texture(sel_tile); - for (int i = 0; i < entries.size(); i++) { + for (int i = 0; i < entries.size(); i++) { - manual_palette->add_item(String()); + manual_palette->add_item(String()); - if (tex.is_valid()) { + if (tex.is_valid()) { - Rect2 region = tileset->tile_get_region(sel_tile); - int spacing = tileset->autotile_get_spacing(sel_tile); - region.size = tileset->autotile_get_size(sel_tile); // !! - region.position += (region.size + Vector2(spacing, spacing)) * entries[i]; + Rect2 region = tileset->tile_get_region(sel_tile); + int spacing = tileset->autotile_get_spacing(sel_tile); + region.size = tileset->autotile_get_size(sel_tile); // !! + region.position += (region.size + Vector2(spacing, spacing)) * entries[i]; - if (!region.has_no_area()) - manual_palette->set_item_icon_region(manual_palette->get_item_count() - 1, region); + if (!region.has_no_area()) + manual_palette->set_item_icon_region(manual_palette->get_item_count() - 1, region); - manual_palette->set_item_icon(manual_palette->get_item_count() - 1, tex); - } + manual_palette->set_item_icon(manual_palette->get_item_count() - 1, tex); + } - manual_palette->set_item_metadata(manual_palette->get_item_count() - 1, entries[i]); + manual_palette->set_item_metadata(manual_palette->get_item_count() - 1, entries[i]); + } } } diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 55a04a51b3..f981ead7eb 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -498,7 +498,7 @@ void TileSetEditor::_on_tileset_toolbar_button_pressed(int p_index) { } break; case TOOL_TILESET_REMOVE_TEXTURE: { if (get_current_texture().is_valid()) { - cd->set_text(TTR("Remove Selected Textue and ALL TILES wich uses it?")); + cd->set_text(TTR("Remove selected texture and ALL TILES which use it?")); cd->popup_centered(Size2(300, 60)); } else { err_dialog->set_text(TTR("You haven't selected a texture to remove.")); @@ -1715,16 +1715,18 @@ void TileSetEditor::draw_polygon_shapes() { Vector<Vector2> polygon; Vector<Color> colors; + Vector2 anchor = WORKSPACE_MARGIN; + anchor += tileset->tile_get_region(get_current_tile()).position; for (int j = 0; j < shape->get_polygon().size(); j++) { - polygon.push_back(shape->get_polygon()[j]); + polygon.push_back(shape->get_polygon()[j] + anchor); colors.push_back(c_bg); } workspace->draw_polygon(polygon, colors); for (int j = 0; j < shape->get_polygon().size() - 1; j++) { - workspace->draw_line(shape->get_polygon()[j], shape->get_polygon()[j + 1], c_border, 1, true); + workspace->draw_line(shape->get_polygon()[j] + anchor, shape->get_polygon()[j + 1] + anchor, c_border, 1, true); } - workspace->draw_line(shape->get_polygon()[shape->get_polygon().size() - 1], shape->get_polygon()[0], c_border, 1, true); + workspace->draw_line(shape->get_polygon()[shape->get_polygon().size() - 1] + anchor, shape->get_polygon()[0] + anchor, c_border, 1, true); if (shape == edited_occlusion_shape) { draw_handles = true; } @@ -1788,10 +1790,11 @@ void TileSetEditor::draw_polygon_shapes() { Vector<Vector2> polygon; Vector<Color> colors; - + Vector2 anchor = WORKSPACE_MARGIN; + anchor += tileset->tile_get_region(get_current_tile()).position; PoolVector<Vector2> vertices = shape->get_vertices(); for (int j = 0; j < shape->get_polygon(0).size(); j++) { - polygon.push_back(vertices[shape->get_polygon(0)[j]]); + polygon.push_back(vertices[shape->get_polygon(0)[j]] + anchor); colors.push_back(c_bg); } workspace->draw_polygon(polygon, colors); @@ -1799,7 +1802,7 @@ void TileSetEditor::draw_polygon_shapes() { if (shape->get_polygon_count() > 0) { PoolVector<Vector2> vertices = shape->get_vertices(); for (int j = 0; j < shape->get_polygon(0).size() - 1; j++) { - workspace->draw_line(vertices[shape->get_polygon(0)[j]], vertices[shape->get_polygon(0)[j + 1]], c_border, 1, true); + workspace->draw_line(vertices[shape->get_polygon(0)[j]] + anchor, vertices[shape->get_polygon(0)[j + 1]] + anchor, c_border, 1, true); } if (shape == edited_navigation_shape) { draw_handles = true; @@ -1954,6 +1957,8 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { void TileSetEditor::select_coord(const Vector2 &coord) { current_shape = PoolVector2Array(); + if (get_current_tile() == -1) + return; Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); current_tile_region.position += WORKSPACE_MARGIN; if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { @@ -2038,8 +2043,10 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) { anchor += tileset->tile_get_region(get_current_tile()).position; anchor += WORKSPACE_MARGIN; Rect2 region(anchor, tile_size); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { region.position = tileset->tile_get_region(get_current_tile()).position + WORKSPACE_MARGIN; + region.size = tileset->tile_get_region(get_current_tile()).size; + } if (tools[TOOL_GRID_SNAP]->is_pressed()) { p.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p.x, snap_separation.x); @@ -2254,6 +2261,9 @@ bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value tileset_editor->workspace_overlay->update(); } return v; + } else if (name == "tileset_script") { + tileset->set_script(p_value); + return true; } tileset_editor->err_dialog->set_text(TTR("This property can't be changed.")); @@ -2302,6 +2312,9 @@ bool TilesetEditorContext::_get(const StringName &p_name, Variant &r_ret) const } else if (name == "selected_occlusion") { r_ret = tileset_editor->edited_occlusion_shape; v = true; + } else if (name == "tileset_script") { + r_ret = tileset->get_script(); + v = true; } return v; } @@ -2346,6 +2359,9 @@ void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_OCCLUSION && tileset_editor->edited_occlusion_shape.is_valid()) { p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_occlusion", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_occlusion_shape->get_class())); } + if (!tileset.is_null()) { + p_list->push_back(PropertyInfo(Variant::OBJECT, "tileset_script", PROPERTY_HINT_RESOURCE_TYPE, "Script")); + } } TilesetEditorContext::TilesetEditorContext(TileSetEditor *p_tileset_editor) { diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 64638cdb1e..07b3c44807 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -1722,8 +1722,16 @@ void PhysicalBoneSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { return; Skeleton *sk(physical_bone->find_skeleton_parent()); + if (!sk) + return; + PhysicalBone *pb(sk->get_physical_bone(physical_bone->get_bone_id())); + if (!pb) + return; + PhysicalBone *pbp(sk->get_physical_bone_parent(physical_bone->get_bone_id())); + if (!pbp) + return; Vector<Vector3> points; diff --git a/main/main.cpp b/main/main.cpp index 21851337b7..a336496d39 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -830,6 +830,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph video_driver = GLOBAL_GET("rendering/quality/driver/driver_name"); } + GLOBAL_DEF("rendering/quality/driver/driver_fallback", "Best"); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/driver/driver_fallback", PropertyInfo(Variant::STRING, "rendering/quality/driver/driver_fallback", PROPERTY_HINT_ENUM, "Best,Never")); + GLOBAL_DEF("display/window/size/width", 1024); GLOBAL_DEF("display/window/size/height", 600); GLOBAL_DEF("display/window/size/resizable", true); @@ -1040,6 +1043,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) { if (err != OK) { return err; } + if (init_use_custom_pos) { OS::get_singleton()->set_window_position(init_custom_pos); } diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format index 016a43038b..4f13b2afcb 100755 --- a/misc/hooks/pre-commit-clang-format +++ b/misc/hooks/pre-commit-clang-format @@ -31,7 +31,7 @@ PARSE_EXTS=true # File types to parse. Only effective when PARSE_EXTS is true. # FILE_EXTS=".c .h .cpp .hpp" -FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m .mm .inc *.java" +FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m .mm .inc *.java *.glsl" # Use pygmentize instead of cat to parse diff with highlighting. # Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac) diff --git a/misc/travis/clang-format.sh b/misc/travis/clang-format.sh index 5463998720..ee4d0b2a10 100755 --- a/misc/travis/clang-format.sh +++ b/misc/travis/clang-format.sh @@ -11,7 +11,7 @@ else RANGE=HEAD fi -FILES=$(git diff-tree --no-commit-id --name-only -r $RANGE | grep -v thirdparty/ | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc|java)$") +FILES=$(git diff-tree --no-commit-id --name-only -r $RANGE | grep -v thirdparty/ | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc|java|glsl)$") echo "Checking files:\n$FILES" # create a random filename to store our generated patch diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp index 6b5438c60f..ecacce0bee 100644 --- a/modules/bullet/cone_twist_joint_bullet.cpp +++ b/modules/bullet/cone_twist_joint_bullet.cpp @@ -83,7 +83,9 @@ void ConeTwistJointBullet::set_param(PhysicsServer::ConeTwistJointParam p_param, coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), coneConstraint->getLimitSoftness(), coneConstraint->getBiasFactor(), p_value); break; default: - WARN_PRINT("This parameter is not supported by Bullet engine"); + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED + break; } } @@ -100,7 +102,8 @@ real_t ConeTwistJointBullet::get_param(PhysicsServer::ConeTwistJointParam p_para case PhysicsServer::CONE_TWIST_JOINT_RELAXATION: return coneConstraint->getRelaxationFactor(); default: - WARN_PRINT("This parameter is not supported by Bullet engine"); + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED; return 0; } } diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp index 6275a0d2ed..a36f1123bc 100644 --- a/modules/bullet/generic_6dof_joint_bullet.cpp +++ b/modules/bullet/generic_6dof_joint_bullet.cpp @@ -153,7 +153,9 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce = p_value; break; default: - WARN_PRINT("This parameter is not supported"); + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED + break; } } @@ -181,8 +183,9 @@ real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer::G6 case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce; default: - WARN_PRINT("This parameter is not supported"); - return 0.; + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED; + return 0; } } @@ -213,8 +216,9 @@ void Generic6DOFJointBullet::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOF sixDOFConstraint->getTranslationalLimitMotor()->m_enableMotor[p_axis] = flags[p_axis][p_flag]; break; default: - WARN_PRINT("This flag is not supported by Bullet engine"); - return; + ERR_EXPLAIN("This flag " + itos(p_flag) + " is deprecated"); + WARN_DEPRECATED + break; } } diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp index 07fde6efb9..86c6a632cd 100644 --- a/modules/bullet/hinge_joint_bullet.cpp +++ b/modules/bullet/hinge_joint_bullet.cpp @@ -95,11 +95,6 @@ real_t HingeJointBullet::get_hinge_angle() { void HingeJointBullet::set_param(PhysicsServer::HingeJointParam p_param, real_t p_value) { switch (p_param) { - case PhysicsServer::HINGE_JOINT_BIAS: - if (0 < p_value) { - WARN_PRINTS("HingeJoint doesn't support bias in the Bullet backend, so it's always 0."); - } - break; case PhysicsServer::HINGE_JOINT_LIMIT_UPPER: hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), p_value, hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor()); break; @@ -122,7 +117,9 @@ void HingeJointBullet::set_param(PhysicsServer::HingeJointParam p_param, real_t hingeConstraint->setMaxMotorImpulse(p_value); break; default: - WARN_PRINTS("HingeJoint doesn't support this parameter in the Bullet backend: " + itos(p_param) + ", value: " + itos(p_value)); + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED + break; } } @@ -146,7 +143,8 @@ real_t HingeJointBullet::get_param(PhysicsServer::HingeJointParam p_param) const case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE: return hingeConstraint->getMaxMotorImpulse(); default: - WARN_PRINTS("HingeJoint doesn't support this parameter in the Bullet backend: " + itos(p_param)); + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED; return 0; } } diff --git a/modules/bullet/pin_joint_bullet.cpp b/modules/bullet/pin_joint_bullet.cpp index c4e5b8cdbe..183a7e75b9 100644 --- a/modules/bullet/pin_joint_bullet.cpp +++ b/modules/bullet/pin_joint_bullet.cpp @@ -85,7 +85,8 @@ real_t PinJointBullet::get_param(PhysicsServer::PinJointParam p_param) const { case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP: return p2pConstraint->m_setting.m_impulseClamp; default: - WARN_PRINTS("This get parameter is not supported"); + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED return 0; } } diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index b5329bc347..4a11bec5af 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -178,7 +178,9 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf space->dynamicsWorld->convexSweepTest(bt_convex_shape, bt_xform_from, bt_xform_to, btResult, 0.002); if (btResult.hasHit()) { - p_closest_safe = p_closest_unsafe = btResult.m_closestHitFraction; + const btScalar l = bt_motion.length(); + p_closest_unsafe = btResult.m_closestHitFraction; + p_closest_safe = MAX(p_closest_unsafe - (1 - ((l - 0.01) / l)), 0); if (r_info) { if (btCollisionObject::CO_RIGID_BODY == btResult.m_hitCollisionObject->getInternalType()) { B_TO_G(static_cast<const btRigidBody *>(btResult.m_hitCollisionObject)->getVelocityInLocalPoint(btResult.m_hitPointWorld), r_info->linear_velocity); diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp index 3a371c8597..af92861352 100644 --- a/modules/cvtt/image_compress_cvtt.cpp +++ b/modules/cvtt/image_compress_cvtt.cpp @@ -247,8 +247,8 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::CompressS } dst_ofs += (MAX(4, bw) * MAX(4, bh)) >> shift; - w >>= 1; - h >>= 1; + w = MAX(w / 2, 1); + h = MAX(h / 2, 1); } if (num_job_threads > 0) { diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index e05bc7d591..33d9c011f2 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -126,7 +126,10 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco GDScriptLanguage::singleton->lock->unlock(); #endif - ERR_FAIL_COND_V(r_error.error != Variant::CallError::CALL_OK, NULL); //error constructing + if (r_error.error != Variant::CallError::CALL_OK) { + memdelete(instance); + ERR_FAIL_COND_V(r_error.error != Variant::CallError::CALL_OK, NULL); //error constructing + } } //@TODO make thread safe @@ -719,22 +722,36 @@ Error GDScript::load_byte_code(const String &p_path) { FileAccess *fa = FileAccess::open(p_path, FileAccess::READ); ERR_FAIL_COND_V(!fa, ERR_CANT_OPEN); + FileAccessEncrypted *fae = memnew(FileAccessEncrypted); ERR_FAIL_COND_V(!fae, ERR_CANT_OPEN); + Vector<uint8_t> key; key.resize(32); for (int i = 0; i < key.size(); i++) { key.write[i] = script_encryption_key[i]; } + Error err = fae->open_and_parse(fa, key, FileAccessEncrypted::MODE_READ); - ERR_FAIL_COND_V(err, err); + + if (err) { + fa->close(); + memdelete(fa); + memdelete(fae); + + ERR_FAIL_COND_V(err, err); + } + bytecode.resize(fae->get_len()); fae->get_buffer(bytecode.ptrw(), bytecode.size()); + fae->close(); memdelete(fae); + } else { bytecode = FileAccess::get_file_as_array(p_path); } + ERR_FAIL_COND_V(bytecode.size() == 0, ERR_PARSE_ERROR); path = p_path; @@ -2097,7 +2114,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_ori Error err = script->load_byte_code(p_path); if (err != OK) { - + memdelete(script); ERR_FAIL_COND_V(err != OK, RES()); } @@ -2105,7 +2122,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_ori Error err = script->load_source_code(p_path); if (err != OK) { - + memdelete(script); ERR_FAIL_COND_V(err != OK, RES()); } @@ -2120,6 +2137,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_ori return scriptres; } + void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("gd"); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 1403184557..006fbece53 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -1253,6 +1253,25 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) } break; + case GDScriptParser::OperatorNode::OP_IS_BUILTIN: { + ERR_FAIL_COND_V(on->arguments.size() != 2, false); + ERR_FAIL_COND_V(on->arguments[1]->type != GDScriptParser::Node::TYPE_TYPE, false); + + int slevel = p_stack_level; + + int src_address_a = _parse_expression(codegen, on->arguments[0], slevel); + if (src_address_a < 0) + return -1; + + if (src_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) + slevel++; //uses stack for return, increase stack + + const GDScriptParser::TypeNode *tn = static_cast<const GDScriptParser::TypeNode *>(on->arguments[1]); + + codegen.opcodes.push_back(GDScriptFunction::OPCODE_IS_BUILTIN); // perform operator + codegen.opcodes.push_back(src_address_a); // argument 1 + codegen.opcodes.push_back((int)tn->vtype); // argument 2 (unary only takes one parameter) + } break; default: { ERR_EXPLAIN("Bug in bytecode compiler, unexpected operator #" + itos(on->op) + " in parse tree while parsing expression."); @@ -1322,6 +1341,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo int ret = _parse_expression(codegen, op, p_stack_level); if (ret < 0) { + memdelete(id); + memdelete(op); return ERR_PARSE_ERROR; } @@ -1341,6 +1362,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo // compile the condition int ret = _parse_expression(codegen, branch.compiled_pattern, p_stack_level); if (ret < 0) { + memdelete(id); + memdelete(op); return ERR_PARSE_ERROR; } @@ -1353,6 +1376,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo Error err = _parse_block(codegen, branch.body, p_stack_level, p_break_addr, continue_addr); if (err) { + memdelete(id); + memdelete(op); return ERR_PARSE_ERROR; } @@ -1364,6 +1389,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo codegen.opcodes.write[break_addr + 1] = codegen.opcodes.size(); + memdelete(id); + memdelete(op); + } break; case GDScriptParser::ControlFlowNode::CF_IF: { diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 30400f01e9..d3068fb6d0 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -63,8 +63,8 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str String _template = "extends %BASE%\n" "\n" "# Declare member variables here. Examples:\n" - "# var a %INT_TYPE%= 2\n" - "# var b %STRING_TYPE%= \"text\"\n" + "# var a%INT_TYPE% = 2\n" + "# var b%STRING_TYPE% = \"text\"\n" "\n" "# Called when the node enters the scene tree for the first time.\n" "func _ready()%VOID_RETURN%:\n" @@ -76,9 +76,9 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str #ifdef TOOLS_ENABLED if (EDITOR_DEF("text_editor/completion/add_type_hints", false)) { - _template = _template.replace("%INT_TYPE%", ": int "); - _template = _template.replace("%STRING_TYPE%", ": String "); - _template = _template.replace("%FLOAT_TYPE%", " : float"); + _template = _template.replace("%INT_TYPE%", ": int"); + _template = _template.replace("%STRING_TYPE%", ": String"); + _template = _template.replace("%FLOAT_TYPE%", ": float"); _template = _template.replace("%VOID_RETURN%", " -> void"); } else { _template = _template.replace("%INT_TYPE%", ""); @@ -466,7 +466,7 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na if (th) { String type = p_args[i].get_slice(":", 1); if (!type.empty() && type != "var") { - s += " : " + type; + s += ": " + type; } } } @@ -2596,7 +2596,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } method_hint += arg; if (use_type_hint && mi.arguments[i].type != Variant::NIL) { - method_hint += " : "; + method_hint += ": "; if (mi.arguments[i].type == Variant::OBJECT && mi.arguments[i].class_name != StringName()) { method_hint += mi.arguments[i].class_name.operator String(); } else { diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index bae3f48923..d615b58b24 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -191,6 +191,7 @@ static String _get_var_type(const Variant *p_type) { static const void *switch_table_ops[] = { \ &&OPCODE_OPERATOR, \ &&OPCODE_EXTENDS_TEST, \ + &&OPCODE_IS_BUILTIN, \ &&OPCODE_SET, \ &&OPCODE_GET, \ &&OPCODE_SET_NAMED, \ @@ -536,6 +537,21 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_IS_BUILTIN) { + + CHECK_SPACE(4); + + GET_VARIANT_PTR(value, 1); + Variant::Type var_type = (Variant::Type)_code_ptr[ip + 2]; + GET_VARIANT_PTR(dst, 3); + + GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX); + + *dst = value->get_type() == var_type; + ip += 4; + } + DISPATCH_OPCODE; + OPCODE(OPCODE_SET) { CHECK_SPACE(3); diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 3ce84290fd..633cca35d3 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -136,6 +136,7 @@ public: enum Opcode { OPCODE_OPERATOR, OPCODE_EXTENDS_TEST, + OPCODE_IS_BUILTIN, OPCODE_SET, OPCODE_GET, OPCODE_SET_NAMED, diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index a3f5e1819e..7502f09d8a 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -861,6 +861,20 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s op->arguments.push_back(subexpr); expr=op;*/ + } else if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_IS && tokenizer->get_token(1) == GDScriptTokenizer::TK_BUILT_IN_TYPE) { + // 'is' operator with built-in type + OperatorNode *op = alloc_node<OperatorNode>(); + op->op = OperatorNode::OP_IS_BUILTIN; + op->arguments.push_back(expr); + + tokenizer->advance(); + + TypeNode *tn = alloc_node<TypeNode>(); + tn->vtype = tokenizer->get_token_type(); + op->arguments.push_back(tn); + tokenizer->advance(); + + expr = op; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_BRACKET_OPEN) { // array tokenizer->advance(); @@ -1071,6 +1085,15 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s expr = op; + } else if (tokenizer->get_token() == GDScriptTokenizer::TK_BUILT_IN_TYPE && expression.size() > 0 && expression[expression.size() - 1].is_op && expression[expression.size() - 1].op == OperatorNode::OP_IS) { + Expression e = expression[expression.size() - 1]; + e.op = OperatorNode::OP_IS_BUILTIN; + expression.write[expression.size() - 1] = e; + + TypeNode *tn = alloc_node<TypeNode>(); + tn->vtype = tokenizer->get_token_type(); + expr = tn; + tokenizer->advance(); } else { //find list [ or find dictionary { @@ -1329,6 +1352,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s switch (expression[i].op) { case OperatorNode::OP_IS: + case OperatorNode::OP_IS_BUILTIN: priority = -1; break; //before anything @@ -3915,14 +3939,15 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "FLAGS") { - //current_export.hint=PROPERTY_HINT_ALL_FLAGS; tokenizer->advance(); if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { + ERR_EXPLAIN("Exporting bit flags hint requires string constants."); + WARN_DEPRECATED break; } if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { - _set_error("Expected ')' or ',' in bit flags hint."); + _set_error("Expected ',' in bit flags hint."); return; } @@ -5793,6 +5818,13 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { case Node::TYPE_CONSTANT: { node_type = _type_from_variant(static_cast<ConstantNode *>(p_node)->value); } break; + case Node::TYPE_TYPE: { + TypeNode *tn = static_cast<TypeNode *>(p_node); + node_type.has_type = true; + node_type.is_meta_type = true; + node_type.kind = DataType::BUILTIN; + node_type.builtin_type = tn->vtype; + } break; case Node::TYPE_ARRAY: { node_type.has_type = true; node_type.kind = DataType::BUILTIN; @@ -5896,7 +5928,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { // yield can return anything node_type.has_type = false; } break; - case OperatorNode::OP_IS: { + case OperatorNode::OP_IS: + case OperatorNode::OP_IS_BUILTIN: { if (op->arguments.size() != 2) { _set_error("Parser bug: binary operation without 2 arguments.", op->line); @@ -5913,8 +5946,11 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { } type_type.is_meta_type = false; // Test the actual type if (!_is_type_compatible(type_type, value_type) && !_is_type_compatible(value_type, type_type)) { - // TODO: Make this a warning? - _set_error("A value of type '" + value_type.to_string() + "' will never be an instance of '" + type_type.to_string() + "'.", op->line); + if (op->op == OperatorNode::OP_IS) { + _set_error("A value of type '" + value_type.to_string() + "' will never be an instance of '" + type_type.to_string() + "'.", op->line); + } else { + _set_error("A value of type '" + value_type.to_string() + "' will never be of type '" + type_type.to_string() + "'.", op->line); + } return DataType(); } } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index dbe523a0b9..3c51e3f372 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -345,6 +345,7 @@ public: OP_PARENT_CALL, OP_YIELD, OP_IS, + OP_IS_BUILTIN, //indexing operator OP_INDEX, OP_INDEX_NAMED, diff --git a/modules/mobile_vr/shaders/lens_distorted.glsl b/modules/mobile_vr/shaders/lens_distorted.glsl index 5a2975d737..92604c891c 100644 --- a/modules/mobile_vr/shaders/lens_distorted.glsl +++ b/modules/mobile_vr/shaders/lens_distorted.glsl @@ -1,7 +1,9 @@ +/* clang-format off */ [vertex] -layout(location=0) in highp vec4 vertex_attrib; -layout(location=4) in vec2 uv_in; +layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ +layout(location = 4) in vec2 uv_in; uniform float offset_x; @@ -9,13 +11,15 @@ out vec2 uv_interp; void main() { - uv_interp = uv_in; - gl_Position = vec4(vertex_attrib.x + offset_x, vertex_attrib.y, 0.0, 1.0); + uv_interp = uv_in; + gl_Position = vec4(vertex_attrib.x + offset_x, vertex_attrib.y, 0.0, 1.0); } +/* clang-format off */ [fragment] uniform sampler2D source; //texunit:0 +/* clang-format on */ uniform vec2 eye_center; uniform float k1; @@ -28,32 +32,31 @@ in vec2 uv_interp; layout(location = 0) out vec4 frag_color; void main() { - vec2 coords = uv_interp; - vec2 offset = coords - eye_center; - - // take aspect ratio into account - offset.y /= aspect_ratio; - - // distort - vec2 offset_sq = offset * offset; - float radius_sq = offset_sq.x + offset_sq.y; - float radius_s4 = radius_sq * radius_sq; - float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4); - offset *= distortion_scale; - - // reapply aspect ratio - offset.y *= aspect_ratio; - - // add our eye center back in - coords = offset + eye_center; - coords /= upscale; - - // and check our color - if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) { - frag_color = vec4(0.0, 0.0, 0.0, 1.0); - } else { - coords = (coords + vec2(1.0)) / vec2(2.0); - frag_color = textureLod(source, coords, 0.0); - } + vec2 coords = uv_interp; + vec2 offset = coords - eye_center; + + // take aspect ratio into account + offset.y /= aspect_ratio; + + // distort + vec2 offset_sq = offset * offset; + float radius_sq = offset_sq.x + offset_sq.y; + float radius_s4 = radius_sq * radius_sq; + float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4); + offset *= distortion_scale; + + // reapply aspect ratio + offset.y *= aspect_ratio; + + // add our eye center back in + coords = offset + eye_center; + coords /= upscale; + + // and check our color + if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) { + frag_color = vec4(0.0, 0.0, 0.0, 1.0); + } else { + coords = (coords + vec2(1.0)) / vec2(2.0); + frag_color = textureLod(source, coords, 0.0); + } } - diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index b8b77924f7..d2a861dbe8 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1013,6 +1013,69 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) { #endif } +void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) { + + Reference *ref_owner = Object::cast_to<Reference>(p_object); + +#ifdef DEBUG_ENABLED + CRASH_COND(!ref_owner); +#endif + + void *data = p_object->get_script_instance_binding(get_language_index()); + if (!data) + return; + Ref<MonoGCHandle> &gchandle = ((Map<Object *, Ref<MonoGCHandle> >::Element *)data)->get(); + + if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + // The reference count was increased after the managed side was the only one referencing our owner. + // This means the owner is being referenced again by the unmanaged side, + // so the owner must hold the managed side alive again to avoid it from being GCed. + + MonoObject *target = gchandle->get_target(); + if (!target) + return; // Called after the managed side was collected, so nothing to do here + + // Release the current weak handle and replace it with a strong handle. + uint32_t strong_gchandle = MonoGCHandle::make_strong_handle(target); + gchandle->release(); + gchandle->set_handle(strong_gchandle, MonoGCHandle::STRONG_HANDLE); + } +} + +bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) { + + Reference *ref_owner = Object::cast_to<Reference>(p_object); + +#ifdef DEBUG_ENABLED + CRASH_COND(!ref_owner); +#endif + + int refcount = ref_owner->reference_get_count(); + + void *data = p_object->get_script_instance_binding(get_language_index()); + if (!data) + return refcount == 0; + Ref<MonoGCHandle> &gchandle = ((Map<Object *, Ref<MonoGCHandle> >::Element *)data)->get(); + + if (refcount == 1 && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + // If owner owner is no longer referenced by the unmanaged side, + // the managed instance takes responsibility of deleting the owner when GCed. + + MonoObject *target = gchandle->get_target(); + if (!target) + return refcount == 0; // Called after the managed side was collected, so nothing to do here + + // Release the current strong handle and replace it with a weak handle. + uint32_t weak_gchandle = MonoGCHandle::make_weak_handle(target); + gchandle->release(); + gchandle->set_handle(weak_gchandle, MonoGCHandle::WEAK_HANDLE); + + return false; + } + + return refcount == 0; +} + CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const Ref<MonoGCHandle> &p_gchandle) { CSharpInstance *instance = memnew(CSharpInstance); @@ -1303,11 +1366,13 @@ void CSharpInstance::mono_object_disposed() { void CSharpInstance::refcount_incremented() { +#ifdef DEBUG_ENABLED CRASH_COND(!base_ref); +#endif Reference *ref_owner = Object::cast_to<Reference>(owner); - if (ref_owner->reference_get_count() > 1) { // The managed side also holds a reference, hence 1 instead of 0 + if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 // The reference count was increased after the managed side was the only one referencing our owner. // This means the owner is being referenced again by the unmanaged side, // so the owner must hold the managed side alive again to avoid it from being GCed. @@ -1315,26 +1380,28 @@ void CSharpInstance::refcount_incremented() { // Release the current weak handle and replace it with a strong handle. uint32_t strong_gchandle = MonoGCHandle::make_strong_handle(gchandle->get_target()); gchandle->release(); - gchandle->set_handle(strong_gchandle); + gchandle->set_handle(strong_gchandle, MonoGCHandle::STRONG_HANDLE); } } bool CSharpInstance::refcount_decremented() { +#ifdef DEBUG_ENABLED CRASH_COND(!base_ref); +#endif Reference *ref_owner = Object::cast_to<Reference>(owner); int refcount = ref_owner->reference_get_count(); - if (refcount == 1) { // The managed side also holds a reference, hence 1 instead of 0 + if (refcount == 1 && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 // If owner owner is no longer referenced by the unmanaged side, // the managed instance takes responsibility of deleting the owner when GCed. // Release the current strong handle and replace it with a weak handle. uint32_t weak_gchandle = MonoGCHandle::make_weak_handle(gchandle->get_target()); gchandle->release(); - gchandle->set_handle(weak_gchandle); + gchandle->set_handle(weak_gchandle, MonoGCHandle::WEAK_HANDLE); return false; } diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 53644eafae..1a5d0c8a69 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -346,6 +346,8 @@ public: // Don't use these. I'm watching you virtual void *alloc_instance_binding_data(Object *p_object); virtual void free_instance_binding_data(void *p_data); + virtual void refcount_incremented_instance_binding(Object *p_object); + virtual bool refcount_decremented_instance_binding(Object *p_object); #ifdef DEBUG_ENABLED Vector<StackInfo> stack_trace_get_info(MonoObject *p_stack_trace); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index b97bb5e95f..4185f3407d 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -533,7 +533,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo cs_icalls_content.push_back("using System;\n" "using System.Runtime.CompilerServices;\n" - "using System.Collections.Generic;\n" + "using " BINDINGS_NAMESPACE_COLLECTIONS ";\n" "\n"); cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); cs_icalls_content.push_back(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK); @@ -638,7 +638,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, cs_icalls_content.push_back("using System;\n" "using System.Runtime.CompilerServices;\n" - "using System.Collections.Generic;\n" + "using " BINDINGS_NAMESPACE_COLLECTIONS ";\n" "\n"); cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); cs_icalls_content.push_back(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK); @@ -713,7 +713,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.push_back("using System;\n"); // IntPtr if (itype.requires_collections) - output.push_back("using System.Collections.Generic;\n"); // Dictionary + output.push_back("using " BINDINGS_NAMESPACE_COLLECTIONS ";\n"); // Dictionary output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); @@ -1922,7 +1922,7 @@ void BindingsGenerator::_populate_object_type_interfaces() { imethod.return_type.cname = Variant::get_type_name(return_info.type); } - if (!itype.requires_collections && imethod.return_type.cname == name_cache.type_Dictionary) + if (!itype.requires_collections && imethod.return_type.cname == name_cache.type_Dictionary || imethod.return_type.cname == name_cache.type_Array) itype.requires_collections = true; for (int i = 0; i < argc; i++) { @@ -1946,7 +1946,7 @@ void BindingsGenerator::_populate_object_type_interfaces() { iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name)); - if (!itype.requires_collections && iarg.type.cname == name_cache.type_Dictionary) + if (!itype.requires_collections && iarg.type.cname == name_cache.type_Dictionary || imethod.return_type.cname == name_cache.type_Array) itype.requires_collections = true; if (m && m->has_default_argument(i)) { @@ -2371,14 +2371,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype = TypeInterface(); itype.name = "Array"; itype.cname = itype.name; - itype.proxy_name = "Array"; + itype.proxy_name = "Collections.Array"; itype.c_out = "\treturn memnew(Array(%1));\n"; itype.c_type = itype.name; itype.c_type_in = itype.c_type + "*"; itype.c_type_out = itype.c_type + "*"; itype.cs_type = itype.proxy_name; itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()"; - itype.cs_out = "return new Array(%0);"; + itype.cs_out = "return new Collections.Array(%0);"; itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; builtin_types.insert(itype.cname, itype); @@ -2387,14 +2387,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype = TypeInterface(); itype.name = "Dictionary"; itype.cname = itype.name; - itype.proxy_name = "Dictionary"; + itype.proxy_name = "Collections.Dictionary"; itype.c_out = "\treturn memnew(Dictionary(%1));\n"; itype.c_type = itype.name; itype.c_type_in = itype.c_type + "*"; itype.c_type_out = itype.c_type + "*"; itype.cs_type = itype.proxy_name; itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()"; - itype.cs_out = "return new Dictionary(%0);"; + itype.cs_out = "return new Collections.Dictionary(%0);"; itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; builtin_types.insert(itype.cname, itype); @@ -2441,7 +2441,7 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant:: else iarg.type.cname = Variant::get_type_name(pi.type); - if (!r_itype.requires_collections && iarg.type.cname == name_cache.type_Dictionary) + if (!r_itype.requires_collections && iarg.type.cname == name_cache.type_Dictionary || imethod.return_type.cname == name_cache.type_Array) r_itype.requires_collections = true; if ((mi.default_arguments.size() - mi.arguments.size() + i) >= 0) @@ -2457,7 +2457,7 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant:: imethod.return_type.cname = Variant::get_type_name(mi.return_val.type); } - if (!r_itype.requires_collections && imethod.return_type.cname == name_cache.type_Dictionary) + if (!r_itype.requires_collections && imethod.return_type.cname == name_cache.type_Dictionary || imethod.return_type.cname == name_cache.type_Array) r_itype.requires_collections = true; if (r_itype.class_doc) { diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index 148bb32398..bb218b49b7 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -209,32 +209,32 @@ bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoOb } void godot_register_collections_icalls() { - mono_add_internal_call("Godot.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor); - mono_add_internal_call("Godot.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor); - mono_add_internal_call("Godot.Array::godot_icall_Array_At", (void *)godot_icall_Array_At); - mono_add_internal_call("Godot.Array::godot_icall_Array_SetAt", (void *)godot_icall_Array_SetAt); - mono_add_internal_call("Godot.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count); - mono_add_internal_call("Godot.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add); - mono_add_internal_call("Godot.Array::godot_icall_Array_Clear", (void *)godot_icall_Array_Clear); - mono_add_internal_call("Godot.Array::godot_icall_Array_Contains", (void *)godot_icall_Array_Contains); - mono_add_internal_call("Godot.Array::godot_icall_Array_CopyTo", (void *)godot_icall_Array_CopyTo); - mono_add_internal_call("Godot.Array::godot_icall_Array_IndexOf", (void *)godot_icall_Array_IndexOf); - mono_add_internal_call("Godot.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert); - mono_add_internal_call("Godot.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove); - mono_add_internal_call("Godot.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt); - - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_GetValue", (void *)godot_icall_Dictionary_GetValue); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_SetValue", (void *)godot_icall_Dictionary_SetValue); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Keys", (void *)godot_icall_Dictionary_Keys); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Values", (void *)godot_icall_Dictionary_Values); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Count", (void *)godot_icall_Dictionary_Count); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Add", (void *)godot_icall_Dictionary_Add); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Clear", (void *)godot_icall_Dictionary_Clear); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Contains", (void *)godot_icall_Dictionary_Contains); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_ContainsKey", (void *)godot_icall_Dictionary_ContainsKey); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_RemoveKey", (void *)godot_icall_Dictionary_RemoveKey); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove); - mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At", (void *)godot_icall_Array_At); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", (void *)godot_icall_Array_SetAt); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Clear", (void *)godot_icall_Array_Clear); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Contains", (void *)godot_icall_Array_Contains); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_CopyTo", (void *)godot_icall_Array_CopyTo); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_IndexOf", (void *)godot_icall_Array_IndexOf); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt); + + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", (void *)godot_icall_Dictionary_GetValue); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", (void *)godot_icall_Dictionary_SetValue); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", (void *)godot_icall_Dictionary_Keys); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", (void *)godot_icall_Dictionary_Values); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", (void *)godot_icall_Dictionary_Count); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", (void *)godot_icall_Dictionary_Add); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", (void *)godot_icall_Dictionary_Clear); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", (void *)godot_icall_Dictionary_Contains); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ContainsKey", (void *)godot_icall_Dictionary_ContainsKey); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", (void *)godot_icall_Dictionary_RemoveKey); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue); } diff --git a/modules/mono/glue/cs_files/Array.cs b/modules/mono/glue/cs_files/Array.cs index 1ec4d7d20a..2f0185b1e3 100644 --- a/modules/mono/glue/cs_files/Array.cs +++ b/modules/mono/glue/cs_files/Array.cs @@ -4,7 +4,7 @@ using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace Godot +namespace Godot.Collections { class ArraySafeHandle : SafeHandle { diff --git a/modules/mono/glue/cs_files/Basis.cs b/modules/mono/glue/cs_files/Basis.cs index c280d32c61..10286f3832 100644 --- a/modules/mono/glue/cs_files/Basis.cs +++ b/modules/mono/glue/cs_files/Basis.cs @@ -426,7 +426,7 @@ namespace Godot public Basis(Quat quat) { - real_t s = 2.0f / quat.LengthSquared(); + real_t s = 2.0f / quat.LengthSquared; real_t xs = quat.x * s; real_t ys = quat.y * s; diff --git a/modules/mono/glue/cs_files/Dictionary.cs b/modules/mono/glue/cs_files/Dictionary.cs index 30d17c2a59..64cb9f935d 100644 --- a/modules/mono/glue/cs_files/Dictionary.cs +++ b/modules/mono/glue/cs_files/Dictionary.cs @@ -4,7 +4,7 @@ using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace Godot +namespace Godot.Collections { class DictionarySafeHandle : SafeHandle { diff --git a/modules/mono/glue/cs_files/MarshalUtils.cs b/modules/mono/glue/cs_files/MarshalUtils.cs index 6ad4b3dcb2..f7699a15bf 100644 --- a/modules/mono/glue/cs_files/MarshalUtils.cs +++ b/modules/mono/glue/cs_files/MarshalUtils.cs @@ -1,4 +1,5 @@ using System; +using Godot.Collections; namespace Godot { diff --git a/modules/mono/glue/cs_files/Quat.cs b/modules/mono/glue/cs_files/Quat.cs index c69c55d997..eaa027eb69 100644 --- a/modules/mono/glue/cs_files/Quat.cs +++ b/modules/mono/glue/cs_files/Quat.cs @@ -11,18 +11,11 @@ namespace Godot [StructLayout(LayoutKind.Sequential)] public struct Quat : IEquatable<Quat> { - private static readonly Quat identity = new Quat(0f, 0f, 0f, 1f); - public real_t x; public real_t y; public real_t z; public real_t w; - public static Quat Identity - { - get { return identity; } - } - public real_t this[int index] { get @@ -63,6 +56,16 @@ namespace Godot } } + public real_t Length + { + get { return Mathf.Sqrt(LengthSquared); } + } + + public real_t LengthSquared + { + get { return Dot(this); } + } + public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t t) { real_t t2 = (1.0f - t) * t * 2f; @@ -76,24 +79,20 @@ namespace Godot return x * b.x + y * b.y + z * b.z + w * b.w; } - public Quat Inverse() - { - return new Quat(-x, -y, -z, w); - } - - public real_t Length() + public Vector3 GetEuler() { - return Mathf.Sqrt(LengthSquared()); + var basis = new Basis(this); + return basis.GetEuler(); } - public real_t LengthSquared() + public Quat Inverse() { - return Dot(this); + return new Quat(-x, -y, -z, w); } public Quat Normalized() { - return this / Length(); + return this / Length; } public void Set(real_t x, real_t y, real_t z, real_t w) @@ -103,12 +102,20 @@ namespace Godot this.z = z; this.w = w; } + public void Set(Quat q) { - x = q.x; - y = q.y; - z = q.z; - w = q.w; + this = q; + } + + public void SetAxisAngle(Vector3 axis, real_t angle) + { + this = new Quat(axis, angle); + } + + public void SetEuler(Vector3 eulerYXZ) + { + this = new Quat(eulerYXZ); } public Quat Slerp(Quat b, real_t t) @@ -192,6 +199,9 @@ namespace Godot return new Vector3(q.x, q.y, q.z); } + // Static Readonly Properties + public static Quat Identity { get; } = new Quat(0f, 0f, 0f, 1f); + // Constructors public Quat(real_t x, real_t y, real_t z, real_t w) { @@ -199,15 +209,46 @@ namespace Godot this.y = y; this.z = z; this.w = w; - } + } + + public bool IsNormalized() + { + return Mathf.Abs(LengthSquared - 1) <= Mathf.Epsilon; + } + public Quat(Quat q) - { - x = q.x; - y = q.y; - z = q.z; - w = q.w; + { + this = q; + } + + public Quat(Basis basis) + { + this = basis.Quat(); } - + + public Quat(Vector3 eulerYXZ) + { + real_t half_a1 = eulerYXZ.y * (real_t)0.5; + real_t half_a2 = eulerYXZ.x * (real_t)0.5; + real_t half_a3 = eulerYXZ.z * (real_t)0.5; + + // R = Y(a1).X(a2).Z(a3) convention for Euler angles. + // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6) + // a3 is the angle of the first rotation, following the notation in this reference. + + real_t cos_a1 = Mathf.Cos(half_a1); + real_t sin_a1 = Mathf.Sin(half_a1); + real_t cos_a2 = Mathf.Cos(half_a2); + real_t sin_a2 = Mathf.Sin(half_a2); + real_t cos_a3 = Mathf.Cos(half_a3); + real_t sin_a3 = Mathf.Sin(half_a3); + + x = sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3; + y = sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3; + z = -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3; + w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3; + } + public Quat(Vector3 axis, real_t angle) { real_t d = axis.Length(); diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h index f604464e8f..39d608de9f 100644 --- a/modules/mono/godotsharp_defs.h +++ b/modules/mono/godotsharp_defs.h @@ -32,6 +32,7 @@ #define GODOTSHARP_DEFS_H #define BINDINGS_NAMESPACE "Godot" +#define BINDINGS_NAMESPACE_COLLECTIONS BINDINGS_NAMESPACE ".Collections" #define BINDINGS_GLOBAL_SCOPE_CLASS "GD" #define BINDINGS_PTR_FIELD "ptr" #define BINDINGS_NATIVE_NAME_FIELD "nativeName" diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp index 12109045e0..9f0e933a8c 100644 --- a/modules/mono/mono_gc_handle.cpp +++ b/modules/mono/mono_gc_handle.cpp @@ -44,12 +44,12 @@ uint32_t MonoGCHandle::make_weak_handle(MonoObject *p_object) { Ref<MonoGCHandle> MonoGCHandle::create_strong(MonoObject *p_object) { - return memnew(MonoGCHandle(make_strong_handle(p_object))); + return memnew(MonoGCHandle(make_strong_handle(p_object), STRONG_HANDLE)); } Ref<MonoGCHandle> MonoGCHandle::create_weak(MonoObject *p_object) { - return memnew(MonoGCHandle(make_weak_handle(p_object))); + return memnew(MonoGCHandle(make_weak_handle(p_object), WEAK_HANDLE)); } void MonoGCHandle::release() { @@ -64,9 +64,10 @@ void MonoGCHandle::release() { } } -MonoGCHandle::MonoGCHandle(uint32_t p_handle) { +MonoGCHandle::MonoGCHandle(uint32_t p_handle, HandleType p_handle_type) { released = false; + weak = p_handle_type == WEAK_HANDLE; handle = p_handle; } diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h index 9cb3ef0fbb..7eeaba30e0 100644 --- a/modules/mono/mono_gc_handle.h +++ b/modules/mono/mono_gc_handle.h @@ -40,24 +40,33 @@ class MonoGCHandle : public Reference { GDCLASS(MonoGCHandle, Reference) bool released; + bool weak; uint32_t handle; public: + enum HandleType { + STRONG_HANDLE, + WEAK_HANDLE + }; + static uint32_t make_strong_handle(MonoObject *p_object); static uint32_t make_weak_handle(MonoObject *p_object); static Ref<MonoGCHandle> create_strong(MonoObject *p_object); static Ref<MonoGCHandle> create_weak(MonoObject *p_object); + _FORCE_INLINE_ bool is_weak() { return weak; } + _FORCE_INLINE_ MonoObject *get_target() const { return released ? NULL : mono_gchandle_get_target(handle); } - _FORCE_INLINE_ void set_handle(uint32_t p_handle) { - handle = p_handle; + _FORCE_INLINE_ void set_handle(uint32_t p_handle, HandleType p_handle_type) { released = false; + weak = p_handle_type == WEAK_HANDLE; + handle = p_handle; } void release(); - MonoGCHandle(uint32_t p_handle); + MonoGCHandle(uint32_t p_handle, HandleType p_handle_type); ~MonoGCHandle(); }; diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index bebc3b863f..c1f56bc3d2 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -156,6 +156,7 @@ void MonoCache::cleanup() { } #define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class)) +#define GODOT_API_NS_CLAS(m_ns, m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(m_ns, #m_class)) void update_corlib_cache() { @@ -206,8 +207,8 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control)); CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial)); CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef)); - CACHE_CLASS_AND_CHECK(Array, GODOT_API_CLASS(Array)); - CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_CLASS(Dictionary)); + CACHE_CLASS_AND_CHECK(Array, GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)); + CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)); CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils)); #ifdef DEBUG_ENABLED @@ -234,8 +235,8 @@ void update_godot_api_cache() { CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD)); CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD)); - CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_CLASS(Array)->get_method_thunk("GetPtr", 0)); - CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_CLASS(Dictionary)->get_method_thunk("GetPtr", 0)); + CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method_thunk("GetPtr", 0)); + CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method_thunk("GetPtr", 0)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsArrayGenericType, (IsArrayGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsArrayGenericType", 1)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsDictionaryGenericType, (IsDictionaryGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsDictionaryGenericType", 1)); CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("SignalCallback", 1)); diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp index 54720652fa..add1e506ea 100644 --- a/modules/mono/signal_awaiter_utils.cpp +++ b/modules/mono/signal_awaiter_utils.cpp @@ -42,8 +42,7 @@ Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p ERR_FAIL_NULL_V(p_source, ERR_INVALID_DATA); ERR_FAIL_NULL_V(p_target, ERR_INVALID_DATA); - uint32_t awaiter_handle = MonoGCHandle::make_strong_handle(p_awaiter); - Ref<SignalAwaiterHandle> sa_con = memnew(SignalAwaiterHandle(awaiter_handle)); + Ref<SignalAwaiterHandle> sa_con = memnew(SignalAwaiterHandle(p_awaiter)); #ifdef DEBUG_ENABLED sa_con->set_connection_target(p_target); #endif @@ -119,8 +118,8 @@ void SignalAwaiterHandle::_bind_methods() { ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &SignalAwaiterHandle::_signal_callback, MethodInfo("_signal_callback")); } -SignalAwaiterHandle::SignalAwaiterHandle(uint32_t p_managed_handle) : - MonoGCHandle(p_managed_handle) { +SignalAwaiterHandle::SignalAwaiterHandle(MonoObject *p_managed) : + MonoGCHandle(MonoGCHandle::make_strong_handle(p_managed), STRONG_HANDLE) { #ifdef DEBUG_ENABLED conn_target_id = 0; diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h index a6a205ff8d..1920432709 100644 --- a/modules/mono/signal_awaiter_utils.h +++ b/modules/mono/signal_awaiter_utils.h @@ -64,7 +64,7 @@ public: } #endif - SignalAwaiterHandle(uint32_t p_managed_handle); + SignalAwaiterHandle(MonoObject *p_managed); ~SignalAwaiterHandle(); }; diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp index 733f32277b..bdd3e31eb8 100644 --- a/modules/regex/regex.cpp +++ b/modules/regex/regex.cpp @@ -205,6 +205,8 @@ Error RegEx::compile(const String &p_pattern) { code = pcre2_compile_16(p, pattern.length(), flags, &err, &offset, cctx); + pcre2_compile_context_free_16(cctx); + if (!code) { PCRE2_UCHAR16 buf[256]; pcre2_get_error_message_16(err, buf, 256); @@ -221,6 +223,8 @@ Error RegEx::compile(const String &p_pattern) { code = pcre2_compile_32(p, pattern.length(), flags, &err, &offset, cctx); + pcre2_compile_context_free_32(cctx); + if (!code) { PCRE2_UCHAR32 buf[256]; pcre2_get_error_message_32(err, buf, 256); @@ -285,6 +289,8 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end) if (res < 0) { pcre2_match_data_free_32(match); + pcre2_match_context_free_32(mctx); + return NULL; } diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp index 653dd82351..bb8a4bdbea 100644 --- a/modules/squish/image_compress_squish.cpp +++ b/modules/squish/image_compress_squish.cpp @@ -193,8 +193,8 @@ void image_compress_squish(Image *p_image, float p_lossy_quality, Image::Compres int src_ofs = p_image->get_mipmap_offset(i); squish::CompressImage(&rb[src_ofs], w, h, &wb[dst_ofs], squish_comp); dst_ofs += (MAX(4, bw) * MAX(4, bh)) >> shift; - w >>= 1; - h >>= 1; + w = MAX(w / 2, 1); + h = MAX(h / 2, 1); } rb = PoolVector<uint8_t>::Read(); diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp index 0abefe11ee..b19bcfefcb 100644 --- a/modules/tinyexr/image_loader_tinyexr.cpp +++ b/modules/tinyexr/image_loader_tinyexr.cpp @@ -129,15 +129,45 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f PoolVector<uint8_t> imgdata; Image::Format format; + int output_channels = 0; if (idxA > 0) { imgdata.resize(exr_image.width * exr_image.height * 8); //RGBA16 format = Image::FORMAT_RGBAH; + output_channels = 4; } else { imgdata.resize(exr_image.width * exr_image.height * 6); //RGB16 format = Image::FORMAT_RGBH; + output_channels = 3; + } + + EXRTile single_image_tile; + int num_tiles; + int tile_width = 0; + int tile_height = 0; + + const EXRTile *exr_tiles; + + if (!exr_header.tiled) { + single_image_tile.images = exr_image.images; + single_image_tile.width = exr_image.width; + single_image_tile.height = exr_image.height; + single_image_tile.level_x = exr_image.width; + single_image_tile.level_y = exr_image.height; + single_image_tile.offset_x = 0; + single_image_tile.offset_y = 0; + + exr_tiles = &single_image_tile; + num_tiles = 1; + tile_width = exr_image.width; + tile_height = exr_image.height; + } else { + tile_width = exr_header.tile_size_x; + tile_height = exr_header.tile_size_y; + num_tiles = exr_image.num_tiles; + exr_tiles = exr_image.tiles; } { @@ -145,22 +175,51 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f uint16_t *iw = (uint16_t *)wd.ptr(); // Assume `out_rgba` have enough memory allocated. - for (int i = 0; i < exr_image.width * exr_image.height; i++) { + for (int tile_index = 0; tile_index < num_tiles; tile_index++) { - Color color( - reinterpret_cast<float **>(exr_image.images)[idxR][i], - reinterpret_cast<float **>(exr_image.images)[idxG][i], - reinterpret_cast<float **>(exr_image.images)[idxB][i]); + const EXRTile &tile = exr_tiles[tile_index]; - if (p_force_linear) - color = color.to_linear(); + int tw = tile.width; + int th = tile.height; - *iw++ = Math::make_half_float(color.r); - *iw++ = Math::make_half_float(color.g); - *iw++ = Math::make_half_float(color.b); + const float *r_channel_start = reinterpret_cast<const float *>(tile.images[idxR]); + const float *g_channel_start = reinterpret_cast<const float *>(tile.images[idxG]); + const float *b_channel_start = reinterpret_cast<const float *>(tile.images[idxB]); + const float *a_channel_start = NULL; if (idxA > 0) { - *iw++ = Math::make_half_float(reinterpret_cast<float **>(exr_image.images)[idxA][i]); + a_channel_start = reinterpret_cast<const float *>(tile.images[idxA]); + } + + uint16_t *first_row_w = iw + (tile.offset_y * tile_height * exr_image.width + tile.offset_x * tile_width) * output_channels; + + for (int y = 0; y < th; y++) { + const float *r_channel = r_channel_start + y * tile_width; + const float *g_channel = g_channel_start + y * tile_width; + const float *b_channel = b_channel_start + y * tile_width; + const float *a_channel = NULL; + + if (a_channel_start) { + a_channel = a_channel_start + y * tile_width; + } + + uint16_t *row_w = first_row_w + (y * exr_image.width * output_channels); + + for (int x = 0; x < tw; x++) { + + Color color(*r_channel++, *g_channel++, *b_channel++); + + if (p_force_linear) + color = color.to_linear(); + + *row_w++ = Math::make_half_float(color.r); + *row_w++ = Math::make_half_float(color.g); + *row_w++ = Math::make_half_float(color.b); + + if (idxA > 0) { + *row_w++ = Math::make_half_float(*a_channel++); + } + } } } } diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index b76b0d5dbe..5c8d9e078f 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1591,8 +1591,11 @@ public: String apkfname = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb"; String fullpath = p_path.get_base_dir().plus_file(apkfname); err = save_pack(p_preset, fullpath); + if (err != OK) { + unzClose(pkg); EditorNode::add_io_error("Could not write expansion package file: " + apkfname); + return OK; } diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index c8bdf98923..74c40bde72 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -62,12 +62,19 @@ public: int OS_Android::get_video_driver_count() const { - return 1; + return 2; } const char *OS_Android::get_video_driver_name(int p_driver) const { - return "GLES2"; + switch (p_driver) { + case VIDEO_DRIVER_GLES3: + return "GLES3"; + case VIDEO_DRIVER_GLES2: + return "GLES2"; + } + ERR_EXPLAIN("Invalid video driver index " + itos(p_driver)); + ERR_FAIL_V(NULL); } int OS_Android::get_audio_driver_count() const { @@ -132,26 +139,55 @@ Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int bool use_gl3 = get_gl_version_code_func() >= 0x00030000; use_gl3 = use_gl3 && (GLOBAL_GET("rendering/quality/driver/driver_name") == "GLES3"); - use_gl2 = !use_gl3; - - if (gfx_init_func) - gfx_init_func(gfx_init_ud, use_gl2); + bool gl_initialization_error = false; + + while (true) { + if (use_gl3) { + if (RasterizerGLES3::is_viable() == OK) { + if (gfx_init_func) + gfx_init_func(gfx_init_ud, false); + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); + break; + } else { + if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best") { + p_video_driver = VIDEO_DRIVER_GLES2; + use_gl3 = false; + continue; + } else { + gl_initialization_error = true; + break; + } + } + } else { + if (RasterizerGLES2::is_viable() == OK) { + if (gfx_init_func) + gfx_init_func(gfx_init_ud, true); + RasterizerGLES2::register_config(); + RasterizerGLES2::make_current(); + break; + } else { + gl_initialization_error = true; + break; + } + } + } - if (use_gl2) { - RasterizerGLES2::register_config(); - RasterizerGLES2::make_current(); - video_driver_index = VIDEO_DRIVER_GLES2; - } else { - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); - video_driver_index = VIDEO_DRIVER_GLES3; + if (gl_initialization_error) { + OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.\n" + "Please try updating your Android version.", + "Unable to initialize Video driver"); + return ERR_UNAVAILABLE; } + video_driver_index = p_video_driver; + visual_server = memnew(VisualServerRaster); /* if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { visual_server = memnew(VisualServerWrapMT(visual_server, false)); };*/ + visual_server->init(); // visual_server->cursor_set_visible(false, 0); diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index a4538a6673..addef61ec7 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -99,8 +99,11 @@ int OSIPhone::get_current_video_driver() const { Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { - video_driver_index = p_video_driver; //this may be misleading + video_driver_index = VIDEO_DRIVER_GLES3; + if (RasterizerGLES3::is_viable() != OK) { + return ERR_UNAVAILABLE; + } RasterizerGLES3::register_config(); RasterizerGLES3::make_current(); diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 5a8a05d4df..80699b0d32 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -652,23 +652,57 @@ Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, attributes.alpha = false; attributes.antialias = false; ERR_FAIL_INDEX_V(p_video_driver, VIDEO_DRIVER_MAX, ERR_INVALID_PARAMETER); - switch (p_video_driver) { - case VIDEO_DRIVER_GLES3: - attributes.majorVersion = 2; - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); - break; - case VIDEO_DRIVER_GLES2: - attributes.majorVersion = 1; - RasterizerGLES2::register_config(); - RasterizerGLES2::make_current(); - break; + + bool gles3 = true; + if (p_video_driver == VIDEO_DRIVER_GLES2) { + gles3 = false; + } + + bool gl_initialization_error = false; + + while (true) { + if (gles3) { + if (RasterizerGLES3::is_viable() == OK) { + attributes.majorVersion = 2; + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); + break; + } else { + if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best") { + p_video_driver = VIDEO_DRIVER_GLES2; + gles3 = false; + continue; + } else { + gl_initialization_error = true; + break; + } + } + } else { + if (RasterizerGLES2::is_viable() == OK) { + attributes.majorVersion = 1; + RasterizerGLES2::register_config(); + RasterizerGLES2::make_current(); + break; + } else { + gl_initialization_error = true; + break; + } + } } - video_driver_index = p_video_driver; EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(NULL, &attributes); - ERR_EXPLAIN("WebGL " + itos(attributes.majorVersion) + ".0 not available"); - ERR_FAIL_COND_V(emscripten_webgl_make_context_current(ctx) != EMSCRIPTEN_RESULT_SUCCESS, ERR_UNAVAILABLE); + if (emscripten_webgl_make_context_current(ctx) != EMSCRIPTEN_RESULT_SUCCESS) { + gl_initialization_error = true; + } + + if (gl_initialization_error) { + OS::get_singleton()->alert("Your browser does not support any of the supported WebGL versions.\n" + "Please update your browser version.", + "Unable to initialize Video driver"); + return ERR_UNAVAILABLE; + } + + video_driver_index = p_video_driver; video_mode = p_desired; // Can't fulfil fullscreen request during start-up due to browser security. diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 41cfada723..79d7ec410a 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1276,8 +1276,6 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); } - video_driver_index = p_video_driver; - ADD_ATTR2(NSOpenGLPFAColorSize, colorBits); /* @@ -1333,22 +1331,58 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a /*** END OSX INITIALIZATION ***/ - // only opengl support here... + bool gles3 = true; if (p_video_driver == VIDEO_DRIVER_GLES2) { - RasterizerGLES2::register_config(); - RasterizerGLES2::make_current(); - } else { - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); + gles3 = false; } + bool editor = Engine::get_singleton()->is_editor_hint(); + bool gl_initialization_error = false; + + while (true) { + if (gles3) { + if (RasterizerGLES3::is_viable() == OK) { + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); + break; + } else { + if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) { + p_video_driver = VIDEO_DRIVER_GLES2; + gles3 = false; + continue; + } else { + gl_initialization_error = true; + break; + } + } + } else { + if (RasterizerGLES2::is_viable() == OK) { + RasterizerGLES2::register_config(); + RasterizerGLES2::make_current(); + break; + } else { + gl_initialization_error = true; + break; + } + } + } + + if (gl_initialization_error) { + OS::get_singleton()->alert("Your video card driver does not support any of the supported OpenGL versions.\n" + "Please update your drivers or if you have a very old or integrated GPU upgrade it.", + "Unable to initialize Video driver"); + return ERR_UNAVAILABLE; + } + + video_driver_index = p_video_driver; + visual_server = memnew(VisualServerRaster); if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD)); } - visual_server->init(); + visual_server->init(); AudioDriverManager::initialize(p_audio_driver); input = memnew(InputDefault); diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 8549a44ce5..b6c3dcf9e0 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -187,12 +187,78 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au main_loop = NULL; outside = true; + ContextEGL::Driver opengl_api_type = ContextEGL::GLES_2_0; + if (p_video_driver == VIDEO_DRIVER_GLES2) { - gl_context = memnew(ContextEGL(window, ContextEGL::GLES_2_0)); - } else { - gl_context = memnew(ContextEGL(window, ContextEGL::GLES_3_0)); + opengl_api_type = ContextEGL::GLES_2_0; + } + + bool gl_initialization_error = false; + + gl_context = NULL; + while (!gl_context) { + gl_context = memnew(ContextEGL(window, opengl_api_type)); + + if (gl_context->initialize() != OK) { + memdelete(gl_context); + gl_context = NULL; + + if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best") { + if (p_video_driver == VIDEO_DRIVER_GLES2) { + gl_initialization_error = true; + break; + } + + p_video_driver = VIDEO_DRIVER_GLES2; + opengl_api_type = ContextEGL::GLES_2_0; + } else { + gl_initialization_error = true; + break; + } + } + } + + while (true) { + if (opengl_api_type == ContextEGL::GLES_3_0) { + if (RasterizerGLES3::is_viable() == OK) { + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); + break; + } else { + if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) { + p_video_driver = VIDEO_DRIVER_GLES2; + opengl_api_type = ContextEGL::GLES_2_0; + continue; + } else { + gl_initialization_error = true; + break; + } + } + } + + if (opengl_api_type == ContextEGL::GLES_2_0) { + if (RasterizerGLES2::is_viable() == OK) { + RasterizerGLES2::register_config(); + RasterizerGLES2::make_current(); + break; + } else { + gl_initialization_error = true; + break; + } + } + } + + if (gl_initialization_error) { + OS::get_singleton()->alert("Your video card driver does not support any of the supported OpenGL versions.\n" + "Please update your drivers or if you have a very old or integrated GPU upgrade it.", + "Unable to initialize Video driver"); + return ERR_UNAVAILABLE; } - gl_context->initialize(); + + video_driver_index = p_video_driver; + gl_context->make_current(); + gl_context->set_use_vsync(video_mode.use_vsync); + VideoMode vm; vm.width = gl_context->get_window_width(); vm.height = gl_context->get_window_height(); @@ -230,19 +296,6 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au set_video_mode(vm); - gl_context->make_current(); - - if (p_video_driver == VIDEO_DRIVER_GLES2) { - RasterizerGLES2::register_config(); - RasterizerGLES2::make_current(); - } else { - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); - } - gl_context->set_use_vsync(vm.use_vsync); - - video_driver_index = p_video_driver; - visual_server = memnew(VisualServerRaster); // FIXME: Reimplement threaded rendering? Or remove? /* @@ -253,7 +306,6 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au */ visual_server->init(); - input = memnew(InputDefault); joypad = ref new JoypadUWP(input); diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp index 59435b04ea..794f6df31f 100644 --- a/platform/windows/context_gl_win.cpp +++ b/platform/windows/context_gl_win.cpp @@ -108,28 +108,24 @@ Error ContextGL_Win::initialize() { hDC = GetDC(hWnd); if (!hDC) { - MessageBox(NULL, "Can't Create A GL Device Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return ERR_CANT_CREATE; // Return FALSE } pixel_format = ChoosePixelFormat(hDC, &pfd); if (!pixel_format) // Did Windows Find A Matching Pixel Format? { - MessageBox(NULL, "Can't Find A Suitable pixel_format.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return ERR_CANT_CREATE; // Return FALSE } BOOL ret = SetPixelFormat(hDC, pixel_format, &pfd); if (!ret) // Are We Able To Set The Pixel Format? { - MessageBox(NULL, "Can't Set The pixel_format.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return ERR_CANT_CREATE; // Return FALSE } hRC = wglCreateContext(hDC); if (!hRC) // Are We Able To Get A Rendering Context? { - MessageBox(NULL, "Can't Create A Temporary GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return ERR_CANT_CREATE; // Return FALSE } @@ -151,7 +147,6 @@ Error ContextGL_Win::initialize() { if (wglCreateContextAttribsARB == NULL) //OpenGL 3.0 is not supported { - MessageBox(NULL, "Cannot get Proc Address for CreateContextAttribs", "ERROR", MB_OK | MB_ICONEXCLAMATION); wglDeleteContext(hRC); return ERR_CANT_CREATE; } @@ -159,7 +154,6 @@ Error ContextGL_Win::initialize() { HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs); if (!new_hRC) { wglDeleteContext(hRC); - MessageBox(NULL, "Can't Create An OpenGL 3.3 Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return ERR_CANT_CREATE; // Return false } wglMakeCurrent(hDC, NULL); @@ -168,7 +162,6 @@ Error ContextGL_Win::initialize() { if (!wglMakeCurrent(hDC, hRC)) // Try To Activate The Rendering Context { - MessageBox(NULL, "Can't Activate The GL 3.3 Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return ERR_CANT_CREATE; // Return FALSE } } diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index fa8717a4b8..7009df8e57 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -190,28 +190,6 @@ BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) { } } -BOOL CALLBACK _CloseWindowsEnum(HWND hWnd, LPARAM lParam) { - DWORD dwID; - - GetWindowThreadProcessId(hWnd, &dwID); - - if (dwID == (DWORD)lParam) { - PostMessage(hWnd, WM_CLOSE, 0, 0); - } - - return TRUE; -} - -bool _close_gracefully(const PROCESS_INFORMATION &pi, const DWORD dwStopWaitMsec) { - if (!EnumWindows(_CloseWindowsEnum, pi.dwProcessId)) - return false; - - if (WaitForSingleObject(pi.hProcess, dwStopWaitMsec) != WAIT_OBJECT_0) - return false; - - return true; -} - void OS_Windows::initialize_debugging() { SetConsoleCtrlHandler(HandlerRoutine, TRUE); @@ -1273,21 +1251,74 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int } #if defined(OPENGL_ENABLED) + + bool gles3_context = true; if (p_video_driver == VIDEO_DRIVER_GLES2) { - gl_context = memnew(ContextGL_Win(hWnd, false)); - gl_context->initialize(); + gles3_context = false; + } - RasterizerGLES2::register_config(); - RasterizerGLES2::make_current(); - } else { - gl_context = memnew(ContextGL_Win(hWnd, true)); - gl_context->initialize(); + bool editor = Engine::get_singleton()->is_editor_hint(); + bool gl_initialization_error = false; + + gl_context = NULL; + while (!gl_context) { + gl_context = memnew(ContextGL_Win(hWnd, gles3_context)); + + if (gl_context->initialize() != OK) { + memdelete(gl_context); + gl_context = NULL; + + if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) { + if (p_video_driver == VIDEO_DRIVER_GLES2) { + gl_initialization_error = true; + break; + } - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); + p_video_driver = VIDEO_DRIVER_GLES2; + gles3_context = false; + } else { + gl_initialization_error = true; + break; + } + } } - video_driver_index = p_video_driver; // FIXME TODO - FIX IF DRIVER DETECTION HAPPENS AND GLES2 MUST BE USED + while (true) { + if (gles3_context) { + if (RasterizerGLES3::is_viable() == OK) { + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); + break; + } else { + if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) { + p_video_driver = VIDEO_DRIVER_GLES2; + gles3_context = false; + continue; + } else { + gl_initialization_error = true; + break; + } + } + } else { + if (RasterizerGLES2::is_viable() == OK) { + RasterizerGLES2::register_config(); + RasterizerGLES2::make_current(); + break; + } else { + gl_initialization_error = true; + break; + } + } + } + + if (gl_initialization_error) { + OS::get_singleton()->alert("Your video card driver does not support any of the supported OpenGL versions.\n" + "Please update your drivers or if you have a very old or integrated GPU upgrade it.", + "Unable to initialize Video driver"); + return ERR_UNAVAILABLE; + } + + video_driver_index = p_video_driver; gl_context->set_use_vsync(video_mode.use_vsync); #endif @@ -2411,26 +2442,20 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, return OK; }; -Error OS_Windows::kill(const ProcessID &p_pid, const int p_max_wait_msec) { +Error OS_Windows::kill(const ProcessID &p_pid) { + ERR_FAIL_COND_V(!process_map->has(p_pid), FAILED); const PROCESS_INFORMATION pi = (*process_map)[p_pid].pi; process_map->erase(p_pid); - Error result; - - if (p_max_wait_msec != -1 && _close_gracefully(pi, p_max_wait_msec)) { - result = OK; - } else { - const int ret = TerminateProcess(pi.hProcess, 0); - result = ret != 0 ? OK : FAILED; - } + const int ret = TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); - return result; -} + return ret != 0 ? OK : FAILED; +}; int OS_Windows::get_process_id() const { return _getpid(); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 243d4bb328..c9fa46052a 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -259,7 +259,7 @@ public: virtual uint64_t get_ticks_usec() const; virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false); - virtual Error kill(const ProcessID &p_pid, const int p_stop_max_wait_msec = -1); + virtual Error kill(const ProcessID &p_pid); virtual int get_process_id() const; virtual bool has_environment(const String &p_var) const; diff --git a/platform/x11/context_gl_x11.cpp b/platform/x11/context_gl_x11.cpp index 5a239e326b..8c1869a1f1 100644 --- a/platform/x11/context_gl_x11.cpp +++ b/platform/x11/context_gl_x11.cpp @@ -116,9 +116,14 @@ Error ContextGL_X11::initialize() { }; int fbcount; - GLXFBConfig fbconfig; + GLXFBConfig fbconfig = 0; XVisualInfo *vi = NULL; + XSetWindowAttributes swa; + swa.event_mask = StructureNotifyMask; + swa.border_pixel = 0; + unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask; + if (OS::get_singleton()->is_layered_allowed()) { GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount); ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED); @@ -142,16 +147,10 @@ Error ContextGL_X11::initialize() { } ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED); - XSetWindowAttributes swa; - - swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone); - swa.border_pixel = 0; swa.background_pixmap = None; swa.background_pixel = 0; swa.border_pixmap = None; - swa.event_mask = StructureNotifyMask; - - x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask | CWBackPixel, &swa); + valuemask |= CWBackPixel; } else { GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount); @@ -160,42 +159,21 @@ Error ContextGL_X11::initialize() { vi = glXGetVisualFromFBConfig(x11_display, fbc[0]); fbconfig = fbc[0]; - - XSetWindowAttributes swa; - - swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone); - swa.border_pixel = 0; - swa.event_mask = StructureNotifyMask; - - x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa); } - ERR_FAIL_COND_V(!x11_window, ERR_UNCONFIGURED); - set_class_hint(x11_display, x11_window); - XMapWindow(x11_display, x11_window); - - int (*oldHandler)(Display *, XErrorEvent *) = - XSetErrorHandler(&ctxErrorHandler); + int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&ctxErrorHandler); switch (context_type) { - case GLES_2_0_COMPATIBLE: case OLDSTYLE: { + p->glx_context = glXCreateContext(x11_display, vi, 0, GL_TRUE); + ERR_FAIL_COND_V(!p->glx_context, ERR_UNCONFIGURED); } break; - /* - case ContextType::GLES_2_0_COMPATIBLE: { - - static int context_attribs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 0, - None - }; + case GLES_2_0_COMPATIBLE: { - p->glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, NULL, true, context_attribs); - ERR_EXPLAIN("Could not obtain an OpenGL 3.0 context!"); + p->glx_context = glXCreateNewContext(x11_display, fbconfig, GLX_RGBA_TYPE, 0, true); ERR_FAIL_COND_V(!p->glx_context, ERR_UNCONFIGURED); } break; - */ case GLES_3_0_COMPATIBLE: { static int context_attribs[] = { @@ -207,24 +185,22 @@ Error ContextGL_X11::initialize() { }; p->glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, NULL, true, context_attribs); - ERR_EXPLAIN("Could not obtain an OpenGL 3.3 context!"); ERR_FAIL_COND_V(ctxErrorOccurred || !p->glx_context, ERR_UNCONFIGURED); } break; } + swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone); + x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa); + + ERR_FAIL_COND_V(!x11_window, ERR_UNCONFIGURED); + set_class_hint(x11_display, x11_window); + XMapWindow(x11_display, x11_window); + XSync(x11_display, False); XSetErrorHandler(oldHandler); glXMakeCurrent(x11_display, x11_window, p->glx_context); - /* - glWrapperInit(wrapper_get_proc_address); - glFlush(); - - glXSwapBuffers(x11_display,x11_window); -*/ - //glXMakeCurrent(x11_display, None, NULL); - XFree(vi); return OK; @@ -297,7 +273,6 @@ ContextGL_X11::ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, c ContextGL_X11::~ContextGL_X11() { release_current(); glXDestroyContext(x11_display, p->glx_context); - memdelete(p); } diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 56b0c975c4..a62bd714d2 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -274,21 +274,70 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a opengl_api_type = ContextGL_X11::GLES_2_0_COMPATIBLE; } - context_gl = memnew(ContextGL_X11(x11_display, x11_window, current_videomode, opengl_api_type)); - context_gl->initialize(); + bool editor = Engine::get_singleton()->is_editor_hint(); + bool gl_initialization_error = false; - switch (opengl_api_type) { - case ContextGL_X11::GLES_2_0_COMPATIBLE: { - RasterizerGLES2::register_config(); - RasterizerGLES2::make_current(); - } break; - case ContextGL_X11::GLES_3_0_COMPATIBLE: { - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); - } break; + context_gl = NULL; + while (!context_gl) { + context_gl = memnew(ContextGL_X11(x11_display, x11_window, current_videomode, opengl_api_type)); + + if (context_gl->initialize() != OK) { + memdelete(context_gl); + context_gl = NULL; + + if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) { + if (p_video_driver == VIDEO_DRIVER_GLES2) { + gl_initialization_error = true; + break; + } + + p_video_driver = VIDEO_DRIVER_GLES2; + opengl_api_type = ContextGL_X11::GLES_2_0_COMPATIBLE; + } else { + gl_initialization_error = true; + break; + } + } + } + + while (true) { + if (opengl_api_type == ContextGL_X11::GLES_3_0_COMPATIBLE) { + if (RasterizerGLES3::is_viable() == OK) { + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); + break; + } else { + if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best" || editor) { + p_video_driver = VIDEO_DRIVER_GLES2; + opengl_api_type = ContextGL_X11::GLES_2_0_COMPATIBLE; + continue; + } else { + gl_initialization_error = true; + break; + } + } + } + + if (opengl_api_type == ContextGL_X11::GLES_2_0_COMPATIBLE) { + if (RasterizerGLES2::is_viable() == OK) { + RasterizerGLES2::register_config(); + RasterizerGLES2::make_current(); + break; + } else { + gl_initialization_error = true; + break; + } + } } - video_driver_index = p_video_driver; // FIXME TODO - FIX IF DRIVER DETECTION HAPPENS AND GLES2 MUST BE USED + if (gl_initialization_error) { + OS::get_singleton()->alert("Your video card driver does not support any of the supported OpenGL versions.\n" + "Please update your drivers or if you have a very old or integrated GPU upgrade it.", + "Unable to initialize Video driver"); + return ERR_UNAVAILABLE; + } + + video_driver_index = p_video_driver; context_gl->set_use_vsync(current_videomode.use_vsync); @@ -339,8 +388,6 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a set_window_always_on_top(true); } - AudioDriverManager::initialize(p_audio_driver); - ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE); ERR_FAIL_COND_V(x11_window == 0, ERR_UNAVAILABLE); @@ -510,6 +557,8 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a visual_server->init(); + AudioDriverManager::initialize(p_audio_driver); + input = memnew(InputDefault); window_has_focus = true; // Set focus to true at init @@ -2564,51 +2613,146 @@ void OS_X11::swap_buffers() { } void OS_X11::alert(const String &p_alert, const String &p_title) { + const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" }; + + String path = get_environment("PATH"); + Vector<String> path_elems = path.split(":", false); + String program; + + for (int i = 0; i < path_elems.size(); i++) { + for (unsigned int k = 0; k < sizeof(message_programs) / sizeof(char *); k++) { + String tested_path = path_elems[i] + "/" + message_programs[k]; + + if (FileAccess::exists(tested_path)) { + program = tested_path; + break; + } + } + + if (program.length()) + break; + } List<String> args; - args.push_back("-center"); - args.push_back("-title"); - args.push_back(p_title); - args.push_back(p_alert); - execute("xmessage", args, true); + if (program.ends_with("zenity")) { + args.push_back("--error"); + args.push_back("--width"); + args.push_back("500"); + args.push_back("--title"); + args.push_back(p_title); + args.push_back("--text"); + args.push_back(p_alert); + } + + if (program.ends_with("kdialog")) { + args.push_back("--error"); + args.push_back(p_alert); + args.push_back("--title"); + args.push_back(p_title); + } + + if (program.ends_with("Xdialog")) { + args.push_back("--title"); + args.push_back(p_title); + args.push_back("--msgbox"); + args.push_back(p_alert); + args.push_back("0"); + args.push_back("0"); + } + + if (program.ends_with("xmessage")) { + args.push_back("-center"); + args.push_back("-title"); + args.push_back(p_title); + args.push_back(p_alert); + } + + if (program.length()) { + execute(program, args, true); + } else { + print_line(p_alert); + } + + return; +} + +bool g_set_icon_error = false; +int set_icon_errorhandler(Display *dpy, XErrorEvent *ev) { + g_set_icon_error = true; + return 0; } void OS_X11::set_icon(const Ref<Image> &p_icon) { + int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&set_icon_errorhandler); + Atom net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False); if (p_icon.is_valid()) { Ref<Image> img = p_icon->duplicate(); img->convert(Image::FORMAT_RGBA8); - int w = img->get_width(); - int h = img->get_height(); + while (true) { + int w = img->get_width(); + int h = img->get_height(); + + if (g_set_icon_error) { + g_set_icon_error = false; + + WARN_PRINT("Icon too large, attempting to resize icon."); + + int new_width, new_height; + if (w > h) { + new_width = w / 2; + new_height = h * new_width / w; + } else { + new_height = h / 2; + new_width = w * new_height / h; + } + + w = new_width; + h = new_height; + + if (!w || !h) { + WARN_PRINT("Unable to set icon."); + break; + } - // We're using long to have wordsize (32Bit build -> 32 Bits, 64 Bit build -> 64 Bits - Vector<long> pd; + img->resize(w, h, Image::INTERPOLATE_CUBIC); + } - pd.resize(2 + w * h); + // We're using long to have wordsize (32Bit build -> 32 Bits, 64 Bit build -> 64 Bits + Vector<long> pd; - pd.write[0] = w; - pd.write[1] = h; + pd.resize(2 + w * h); - PoolVector<uint8_t>::Read r = img->get_data().read(); + pd.write[0] = w; + pd.write[1] = h; - long *wr = &pd.write[2]; - uint8_t const *pr = r.ptr(); + PoolVector<uint8_t>::Read r = img->get_data().read(); - for (int i = 0; i < w * h; i++) { - long v = 0; - // A R G B - v |= pr[3] << 24 | pr[0] << 16 | pr[1] << 8 | pr[2]; - *wr++ = v; - pr += 4; + long *wr = &pd.write[2]; + uint8_t const *pr = r.ptr(); + + for (int i = 0; i < w * h; i++) { + long v = 0; + // A R G B + v |= pr[3] << 24 | pr[0] << 16 | pr[1] << 8 | pr[2]; + *wr++ = v; + pr += 4; + } + + XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pd.ptr(), pd.size()); + + if (!g_set_icon_error) + break; } - XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pd.ptr(), pd.size()); } else { XDeleteProperty(x11_display, x11_window, net_wm_icon); } + XFlush(x11_display); + XSetErrorHandler(oldHandler); } void OS_X11::force_process_input() { diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp index 9b1cb1369a..69975e6195 100644 --- a/scene/animation/skeleton_ik.cpp +++ b/scene/animation/skeleton_ik.cpp @@ -54,9 +54,9 @@ FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::add_child( } /// Build a chain that starts from the root to tip -void FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain) { +bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain) { - ERR_FAIL_COND(-1 == p_task->root_bone); + ERR_FAIL_COND_V(-1 == p_task->root_bone, false); Chain &chain(p_task->chain); @@ -77,8 +77,8 @@ void FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain for (int x = p_task->end_effectors.size() - 1; 0 <= x; --x) { const EndEffector *ee(&p_task->end_effectors[x]); - ERR_FAIL_COND(p_task->root_bone >= ee->tip_bone); - ERR_FAIL_INDEX(ee->tip_bone, p_task->skeleton->get_bone_count()); + ERR_FAIL_COND_V(p_task->root_bone >= ee->tip_bone, false); + ERR_FAIL_INDEX_V(ee->tip_bone, p_task->skeleton->get_bone_count(), false); sub_chain_size = 0; // Picks all IDs that composing a single chain in reverse order (except the root) @@ -133,6 +133,7 @@ void FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain break; } } + return true; } void FabrikInverseKinematic::update_chain(const Skeleton *p_sk, ChainItem *p_chain_item) { @@ -247,7 +248,10 @@ FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleto task->end_effectors.push_back(ee); task->goal_global_transform = goal_transform; - build_chain(task); + if (!build_chain(task)) { + free_task(task); + return NULL; + } return task; } @@ -535,8 +539,10 @@ void SkeletonIK::reload_chain() { return; task = FabrikInverseKinematic::create_simple_task(skeleton, skeleton->find_bone(root_bone), skeleton->find_bone(tip_bone), _get_target_transform()); - task->max_iterations = max_iterations; - task->min_distance = min_distance; + if (task) { + task->max_iterations = max_iterations; + task->min_distance = min_distance; + } } void SkeletonIK::reload_goal() { diff --git a/scene/animation/skeleton_ik.h b/scene/animation/skeleton_ik.h index 08fb00e798..202d6959bb 100644 --- a/scene/animation/skeleton_ik.h +++ b/scene/animation/skeleton_ik.h @@ -123,7 +123,7 @@ public: private: /// Init a chain that starts from the root to tip - static void build_chain(Task *p_task, bool p_force_simple_chain = true); + static bool build_chain(Task *p_task, bool p_force_simple_chain = true); static void update_chain(const Skeleton *p_sk, ChainItem *p_chain_item); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 635f812805..9bddaa7d29 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -284,7 +284,13 @@ bool FileDialog::_is_open_should_be_disabled() { if (mode == MODE_OPEN_ANY || mode == MODE_SAVE_FILE) return false; - TreeItem *ti = tree->get_selected(); + TreeItem *ti = tree->get_next_selected(tree->get_root()); + while (ti) { + TreeItem *prev_ti = ti; + ti = tree->get_next_selected(tree->get_root()); + if (ti == prev_ti) + break; + } // We have something that we can't select? if (!ti) return mode != MODE_OPEN_DIR; // In "Open folder" mode, having nothing selected picks the current folder. @@ -328,6 +334,10 @@ void FileDialog::deselect_items() { } } +void FileDialog::_tree_multi_selected(Object *p_object, int p_cell, bool p_selected) { + _tree_selected(); +} + void FileDialog::_tree_selected() { TreeItem *ti = tree->get_selected(); @@ -754,6 +764,7 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_unhandled_input"), &FileDialog::_unhandled_input); + ClassDB::bind_method(D_METHOD("_tree_multi_selected"), &FileDialog::_tree_multi_selected); ClassDB::bind_method(D_METHOD("_tree_selected"), &FileDialog::_tree_selected); ClassDB::bind_method(D_METHOD("_tree_item_activated"), &FileDialog::_tree_item_activated); ClassDB::bind_method(D_METHOD("_dir_entered"), &FileDialog::_dir_entered); @@ -794,7 +805,7 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open File,Open Files,Open Folder,Open Any,Save"), "set_mode", "get_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access"); ADD_PROPERTY(PropertyInfo(Variant::POOL_STRING_ARRAY, "filters"), "set_filters", "get_filters"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files"); @@ -890,6 +901,7 @@ FileDialog::FileDialog() { _update_drives(); connect("confirmed", this, "_action_pressed"); + tree->connect("multi_selected", this, "_tree_multi_selected", varray(), CONNECT_DEFERRED); tree->connect("cell_selected", this, "_tree_selected", varray(), CONNECT_DEFERRED); tree->connect("item_activated", this, "_tree_item_activated", varray()); tree->connect("nothing_selected", this, "deselect_items"); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index ad483d5dab..3227f1c3a8 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -104,6 +104,7 @@ private: void update_file_list(); void update_filters(); + void _tree_multi_selected(Object *p_object, int p_cell, bool p_selected); void _tree_selected(); void _select_drive(int p_idx); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 549daecdae..1f3d5e6e13 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -866,15 +866,14 @@ void LineEdit::_notification(int p_what) { void LineEdit::copy_text() { - if (selection.enabled) { - + if (selection.enabled && !pass) { OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin)); } } void LineEdit::cut_text() { - if (selection.enabled) { + if (selection.enabled && !pass) { OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin)); selection_delete(); } diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 042cf28fec..e6ef956dc5 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -482,6 +482,11 @@ void Mesh::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint"); + ClassDB::bind_method(D_METHOD("get_surface_count"), &Mesh::get_surface_count); + ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &Mesh::surface_get_arrays); + ClassDB::bind_method(D_METHOD("surface_get_blend_shape_arrays", "surf_idx"), &Mesh::surface_get_blend_shape_arrays); + ClassDB::bind_method(D_METHOD("surface_get_material", "surf_idx"), &Mesh::surface_get_material); + BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP); @@ -1313,7 +1318,6 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ArrayMesh::get_blend_shape_mode); ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); - ClassDB::bind_method(D_METHOD("get_surface_count"), &ArrayMesh::get_surface_count); ClassDB::bind_method(D_METHOD("surface_remove", "surf_idx"), &ArrayMesh::surface_remove); ClassDB::bind_method(D_METHOD("surface_update_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_region); ClassDB::bind_method(D_METHOD("surface_get_array_len", "surf_idx"), &ArrayMesh::surface_get_array_len); @@ -1321,12 +1325,9 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("surface_get_format", "surf_idx"), &ArrayMesh::surface_get_format); ClassDB::bind_method(D_METHOD("surface_get_primitive_type", "surf_idx"), &ArrayMesh::surface_get_primitive_type); ClassDB::bind_method(D_METHOD("surface_set_material", "surf_idx", "material"), &ArrayMesh::surface_set_material); - ClassDB::bind_method(D_METHOD("surface_get_material", "surf_idx"), &ArrayMesh::surface_get_material); ClassDB::bind_method(D_METHOD("surface_find_by_name", "name"), &ArrayMesh::surface_find_by_name); ClassDB::bind_method(D_METHOD("surface_set_name", "surf_idx", "name"), &ArrayMesh::surface_set_name); ClassDB::bind_method(D_METHOD("surface_get_name", "surf_idx"), &ArrayMesh::surface_get_name); - ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &ArrayMesh::surface_get_arrays); - ClassDB::bind_method(D_METHOD("surface_get_blend_shape_arrays", "surf_idx"), &ArrayMesh::surface_get_blend_shape_arrays); ClassDB::bind_method(D_METHOD("create_trimesh_shape"), &ArrayMesh::create_trimesh_shape); ClassDB::bind_method(D_METHOD("create_convex_shape"), &ArrayMesh::create_convex_shape); ClassDB::bind_method(D_METHOD("create_outline", "margin"), &ArrayMesh::create_outline); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 3d2b6c36de..8112d6be00 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -59,7 +59,13 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { tile_set_region(id, p_value); else if (what == "tile_mode") tile_set_tile_mode(id, (TileMode)((int)p_value)); - else if (what.left(9) == "autotile/") { + else if (what == "is_autotile") { + // backward compatibility for Godot 3.0.x + // autotile used to be a bool, it's now an enum + bool is_autotile = p_value; + if (is_autotile) + tile_set_tile_mode(id, AUTO_TILE); + } else if (what.left(9) == "autotile/") { what = what.right(9); if (what == "bitmask_mode") autotile_set_bitmask_mode(id, (BitmaskMode)((int)p_value)); @@ -950,6 +956,8 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("tile_get_region", "id"), &TileSet::tile_get_region); ClassDB::bind_method(D_METHOD("tile_set_shape", "id", "shape_id", "shape"), &TileSet::tile_set_shape); ClassDB::bind_method(D_METHOD("tile_get_shape", "id", "shape_id"), &TileSet::tile_get_shape); + ClassDB::bind_method(D_METHOD("tile_set_shape_offset", "id", "shape_id", "shape_offset"), &TileSet::tile_set_shape_offset); + ClassDB::bind_method(D_METHOD("tile_get_shape_offset", "id", "shape_id"), &TileSet::tile_get_shape_offset); ClassDB::bind_method(D_METHOD("tile_set_shape_transform", "id", "shape_id", "shape_transform"), &TileSet::tile_set_shape_transform); ClassDB::bind_method(D_METHOD("tile_get_shape_transform", "id", "shape_id"), &TileSet::tile_get_shape_transform); ClassDB::bind_method(D_METHOD("tile_set_shape_one_way", "id", "shape_id", "one_way"), &TileSet::tile_set_shape_one_way); diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index b737f4681d..db178e0df8 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -185,9 +185,13 @@ void AudioDriverManager::initialize(int p_driver) { if (drivers[i]->init() == OK) { drivers[i]->set_singleton(); - return; + break; } } + + if (driver_count > 1 && AudioDriver::get_singleton()->get_name() == "Dummy") { + WARN_PRINT("All audio drivers failed, falling back to the dummy driver."); + } } AudioDriver *AudioDriverManager::get_driver(int p_driver) { diff --git a/thirdparty/README.md b/thirdparty/README.md index 9da3d857a6..9c8884fe84 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -494,7 +494,7 @@ changes are marked with `// -- GODOT --` comments. ## tinyexr - Upstream: https://github.com/syoyo/tinyexr -- Version: git (e385dad, 2018) +- Version: git (2d5375f, 2018) - License: BSD-3-Clause Files extracted from upstream source: diff --git a/thirdparty/cvtt/ConvectionKernels.cpp b/thirdparty/cvtt/ConvectionKernels.cpp index 5137e35730..8d379344e1 100644 --- a/thirdparty/cvtt/ConvectionKernels.cpp +++ b/thirdparty/cvtt/ConvectionKernels.cpp @@ -1420,6 +1420,16 @@ namespace cvtt return v; } + static bool MakeBoolInt16(bool b) + { + return b; + } + + static bool MakeBoolFloat(bool b) + { + return b; + } + static bool AndNot(bool a, bool b) { return a && !b; diff --git a/thirdparty/tinyexr/tinyexr.h b/thirdparty/tinyexr/tinyexr.h index 107c22ffb3..990c8ee142 100644 --- a/thirdparty/tinyexr/tinyexr.h +++ b/thirdparty/tinyexr/tinyexr.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2014 - 2017, Syoyo Fujita +Copyright (c) 2014 - 2018, Syoyo Fujita and many contributors. All rights reserved. Redistribution and use in source and binary forms, with or without @@ -115,6 +115,7 @@ extern "C" { #define TINYEXR_ERROR_CANT_OPEN_FILE (-6) #define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-7) #define TINYEXR_ERROR_INVALID_HEADER (-8) +#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-9) // @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf } @@ -123,7 +124,8 @@ extern "C" { #define TINYEXR_PIXELTYPE_HALF (1) #define TINYEXR_PIXELTYPE_FLOAT (2) -#define TINYEXR_MAX_ATTRIBUTES (128) +#define TINYEXR_MAX_HEADER_ATTRIBUTES (1024) +#define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128) #define TINYEXR_COMPRESSIONTYPE_NONE (0) #define TINYEXR_COMPRESSIONTYPE_RLE (1) @@ -205,7 +207,8 @@ typedef struct _EXRHeader { // Custom attributes(exludes required attributes(e.g. `channels`, // `compression`, etc) int num_custom_attributes; - EXRAttribute custom_attributes[TINYEXR_MAX_ATTRIBUTES]; + EXRAttribute *custom_attributes; // array of EXRAttribute. size = + // `num_custom_attributes`. EXRChannelInfo *channels; // [num_channels] @@ -292,6 +295,9 @@ extern int FreeEXRHeader(EXRHeader *exr_header); // Free's internal data of EXRImage struct extern int FreeEXRImage(EXRImage *exr_image); +// Free's error message +extern void FreeEXRErrorMessage(const char *msg); + // Parse EXR version header of a file. extern int ParseEXRVersionFromFile(EXRVersion *version, const char *filename); @@ -300,10 +306,14 @@ extern int ParseEXRVersionFromMemory(EXRVersion *version, const unsigned char *memory, size_t size); // Parse single-part OpenEXR header from a file and initialize `EXRHeader`. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version, const char *filename, const char **err); // Parse single-part OpenEXR header from a memory and initialize `EXRHeader`. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern int ParseEXRHeaderFromMemory(EXRHeader *header, const EXRVersion *version, const unsigned char *memory, size_t size, @@ -311,6 +321,8 @@ extern int ParseEXRHeaderFromMemory(EXRHeader *header, // Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*` // array. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers, int *num_headers, const EXRVersion *version, @@ -319,6 +331,8 @@ extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers, // Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*` // array +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers, int *num_headers, const EXRVersion *version, @@ -330,6 +344,8 @@ extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers, // Application can free EXRImage using `FreeEXRImage` // Returns negative value and may set error string in `err` when there's an // error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header, const char *filename, const char **err); @@ -339,6 +355,8 @@ extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header, // Application can free EXRImage using `FreeEXRImage` // Returns negative value and may set error string in `err` when there's an // error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header, const unsigned char *memory, const size_t size, const char **err); @@ -349,6 +367,8 @@ extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header, // Application can free EXRImage using `FreeEXRImage` // Returns negative value and may set error string in `err` when there's an // error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern int LoadEXRMultipartImageFromFile(EXRImage *images, const EXRHeader **headers, unsigned int num_parts, @@ -361,6 +381,8 @@ extern int LoadEXRMultipartImageFromFile(EXRImage *images, // Application can free EXRImage using `FreeEXRImage` // Returns negative value and may set error string in `err` when there's an // error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern int LoadEXRMultipartImageFromMemory(EXRImage *images, const EXRHeader **headers, unsigned int num_parts, @@ -370,6 +392,8 @@ extern int LoadEXRMultipartImageFromMemory(EXRImage *images, // Saves multi-channel, single-frame OpenEXR image to a file. // Returns negative value and may set error string in `err` when there's an // error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern int SaveEXRImageToFile(const EXRImage *image, const EXRHeader *exr_header, const char *filename, const char **err); @@ -379,6 +403,8 @@ extern int SaveEXRImageToFile(const EXRImage *image, // Return the number of bytes if succes. // Returns negative value and may set error string in `err` when there's an // error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern size_t SaveEXRImageToMemory(const EXRImage *image, const EXRHeader *exr_header, unsigned char **memory, const char **err); @@ -387,6 +413,8 @@ extern size_t SaveEXRImageToMemory(const EXRImage *image, // Application must free memory of variables in DeepImage(image, offset_table) // Returns negative value and may set error string in `err` when there's an // error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern int LoadDeepEXR(DeepImage *out_image, const char *filename, const char **err); @@ -409,6 +437,8 @@ extern int LoadDeepEXR(DeepImage *out_image, const char *filename, // RGB(A) channels. // Returns negative value and may set error string in `err` when there's an // error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height, const unsigned char *memory, size_t size, const char **err); @@ -428,8 +458,10 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height, #include <cstdio> #include <cstdlib> #include <cstring> +#include <iostream> #include <sstream> +#include <limits> #include <string> #include <vector> @@ -486,6 +518,9 @@ namespace miniz { #pragma clang diagnostic ignored "-Wc++11-extensions" #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#pragma clang diagnostic ignored "-Wundef" + #if __has_warning("-Wcomma") #pragma clang diagnostic ignored "-Wcomma" #endif @@ -495,6 +530,9 @@ namespace miniz { #if __has_warning("-Wcast-qual") #pragma clang diagnostic ignored "-Wcast-qual" #endif +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif #endif /* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP @@ -2480,10 +2518,10 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; - const mz_uint8 *pIn_buf_cur = pIn_buf_next, - *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - mz_uint8 *pOut_buf_cur = pOut_buf_next, - *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = + pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = + pOut_buf_next + *pOut_buf_size; size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 @@ -2955,9 +2993,8 @@ int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, - (flags & - ~(TINFL_FLAG_HAS_MORE_INPUT | - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); in_buf_ofs += in_buf_size; if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) @@ -3082,7 +3119,9 @@ static const mz_uint8 s_tdefl_large_dist_extra[128] = { // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted // values. -typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; +typedef struct { + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) { @@ -3549,10 +3588,9 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) { mz_uint saved_bit_buf, saved_bits_in; mz_uint8 *pSaved_output_buf; mz_bool comp_block_succeeded = MZ_FALSE; - int n, - use_raw_block = - ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && - (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + int n, use_raw_block = + ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && + (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) @@ -3582,9 +3620,8 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) { if (!use_raw_block) comp_block_succeeded = - tdefl_compress_block(d, - (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || - (d->m_total_lz_bytes < 48)); + tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || + (d->m_total_lz_bytes < 48)); // If the block gets expanded, forget the current contents of the output // buffer and send a raw block instead. @@ -4388,9 +4425,8 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, // C and C99, so no big deal) #pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to // 'int', possible loss of data -#pragma warning( \ - disable : 4267) // 'argument': conversion from '__int64' to 'int', - // possible loss of data +#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to + // 'int', possible loss of data #pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is // deprecated. Instead, use the ISO C and C++ // conformant name: _strdup. @@ -6894,7 +6930,7 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, #ifdef _MSC_VER #pragma warning(pop) #endif -} +} // namespace miniz #else // Reuse MINIZ_LITTE_ENDIAN macro @@ -6919,8 +6955,26 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, // return bint.c[0] == 1; //} +static void SetErrorMessage(const std::string &msg, const char **err) { + if (err) { +#ifdef _WIN32 + (*err) = _strdup(msg.c_str()); +#else + (*err) = strdup(msg.c_str()); +#endif + } +} + static const int kEXRVersionSize = 8; +static void cpy2(unsigned short *dst_val, const unsigned short *src_val) { + unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val); + const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; +} + static void swap2(unsigned short *val) { #ifdef MINIZ_LITTLE_ENDIAN (void)val; @@ -6934,6 +6988,36 @@ static void swap2(unsigned short *val) { #endif } +static void cpy4(int *dst_val, const int *src_val) { + unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val); + const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + +static void cpy4(unsigned int *dst_val, const unsigned int *src_val) { + unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val); + const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + +static void cpy4(float *dst_val, const float *src_val) { + unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val); + const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + static void swap4(unsigned int *val) { #ifdef MINIZ_LITTLE_ENDIAN (void)val; @@ -6949,6 +7033,22 @@ static void swap4(unsigned int *val) { #endif } +#if 0 +static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64 *src_val) { + unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val); + const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +} +#endif + static void swap8(tinyexr::tinyexr_uint64 *val) { #ifdef MINIZ_LITTLE_ENDIAN (void)val; @@ -7084,6 +7184,15 @@ static FP16 float_to_half_full(FP32 f) { // #define IMF_B44_COMPRESSION 6 // #define IMF_B44A_COMPRESSION 7 +#ifdef __clang__ +#pragma clang diagnostic push + +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#endif + static const char *ReadString(std::string *s, const char *ptr, size_t len) { // Read untile NULL(\0). const char *p = ptr; @@ -7133,7 +7242,21 @@ static bool ReadAttribute(std::string *name, std::string *type, tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len)); if (data_len == 0) { - return false; + if ((*type).compare("string") == 0) { + // Accept empty string attribute. + + marker += sizeof(uint32_t); + size -= sizeof(uint32_t); + + *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t); + + data->resize(1); + (*data)[0] = '\0'; + + return true; + } else { + return false; + } } marker += sizeof(uint32_t); @@ -7236,18 +7359,24 @@ static bool ReadChannelInfo(std::vector<ChannelInfo> &channels, } ChannelInfo info; - tinyexr_int64 data_len = static_cast<tinyexr_int64>(data.size()) - (p - reinterpret_cast<const char *>(data.data())); + tinyexr_int64 data_len = static_cast<tinyexr_int64>(data.size()) - + (p - reinterpret_cast<const char *>(data.data())); if (data_len < 0) { return false; } - p = ReadString( - &info.name, p, size_t(data_len)); + p = ReadString(&info.name, p, size_t(data_len)); if ((p == NULL) && (info.name.empty())) { // Buffer overrun. Issue #51. return false; } + const unsigned char *data_end = + reinterpret_cast<const unsigned char *>(p) + 16; + if (data_end >= (data.data() + data.size())) { + return false; + } + memcpy(&info.pixel_type, p, sizeof(int)); p += 4; info.p_linear = static_cast<unsigned char>(p[0]); // uchar @@ -7468,9 +7597,8 @@ static bool DecompressZip(unsigned char *dst, // C and C99, so no big deal) #pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to // 'int', possible loss of data -#pragma warning( \ - disable : 4267) // 'argument': conversion from '__int64' to 'int', - // possible loss of data +#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to + // 'int', possible loss of data #pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is // deprecated. Instead, use the ISO C and C++ // conformant name: _strdup. @@ -7705,6 +7833,7 @@ static void DecompressRle(unsigned char *dst, #pragma clang diagnostic ignored "-Wsign-conversion" #pragma clang diagnostic ignored "-Wc++11-extensions" #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" #if __has_warning("-Wcast-qual") #pragma clang diagnostic ignored "-Wcast-qual" @@ -8187,8 +8316,8 @@ static void hufBuildEncTable( // for all array entries. // - int hlink[HUF_ENCSIZE]; - long long *fHeap[HUF_ENCSIZE]; + std::vector<int> hlink(HUF_ENCSIZE); + std::vector<long long *> fHeap(HUF_ENCSIZE); *im = 0; @@ -8247,8 +8376,8 @@ static void hufBuildEncTable( std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); - long long scode[HUF_ENCSIZE]; - memset(scode, 0, sizeof(long long) * HUF_ENCSIZE); + std::vector<long long> scode(HUF_ENCSIZE); + memset(scode.data(), 0, sizeof(long long) * HUF_ENCSIZE); while (nf > 1) { // @@ -8320,8 +8449,8 @@ static void hufBuildEncTable( // code table from scode into frq. // - hufCanonicalCodeTable(scode); - memcpy(frq, scode, sizeof(long long) * HUF_ENCSIZE); + hufCanonicalCodeTable(scode.data()); + memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE); } // @@ -8657,26 +8786,62 @@ static int hufEncode // return: output size (in bits) lc += 8; \ } -#define getCode(po, rlc, c, lc, in, out, oe) \ - { \ - if (po == rlc) { \ - if (lc < 8) getChar(c, lc, in); \ - \ - lc -= 8; \ - \ - unsigned char cs = (c >> lc); \ - \ - if (out + cs > oe) return false; \ - \ - unsigned short s = out[-1]; \ - \ - while (cs-- > 0) *out++ = s; \ - } else if (out < oe) { \ - *out++ = po; \ - } else { \ - return false; \ - } \ +#if 0 +#define getCode(po, rlc, c, lc, in, out, ob, oe) \ + { \ + if (po == rlc) { \ + if (lc < 8) getChar(c, lc, in); \ + \ + lc -= 8; \ + \ + unsigned char cs = (c >> lc); \ + \ + if (out + cs > oe) return false; \ + \ + /* TinyEXR issue 78 */ \ + unsigned short s = out[-1]; \ + \ + while (cs-- > 0) *out++ = s; \ + } else if (out < oe) { \ + *out++ = po; \ + } else { \ + return false; \ + } \ + } +#else +static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in, + const char *in_end, unsigned short *&out, + const unsigned short *ob, const unsigned short *oe) { + (void)ob; + if (po == rlc) { + if (lc < 8) { + /* TinyEXR issue 78 */ + if ((in + 1) >= in_end) { + return false; + } + + getChar(c, lc, in); + } + + lc -= 8; + + unsigned char cs = (c >> lc); + + if (out + cs > oe) return false; + + // Bounds check for safety + if ((out - 1) <= ob) return false; + unsigned short s = out[-1]; + + while (cs-- > 0) *out++ = s; + } else if (out < oe) { + *out++ = po; + } else { + return false; } + return true; +} +#endif // // Decode (uncompress) ni bits based on encoding & decoding tables: @@ -8692,8 +8857,8 @@ static bool hufDecode(const long long *hcode, // i : encoding table { long long c = 0; int lc = 0; - unsigned short *outb = out; - unsigned short *oe = out + no; + unsigned short *outb = out; // begin + unsigned short *oe = out + no; // end const char *ie = in + (ni + 7) / 8; // input byte size // @@ -8716,7 +8881,16 @@ static bool hufDecode(const long long *hcode, // i : encoding table // lc -= pl.len; - getCode(pl.lit, rlc, c, lc, in, out, oe); + // std::cout << "lit = " << pl.lit << std::endl; + // std::cout << "rlc = " << rlc << std::endl; + // std::cout << "c = " << c << std::endl; + // std::cout << "lc = " << lc << std::endl; + // std::cout << "in = " << in << std::endl; + // std::cout << "out = " << out << std::endl; + // std::cout << "oe = " << oe << std::endl; + if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } } else { if (!pl.p) { return false; @@ -8743,7 +8917,9 @@ static bool hufDecode(const long long *hcode, // i : encoding table // lc -= l; - getCode(pl.p[j], rlc, c, lc, in, out, oe); + if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } break; } } @@ -8770,7 +8946,9 @@ static bool hufDecode(const long long *hcode, // i : encoding table if (pl.len) { lc -= pl.len; - getCode(pl.lit, rlc, c, lc, in, out, oe); + if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } } else { return false; // invalidCode(); // wrong (long) code @@ -8785,7 +8963,7 @@ static bool hufDecode(const long long *hcode, // i : encoding table return true; } -static void countFrequencies(long long freq[HUF_ENCSIZE], +static void countFrequencies(std::vector<long long> &freq, const unsigned short data[/*n*/], int n) { for (int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0; @@ -8816,21 +8994,21 @@ static int hufCompress(const unsigned short raw[], int nRaw, char compressed[]) { if (nRaw == 0) return 0; - long long freq[HUF_ENCSIZE]; + std::vector<long long> freq(HUF_ENCSIZE); countFrequencies(freq, raw, nRaw); int im = 0; int iM = 0; - hufBuildEncTable(freq, &im, &iM); + hufBuildEncTable(freq.data(), &im, &iM); char *tableStart = compressed + 20; char *tableEnd = tableStart; - hufPackEncTable(freq, im, iM, &tableEnd); + hufPackEncTable(freq.data(), im, iM, &tableEnd); int tableLength = tableEnd - tableStart; char *dataStart = tableEnd; - int nBits = hufEncode(freq, raw, nRaw, iM, dataStart); + int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart); int data_length = (nBits + 7) / 8; writeUInt(compressed, im); @@ -8843,9 +9021,9 @@ static int hufCompress(const unsigned short raw[], int nRaw, } static bool hufUncompress(const char compressed[], int nCompressed, - unsigned short raw[], int nRaw) { + std::vector<unsigned short> *raw) { if (nCompressed == 0) { - if (nRaw != 0) return false; + if (raw->size() != 0) return false; return false; } @@ -8886,7 +9064,8 @@ static bool hufUncompress(const char compressed[], int nCompressed, } hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0)); - hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, nRaw, raw); + hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(), + raw->data()); } // catch (...) //{ @@ -8975,7 +9154,7 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize, const unsigned char *inPtr, size_t inSize, const std::vector<ChannelInfo> &channelInfo, int data_width, int num_lines) { - unsigned char bitmap[BITMAP_SIZE]; + std::vector<unsigned char> bitmap(BITMAP_SIZE); unsigned short minNonZero; unsigned short maxNonZero; @@ -9026,12 +9205,12 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize, } } - bitmapFromData(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()), bitmap, - minNonZero, maxNonZero); + bitmapFromData(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()), + bitmap.data(), minNonZero, maxNonZero); - unsigned short lut[USHORT_RANGE]; - unsigned short maxValue = forwardLutFromBitmap(bitmap, lut); - applyLut(lut, &tmpBuffer.at(0), static_cast<int>(tmpBuffer.size())); + std::vector<unsigned short> lut(USHORT_RANGE); + unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data()); + applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBuffer.size())); // // Store range compression info in _outBuffer @@ -9101,7 +9280,7 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, return true; } - unsigned char bitmap[BITMAP_SIZE]; + std::vector<unsigned char> bitmap(BITMAP_SIZE); unsigned short minNonZero; unsigned short maxNonZero; @@ -9111,11 +9290,13 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, return false; #endif - memset(bitmap, 0, BITMAP_SIZE); + memset(bitmap.data(), 0, BITMAP_SIZE); const unsigned char *ptr = inPtr; - minNonZero = *(reinterpret_cast<const unsigned short *>(ptr)); - maxNonZero = *(reinterpret_cast<const unsigned short *>(ptr + 2)); + // minNonZero = *(reinterpret_cast<const unsigned short *>(ptr)); + tinyexr::cpy2(&minNonZero, reinterpret_cast<const unsigned short *>(ptr)); + // maxNonZero = *(reinterpret_cast<const unsigned short *>(ptr + 2)); + tinyexr::cpy2(&maxNonZero, reinterpret_cast<const unsigned short *>(ptr + 2)); ptr += 4; if (maxNonZero >= BITMAP_SIZE) { @@ -9128,9 +9309,9 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, ptr += maxNonZero - minNonZero + 1; } - unsigned short lut[USHORT_RANGE]; - memset(lut, 0, sizeof(unsigned short) * USHORT_RANGE); - unsigned short maxValue = reverseLutFromBitmap(bitmap, lut); + std::vector<unsigned short> lut(USHORT_RANGE); + memset(lut.data(), 0, sizeof(unsigned short) * USHORT_RANGE); + unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data()); // // Huffman decoding @@ -9138,12 +9319,12 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, int length; - length = *(reinterpret_cast<const int *>(ptr)); + // length = *(reinterpret_cast<const int *>(ptr)); + tinyexr::cpy4(&length, reinterpret_cast<const int *>(ptr)); ptr += sizeof(int); std::vector<unsigned short> tmpBuffer(tmpBufSize); - hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer.at(0), - static_cast<int>(tmpBufSize)); + hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer); // // Wavelet decoding @@ -9184,7 +9365,7 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, // Expand the pixel data to their original range // - applyLut(lut, &tmpBuffer.at(0), static_cast<int>(tmpBufSize)); + applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBufSize)); for (int y = 0; y < num_lines; y++) { for (size_t i = 0; i < channelData.size(); ++i) { @@ -9409,6 +9590,7 @@ bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize, // ----------------------------------------------------------------- // +// TODO(syoyo): Refactor function arguments. static bool DecodePixelData(/* out */ unsigned char **out_images, const int *requested_pixel_types, const unsigned char *data_ptr, size_t data_len, @@ -9421,6 +9603,11 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, const std::vector<size_t> &channel_offset_list) { if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { // PIZ #if TINYEXR_USE_PIZ + if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) { + // Invalid input #90 + return false; + } + // Allocate original data size. std::vector<unsigned char> outBuf(static_cast<size_t>( static_cast<size_t>(width * num_lines) * pixel_data_size)); @@ -9452,7 +9639,10 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, for (size_t u = 0; u < static_cast<size_t>(width); u++) { FP16 hf; - hf.u = line_ptr[u]; + // hf.u = line_ptr[u]; + // use `cpy` to avoid unaligned memory access when compiler's + // optimization is on. + tinyexr::cpy2(&(hf.u), line_ptr + u); tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); @@ -9495,7 +9685,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + channel_offset_list[c] * static_cast<size_t>(width))); for (size_t u = 0; u < static_cast<size_t>(width); u++) { - unsigned int val = line_ptr[u]; + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); tinyexr::swap4(&val); @@ -9521,7 +9713,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, v * pixel_data_size * static_cast<size_t>(x_stride) + channel_offset_list[c] * static_cast<size_t>(x_stride))); for (size_t u = 0; u < static_cast<size_t>(width); u++) { - float val = line_ptr[u]; + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); @@ -9557,9 +9751,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, unsigned long dstLen = static_cast<unsigned long>(outBuf.size()); assert(dstLen > 0); - if (!tinyexr::DecompressZip(reinterpret_cast<unsigned char *>(&outBuf.at(0)), - &dstLen, data_ptr, - static_cast<unsigned long>(data_len))) { + if (!tinyexr::DecompressZip( + reinterpret_cast<unsigned char *>(&outBuf.at(0)), &dstLen, data_ptr, + static_cast<unsigned long>(data_len))) { return false; } @@ -9583,7 +9777,8 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, for (size_t u = 0; u < static_cast<size_t>(width); u++) { tinyexr::FP16 hf; - hf.u = line_ptr[u]; + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); @@ -9626,7 +9821,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + channel_offset_list[c] * static_cast<size_t>(width))); for (size_t u = 0; u < static_cast<size_t>(width); u++) { - unsigned int val = line_ptr[u]; + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); tinyexr::swap4(&val); @@ -9652,7 +9849,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + channel_offset_list[c] * static_cast<size_t>(width))); for (size_t u = 0; u < static_cast<size_t>(width); u++) { - float val = line_ptr[u]; + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); @@ -9707,7 +9906,8 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, for (size_t u = 0; u < static_cast<size_t>(width); u++) { tinyexr::FP16 hf; - hf.u = line_ptr[u]; + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); @@ -9750,7 +9950,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + channel_offset_list[c] * static_cast<size_t>(width))); for (size_t u = 0; u < static_cast<size_t>(width); u++) { - unsigned int val = line_ptr[u]; + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); tinyexr::swap4(&val); @@ -9776,7 +9978,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + channel_offset_list[c] * static_cast<size_t>(width))); for (size_t u = 0; u < static_cast<size_t>(width); u++) { - float val = line_ptr[u]; + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); @@ -9839,7 +10043,8 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + channel_offset_list[c] * static_cast<size_t>(width))); for (size_t u = 0; u < static_cast<size_t>(width); u++) { - float val = line_ptr[u]; + float val; + tinyexr::cpy4(&val, line_ptr + u); tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); @@ -9871,88 +10076,116 @@ static bool DecodePixelData(/* out */ unsigned char **out_images, #endif } else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) { for (size_t c = 0; c < num_channels; c++) { - if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { - const unsigned short *line_ptr = - reinterpret_cast<const unsigned short *>( - data_ptr + - c * static_cast<size_t>(width) * sizeof(unsigned short)); - - if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { - unsigned short *outLine = - reinterpret_cast<unsigned short *>(out_images[c]); - if (line_order == 0) { - outLine += y * x_stride; - } else { - outLine += (height - 1 - y) * x_stride; - } + for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + const unsigned short *line_ptr = + reinterpret_cast<const unsigned short *>( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast<size_t>(width)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *outLine = + reinterpret_cast<unsigned short *>(out_images[c]); + if (line_order == 0) { + outLine += (y + v) * x_stride; + } else { + outLine += (height - 1 - (y + v)) * x_stride; + } - for (int u = 0; u < width; u++) { - tinyexr::FP16 hf; + for (int u = 0; u < width; u++) { + tinyexr::FP16 hf; - hf.u = line_ptr[u]; + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); - tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); + tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); + + outLine[u] = hf.u; + } + } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + float *outLine = reinterpret_cast<float *>(out_images[c]); + if (line_order == 0) { + outLine += (y + v) * x_stride; + } else { + outLine += (height - 1 - (y + v)) * x_stride; + } - outLine[u] = hf.u; + if (reinterpret_cast<const unsigned char *>(line_ptr + width) > + (data_ptr + data_len)) { + // Insufficient data size + return false; + } + + for (int u = 0; u < width; u++) { + tinyexr::FP16 hf; + + // address may not be aliged. use byte-wise copy for safety.#76 + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); + + tinyexr::FP32 f32 = half_to_float(hf); + + outLine[u] = f32.f; + } + } else { + assert(0); + return false; } - } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + const float *line_ptr = reinterpret_cast<const float *>( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast<size_t>(width)); + float *outLine = reinterpret_cast<float *>(out_images[c]); if (line_order == 0) { - outLine += y * x_stride; + outLine += (y + v) * x_stride; } else { - outLine += (height - 1 - y) * x_stride; + outLine += (height - 1 - (y + v)) * x_stride; } - for (int u = 0; u < width; u++) { - tinyexr::FP16 hf; - - hf.u = line_ptr[u]; - - tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); - - tinyexr::FP32 f32 = half_to_float(hf); - - outLine[u] = f32.f; + if (reinterpret_cast<const unsigned char *>(line_ptr + width) > + (data_ptr + data_len)) { + // Insufficient data size + return false; } - } else { - assert(0); - return false; - } - } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { - const float *line_ptr = reinterpret_cast<const float *>( - data_ptr + c * static_cast<size_t>(width) * sizeof(float)); - float *outLine = reinterpret_cast<float *>(out_images[c]); - if (line_order == 0) { - outLine += y * x_stride; - } else { - outLine += (height - 1 - y) * x_stride; - } + for (int u = 0; u < width; u++) { + float val; + tinyexr::cpy4(&val, line_ptr + u); - for (int u = 0; u < width; u++) { - float val = line_ptr[u]; + tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); - tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); + outLine[u] = val; + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + const unsigned int *line_ptr = reinterpret_cast<const unsigned int *>( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast<size_t>(width)); - outLine[u] = val; - } - } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { - const unsigned int *line_ptr = reinterpret_cast<const unsigned int *>( - data_ptr + c * static_cast<size_t>(width) * sizeof(unsigned int)); + unsigned int *outLine = + reinterpret_cast<unsigned int *>(out_images[c]); + if (line_order == 0) { + outLine += (y + v) * x_stride; + } else { + outLine += (height - 1 - (y + v)) * x_stride; + } - unsigned int *outLine = reinterpret_cast<unsigned int *>(out_images[c]); - if (line_order == 0) { - outLine += y * x_stride; - } else { - outLine += (height - 1 - y) * x_stride; - } + for (int u = 0; u < width; u++) { + if (reinterpret_cast<const unsigned char *>(line_ptr + u) >= + (data_ptr + data_len)) { + // Corrupsed data? + return false; + } - for (int u = 0; u < width; u++) { - unsigned int val = line_ptr[u]; + unsigned int val; + tinyexr::cpy4(&val, line_ptr + u); - tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); + tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); - outLine[u] = val; + outLine[u] = val; + } } } } @@ -9994,7 +10227,7 @@ static void DecodeTiledPixelData( num_channels, channels, channel_offset_list); } -static void ComputeChannelLayout(std::vector<size_t> *channel_offset_list, +static bool ComputeChannelLayout(std::vector<size_t> *channel_offset_list, int *pixel_data_size, size_t *channel_offset, int num_channels, const EXRChannelInfo *channels) { @@ -10015,9 +10248,11 @@ static void ComputeChannelLayout(std::vector<size_t> *channel_offset_list, (*pixel_data_size) += sizeof(unsigned int); (*channel_offset) += sizeof(unsigned int); } else { - assert(0); + // ??? + return false; } } + return true; } static unsigned char **AllocateImage(int num_channels, @@ -10125,8 +10360,11 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, // Read attributes size_t orig_size = size; - for (;;) { + for (size_t nattr = 0; nattr < TINYEXR_MAX_HEADER_ATTRIBUTES; nattr++) { if (0 == size) { + if (err) { + (*err) += "Insufficient data size for attributes.\n"; + } return TINYEXR_ERROR_INVALID_DATA; } else if (marker[0] == '\0') { size--; @@ -10139,6 +10377,9 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, size_t marker_size; if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size, marker, size)) { + if (err) { + (*err) += "Failed to read attribute.\n"; + } return TINYEXR_ERROR_INVALID_DATA; } marker += marker_size; @@ -10209,14 +10450,14 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, if (!ReadChannelInfo(info->channels, data)) { if (err) { - (*err) = "Failed to parse channel info."; + (*err) += "Failed to parse channel info.\n"; } return TINYEXR_ERROR_INVALID_DATA; } if (info->channels.size() < 1) { if (err) { - (*err) = "# of channels is zero."; + (*err) += "# of channels is zero.\n"; } return TINYEXR_ERROR_INVALID_DATA; } @@ -10224,9 +10465,7 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, has_channels = true; } else if (attr_name.compare("dataWindow") == 0) { - if (data.size() < 16) { - // Corrupsed file(Issue #50). - } else { + if (data.size() >= 16) { memcpy(&info->data_window[0], &data.at(0), sizeof(int)); memcpy(&info->data_window[1], &data.at(4), sizeof(int)); memcpy(&info->data_window[2], &data.at(8), sizeof(int)); @@ -10238,48 +10477,60 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, has_data_window = true; } } else if (attr_name.compare("displayWindow") == 0) { - memcpy(&info->display_window[0], &data.at(0), sizeof(int)); - memcpy(&info->display_window[1], &data.at(4), sizeof(int)); - memcpy(&info->display_window[2], &data.at(8), sizeof(int)); - memcpy(&info->display_window[3], &data.at(12), sizeof(int)); - tinyexr::swap4( - reinterpret_cast<unsigned int *>(&info->display_window[0])); - tinyexr::swap4( - reinterpret_cast<unsigned int *>(&info->display_window[1])); - tinyexr::swap4( - reinterpret_cast<unsigned int *>(&info->display_window[2])); - tinyexr::swap4( - reinterpret_cast<unsigned int *>(&info->display_window[3])); - - has_display_window = true; + if (data.size() >= 16) { + memcpy(&info->display_window[0], &data.at(0), sizeof(int)); + memcpy(&info->display_window[1], &data.at(4), sizeof(int)); + memcpy(&info->display_window[2], &data.at(8), sizeof(int)); + memcpy(&info->display_window[3], &data.at(12), sizeof(int)); + tinyexr::swap4( + reinterpret_cast<unsigned int *>(&info->display_window[0])); + tinyexr::swap4( + reinterpret_cast<unsigned int *>(&info->display_window[1])); + tinyexr::swap4( + reinterpret_cast<unsigned int *>(&info->display_window[2])); + tinyexr::swap4( + reinterpret_cast<unsigned int *>(&info->display_window[3])); + + has_display_window = true; + } } else if (attr_name.compare("lineOrder") == 0) { - info->line_order = static_cast<int>(data[0]); - has_line_order = true; + if (data.size() >= 1) { + info->line_order = static_cast<int>(data[0]); + has_line_order = true; + } } else if (attr_name.compare("pixelAspectRatio") == 0) { - memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float)); - tinyexr::swap4( - reinterpret_cast<unsigned int *>(&info->pixel_aspect_ratio)); - has_pixel_aspect_ratio = true; + if (data.size() >= sizeof(float)) { + memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float)); + tinyexr::swap4( + reinterpret_cast<unsigned int *>(&info->pixel_aspect_ratio)); + has_pixel_aspect_ratio = true; + } } else if (attr_name.compare("screenWindowCenter") == 0) { - memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float)); - memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float)); - tinyexr::swap4( - reinterpret_cast<unsigned int *>(&info->screen_window_center[0])); - tinyexr::swap4( - reinterpret_cast<unsigned int *>(&info->screen_window_center[1])); - has_screen_window_center = true; + if (data.size() >= 8) { + memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float)); + memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float)); + tinyexr::swap4( + reinterpret_cast<unsigned int *>(&info->screen_window_center[0])); + tinyexr::swap4( + reinterpret_cast<unsigned int *>(&info->screen_window_center[1])); + has_screen_window_center = true; + } } else if (attr_name.compare("screenWindowWidth") == 0) { - memcpy(&info->screen_window_width, &data.at(0), sizeof(float)); - tinyexr::swap4( - reinterpret_cast<unsigned int *>(&info->screen_window_width)); + if (data.size() >= sizeof(float)) { + memcpy(&info->screen_window_width, &data.at(0), sizeof(float)); + tinyexr::swap4( + reinterpret_cast<unsigned int *>(&info->screen_window_width)); - has_screen_window_width = true; + has_screen_window_width = true; + } } else if (attr_name.compare("chunkCount") == 0) { - memcpy(&info->chunk_count, &data.at(0), sizeof(int)); - tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->chunk_count)); + if (data.size() >= sizeof(int)) { + memcpy(&info->chunk_count, &data.at(0), sizeof(int)); + tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->chunk_count)); + } } else { - // Custom attribute(up to TINYEXR_MAX_ATTRIBUTES) - if (info->attributes.size() < TINYEXR_MAX_ATTRIBUTES) { + // Custom attribute(up to TINYEXR_MAX_CUSTOM_ATTRIBUTES) + if (info->attributes.size() < TINYEXR_MAX_CUSTOM_ATTRIBUTES) { EXRAttribute attrib; #ifdef _MSC_VER strncpy_s(attrib.name, attr_name.c_str(), 255); @@ -10409,15 +10660,30 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) { exr_header->requested_pixel_types[c] = info.channels[c].pixel_type; } - assert(info.attributes.size() < TINYEXR_MAX_ATTRIBUTES); exr_header->num_custom_attributes = static_cast<int>(info.attributes.size()); - for (size_t i = 0; i < info.attributes.size(); i++) { - memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name, 256); - memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type, 256); - exr_header->custom_attributes[i].size = info.attributes[i].size; - // Just copy poiner - exr_header->custom_attributes[i].value = info.attributes[i].value; + if (exr_header->num_custom_attributes > 0) { + // TODO(syoyo): Report warning when # of attributes exceeds + // `TINYEXR_MAX_CUSTOM_ATTRIBUTES` + if (exr_header->num_custom_attributes > TINYEXR_MAX_CUSTOM_ATTRIBUTES) { + exr_header->num_custom_attributes = TINYEXR_MAX_CUSTOM_ATTRIBUTES; + } + + exr_header->custom_attributes = static_cast<EXRAttribute *>(malloc( + sizeof(EXRAttribute) * size_t(exr_header->num_custom_attributes))); + + for (size_t i = 0; i < info.attributes.size(); i++) { + memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name, + 256); + memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type, + 256); + exr_header->custom_attributes[i].size = info.attributes[i].size; + // Just copy poiner + exr_header->custom_attributes[i].value = info.attributes[i].value; + } + + } else { + exr_header->custom_attributes = NULL; } exr_header->header_len = info.header_len; @@ -10425,7 +10691,8 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) { static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, const std::vector<tinyexr::tinyexr_uint64> &offsets, - const unsigned char *head, const size_t size) { + const unsigned char *head, const size_t size, + std::string *err) { int num_channels = exr_header->num_channels; int num_scanline_blocks = 1; @@ -10445,32 +10712,40 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, std::vector<size_t> channel_offset_list; int pixel_data_size = 0; size_t channel_offset = 0; - tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size, - &channel_offset, num_channels, - exr_header->channels); + if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size, + &channel_offset, num_channels, + exr_header->channels)) { + if (err) { + (*err) += "Failed to compute channel layout.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } - bool invalid_data = false; + bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety. if (exr_header->tiled) { size_t num_tiles = offsets.size(); // = # of blocks exr_image->tiles = static_cast<EXRTile *>( - malloc(sizeof(EXRTile) * static_cast<size_t>(num_tiles))); + calloc(sizeof(EXRTile), static_cast<size_t>(num_tiles))); for (size_t tile_idx = 0; tile_idx < num_tiles; tile_idx++) { // Allocate memory for each tile. exr_image->tiles[tile_idx].images = tinyexr::AllocateImage( num_channels, exr_header->channels, exr_header->requested_pixel_types, - data_width, data_height); + exr_header->tile_size_x, exr_header->tile_size_y); // 16 byte: tile coordinates // 4 byte : data size // ~ : data(uncompressed or compressed) if (offsets[tile_idx] + sizeof(int) * 5 > size) { + if (err) { + (*err) += "Insufficient data size.\n"; + } return TINYEXR_ERROR_INVALID_DATA; } - size_t data_size = size - (offsets[tile_idx] + sizeof(int) * 5); + size_t data_size = size_t(size - (offsets[tile_idx] + sizeof(int) * 5)); const unsigned char *data_ptr = reinterpret_cast<const unsigned char *>(head + offsets[tile_idx]); @@ -10482,8 +10757,12 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, tinyexr::swap4(reinterpret_cast<unsigned int *>(&tile_coordinates[3])); // @todo{ LoD } - assert(tile_coordinates[2] == 0); - assert(tile_coordinates[3] == 0); + if (tile_coordinates[2] != 0) { + return TINYEXR_ERROR_UNSUPPORTED_FEATURE; + } + if (tile_coordinates[3] != 0) { + return TINYEXR_ERROR_UNSUPPORTED_FEATURE; + } int data_len; memcpy(&data_len, data_ptr + 16, @@ -10491,6 +10770,9 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len)); if (data_len < 4 || size_t(data_len) > data_size) { + if (err) { + (*err) += "Insufficient data length.\n"; + } return TINYEXR_ERROR_INVALID_DATA; } @@ -10531,56 +10813,56 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, size_t y_idx = static_cast<size_t>(y); if (offsets[y_idx] + sizeof(int) * 2 > size) { - return TINYEXR_ERROR_INVALID_DATA; - } - - // 4 byte: scan line - // 4 byte: data size - // ~ : pixel data(uncompressed or compressed) - size_t data_size = size - (offsets[y_idx] + sizeof(int) * 2); - const unsigned char *data_ptr = - reinterpret_cast<const unsigned char *>(head + offsets[y_idx]); - - int line_no; - memcpy(&line_no, data_ptr, sizeof(int)); - int data_len; - memcpy(&data_len, data_ptr + 4, sizeof(int)); - tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no)); - tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len)); - - if (size_t(data_len) > data_size) { - return TINYEXR_ERROR_INVALID_DATA; - } - - int end_line_no = (std::min)(line_no + num_scanline_blocks, - (exr_header->data_window[3] + 1)); - - int num_lines = end_line_no - line_no; - //assert(num_lines > 0); - - if (num_lines <= 0) { invalid_data = true; } else { - - // Move to data addr: 8 = 4 + 4; - data_ptr += 8; - - // Adjust line_no with data_window.bmin.y - line_no -= exr_header->data_window[1]; - - if (line_no < 0) { + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(uncompressed or compressed) + size_t data_size = size_t(size - (offsets[y_idx] + sizeof(int) * 2)); + const unsigned char *data_ptr = + reinterpret_cast<const unsigned char *>(head + offsets[y_idx]); + + int line_no; + memcpy(&line_no, data_ptr, sizeof(int)); + int data_len; + memcpy(&data_len, data_ptr + 4, sizeof(int)); + tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no)); + tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len)); + + if (size_t(data_len) > data_size) { invalid_data = true; } else { - if (!tinyexr::DecodePixelData( - exr_image->images, exr_header->requested_pixel_types, data_ptr, - static_cast<size_t>(data_len), exr_header->compression_type, - exr_header->line_order, data_width, data_height, data_width, y, - line_no, num_lines, static_cast<size_t>(pixel_data_size), - static_cast<size_t>(exr_header->num_custom_attributes), - exr_header->custom_attributes, - static_cast<size_t>(exr_header->num_channels), exr_header->channels, - channel_offset_list)) { + int end_line_no = (std::min)(line_no + num_scanline_blocks, + (exr_header->data_window[3] + 1)); + + int num_lines = end_line_no - line_no; + // assert(num_lines > 0); + + if (num_lines <= 0) { invalid_data = true; + } else { + // Move to data addr: 8 = 4 + 4; + data_ptr += 8; + + // Adjust line_no with data_window.bmin.y + line_no -= exr_header->data_window[1]; + + if (line_no < 0) { + invalid_data = true; + } else { + if (!tinyexr::DecodePixelData( + exr_image->images, exr_header->requested_pixel_types, + data_ptr, static_cast<size_t>(data_len), + exr_header->compression_type, exr_header->line_order, + data_width, data_height, data_width, y, line_no, + num_lines, static_cast<size_t>(pixel_data_size), + static_cast<size_t>(exr_header->num_custom_attributes), + exr_header->custom_attributes, + static_cast<size_t>(exr_header->num_channels), + exr_header->channels, channel_offset_list)) { + invalid_data = true; + } + } } } } @@ -10648,9 +10930,7 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header, const char **err) { if (exr_image == NULL || exr_header == NULL || head == NULL || marker == NULL || (size <= tinyexr::kEXRVersionSize)) { - if (err) { - (*err) = "Invalid argument."; - } + tinyexr::SetErrorMessage("Invalid argument for DecodeEXRImage().", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } @@ -10663,13 +10943,23 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header, num_scanline_blocks = 16; } - int data_width = exr_header->data_window[2] - exr_header->data_window[0] + 1; - int data_height = exr_header->data_window[3] - exr_header->data_window[1] + 1; + int data_width = exr_header->data_window[2] - exr_header->data_window[0]; + if (data_width >= std::numeric_limits<int>::max()) { + // Issue 63 + tinyexr::SetErrorMessage("Invalid data window value", err); + return TINYEXR_ERROR_INVALID_DATA; + } + data_width++; + + int data_height = exr_header->data_window[3] - exr_header->data_window[1]; + if (data_height >= std::numeric_limits<int>::max()) { + tinyexr::SetErrorMessage("Invalid data height value", err); + return TINYEXR_ERROR_INVALID_DATA; + } + data_height++; if ((data_width < 0) || (data_height < 0)) { - if (err) { - (*err) = "Invalid data window value."; - } + tinyexr::SetErrorMessage("data window or data height is negative.", err); return TINYEXR_ERROR_INVALID_DATA; } @@ -10708,12 +10998,16 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header, for (size_t y = 0; y < num_blocks; y++) { tinyexr::tinyexr_uint64 offset; + // Issue #81 + if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) { + tinyexr::SetErrorMessage("Insufficient data size in offset table.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64)); tinyexr::swap8(&offset); if (offset >= size) { - if (err) { - (*err) = "Invalid offset value."; - } + tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err); return TINYEXR_ERROR_INVALID_DATA; } marker += sizeof(tinyexr::tinyexr_uint64); // = 8 @@ -10736,15 +11030,37 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header, // OK break; } else { - if (err) { - (*err) = "Cannot reconstruct lineOffset table."; - } + tinyexr::SetErrorMessage( + "Cannot reconstruct lineOffset table in DecodeEXRImage.", err); return TINYEXR_ERROR_INVALID_DATA; } } } - return DecodeChunk(exr_image, exr_header, offsets, head, size); + { + std::string e; + int ret = DecodeChunk(exr_image, exr_header, offsets, head, size, &e); + + if (ret != TINYEXR_SUCCESS) { + if (!e.empty()) { + tinyexr::SetErrorMessage(e, err); + } + + // release memory(if exists) + if ((exr_header->num_channels > 0) && exr_image && exr_image->images) { + for (size_t c = 0; c < size_t(exr_header->num_channels); c++) { + if (exr_image->images[c]) { + free(exr_image->images[c]); + exr_image->images[c] = NULL; + } + } + free(exr_image->images); + exr_image->images = NULL; + } + } + + return ret; + } } } // namespace tinyexr @@ -10752,9 +11068,7 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header, int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, const char **err) { if (out_rgba == NULL) { - if (err) { - (*err) = "Invalid argument.\n"; - } + tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } @@ -10767,13 +11081,14 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, { int ret = ParseEXRVersionFromFile(&exr_version, filename); if (ret != TINYEXR_SUCCESS) { + tinyexr::SetErrorMessage("Invalid EXR header.", err); return ret; } if (exr_version.multipart || exr_version.non_image) { - if (err) { - (*err) = "Loading multipart or DeepImage is not supported yet.\n"; - } + tinyexr::SetErrorMessage( + "Loading multipart or DeepImage is not supported in LoadEXR() API", + err); return TINYEXR_ERROR_INVALID_DATA; // @fixme. } } @@ -10781,6 +11096,7 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, { int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err); if (ret != TINYEXR_SUCCESS) { + FreeEXRHeader(&exr_header); return ret; } } @@ -10795,6 +11111,7 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, { int ret = LoadEXRImageFromFile(&exr_image, &exr_header, filename, err); if (ret != TINYEXR_SUCCESS) { + FreeEXRHeader(&exr_header); return ret; } } @@ -10819,6 +11136,9 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, if ((idxA == 0) && (idxR == -1) && (idxG == -1) && (idxB == -1)) { // Alpha channel only. + if (exr_header.tiled) { + // todo.implement this + } (*out_rgba) = reinterpret_cast<float *>( malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) * static_cast<size_t>(exr_image.height))); @@ -10833,45 +11153,77 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, // Assume RGB(A) if (idxR == -1) { - if (err) { - (*err) = "R channel not found\n"; - } + tinyexr::SetErrorMessage("R channel not found", err); // @todo { free exr_image } + FreeEXRHeader(&exr_header); return TINYEXR_ERROR_INVALID_DATA; } if (idxG == -1) { - if (err) { - (*err) = "G channel not found\n"; - } + tinyexr::SetErrorMessage("G channel not found", err); // @todo { free exr_image } + FreeEXRHeader(&exr_header); return TINYEXR_ERROR_INVALID_DATA; } if (idxB == -1) { - if (err) { - (*err) = "B channel not found\n"; - } + tinyexr::SetErrorMessage("B channel not found", err); // @todo { free exr_image } + FreeEXRHeader(&exr_header); return TINYEXR_ERROR_INVALID_DATA; } (*out_rgba) = reinterpret_cast<float *>( malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) * static_cast<size_t>(exr_image.height))); - for (int i = 0; i < exr_image.width * exr_image.height; i++) { - (*out_rgba)[4 * i + 0] = - reinterpret_cast<float **>(exr_image.images)[idxR][i]; - (*out_rgba)[4 * i + 1] = - reinterpret_cast<float **>(exr_image.images)[idxG][i]; - (*out_rgba)[4 * i + 2] = - reinterpret_cast<float **>(exr_image.images)[idxB][i]; - if (idxA != -1) { - (*out_rgba)[4 * i + 3] = - reinterpret_cast<float **>(exr_image.images)[idxA][i]; - } else { - (*out_rgba)[4 * i + 3] = 1.0; + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = + exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; + const int jj = + exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; + const int idx = ii + jj * exr_image.width; + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast<float **>(src)[idxR][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast<float **>(src)[idxG][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast<float **>(src)[idxB][srcIdx]; + if (idxA != -1) { + (*out_rgba)[4 * idx + 3] = + reinterpret_cast<float **>(src)[idxA][srcIdx]; + } else { + (*out_rgba)[4 * idx + 3] = 1.0; + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + (*out_rgba)[4 * i + 0] = + reinterpret_cast<float **>(exr_image.images)[idxR][i]; + (*out_rgba)[4 * i + 1] = + reinterpret_cast<float **>(exr_image.images)[idxG][i]; + (*out_rgba)[4 * i + 2] = + reinterpret_cast<float **>(exr_image.images)[idxB][i]; + if (idxA != -1) { + (*out_rgba)[4 * i + 3] = + reinterpret_cast<float **>(exr_image.images)[idxA][i]; + } else { + (*out_rgba)[4 * i + 3] = 1.0; + } } } } @@ -10889,15 +11241,17 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version, const unsigned char *memory, size_t size, const char **err) { if (memory == NULL || exr_header == NULL) { - if (err) { - (*err) = "Invalid argument.\n"; - } + tinyexr::SetErrorMessage( + "Invalid argument. `memory` or `exr_header` argument is null in " + "ParseEXRHeaderFromMemory()", + err); // Invalid argument return TINYEXR_ERROR_INVALID_ARGUMENT; } if (size < tinyexr::kEXRVersionSize) { + tinyexr::SetErrorMessage("Insufficient header/data size.\n", err); return TINYEXR_ERROR_INVALID_DATA; } @@ -10912,11 +11266,7 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version, if (ret != TINYEXR_SUCCESS) { if (err && !err_str.empty()) { -#ifdef _WIN32 - (*err) = _strdup(err_str.c_str()); // May leak -#else - (*err) = strdup(err_str.c_str()); // May leak -#endif + tinyexr::SetErrorMessage(err_str, err); } } @@ -10932,9 +11282,7 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height, const unsigned char *memory, size_t size, const char **err) { if (out_rgba == NULL || memory == NULL) { - if (err) { - (*err) = "Invalid argument.\n"; - } + tinyexr::SetErrorMessage("Invalid argument for LoadEXRFromMemory", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } @@ -10946,6 +11294,7 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height, int ret = ParseEXRVersionFromMemory(&exr_version, memory, size); if (ret != TINYEXR_SUCCESS) { + tinyexr::SetErrorMessage("Failed to parse EXR version", err); return ret; } @@ -10985,26 +11334,20 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height, } if (idxR == -1) { - if (err) { - (*err) = "R channel not found\n"; - } + tinyexr::SetErrorMessage("R channel not found", err); // @todo { free exr_image } return TINYEXR_ERROR_INVALID_DATA; } if (idxG == -1) { - if (err) { - (*err) = "G channel not found\n"; - } + tinyexr::SetErrorMessage("G channel not found", err); // @todo { free exr_image } return TINYEXR_ERROR_INVALID_DATA; } if (idxB == -1) { - if (err) { - (*err) = "B channel not found\n"; - } + tinyexr::SetErrorMessage("B channel not found", err); // @todo { free exr_image } return TINYEXR_ERROR_INVALID_DATA; } @@ -11040,9 +11383,7 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height, int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header, const char *filename, const char **err) { if (exr_image == NULL) { - if (err) { - (*err) = "Invalid argument."; - } + tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } @@ -11053,9 +11394,7 @@ int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header, FILE *fp = fopen(filename, "rb"); #endif if (!fp) { - if (err) { - (*err) = "Cannot read file."; - } + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); return TINYEXR_ERROR_CANT_OPEN_FILE; } @@ -11065,6 +11404,12 @@ int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header, filesize = static_cast<size_t>(ftell(fp)); fseek(fp, 0, SEEK_SET); + if (filesize < 16) { + tinyexr::SetErrorMessage("File size too short " + std::string(filename), + err); + return TINYEXR_ERROR_INVALID_FILE; + } + std::vector<unsigned char> buf(filesize); // @todo { use mmap } { size_t ret; @@ -11083,16 +11428,13 @@ int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header, const char **err) { if (exr_image == NULL || memory == NULL || (size < tinyexr::kEXRVersionSize)) { - if (err) { - (*err) = "Invalid argument."; - } + tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory", + err); return TINYEXR_ERROR_INVALID_ARGUMENT; } if (exr_header->header_len == 0) { - if (err) { - (*err) = "EXRHeader is not initialized."; - } + tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } @@ -11109,26 +11451,22 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image, unsigned char **memory_out, const char **err) { if (exr_image == NULL || memory_out == NULL || exr_header->compression_type < 0) { - if (err) { - (*err) = "Invalid argument."; - } + tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToMemory", err); return 0; // @fixme } #if !TINYEXR_USE_PIZ if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { - if (err) { - (*err) = "PIZ compression is not supported in this build."; - } + tinyexr::SetErrorMessage("PIZ compression is not supported in this build", + err); return 0; } #endif #if !TINYEXR_USE_ZFP if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { - if (err) { - (*err) = "ZFP compression is not supported in this build."; - } + tinyexr::SetErrorMessage("ZFP compression is not supported in this build", + err); return 0; } #endif @@ -11136,9 +11474,8 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image, #if TINYEXR_USE_ZFP for (size_t i = 0; i < static_cast<size_t>(exr_header->num_channels); i++) { if (exr_header->requested_pixel_types[i] != TINYEXR_PIXELTYPE_FLOAT) { - if (err) { - (*err) = "Pixel type must be FLOAT for ZFP compression."; - } + tinyexr::SetErrorMessage("Pixel type must be FLOAT for ZFP compression", + err); return 0; } } @@ -11348,6 +11685,11 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image, if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { for (int y = 0; y < h; y++) { + // Assume increasing Y + float *line_ptr = reinterpret_cast<float *>(&buf.at( + static_cast<size_t>(pixel_data_size * y * exr_image->width) + + channel_offset_list[c] * + static_cast<size_t>(exr_image->width))); for (int x = 0; x < exr_image->width; x++) { tinyexr::FP16 h16; h16.u = reinterpret_cast<unsigned short **>( @@ -11357,30 +11699,27 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image, tinyexr::swap4(reinterpret_cast<unsigned int *>(&f32.f)); - // Assume increasing Y - float *line_ptr = reinterpret_cast<float *>(&buf.at( - static_cast<size_t>(pixel_data_size * y * exr_image->width) + - channel_offset_list[c] * - static_cast<size_t>(exr_image->width))); - line_ptr[x] = f32.f; + // line_ptr[x] = f32.f; + tinyexr::cpy4(line_ptr + x, &(f32.f)); } } } else if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { for (int y = 0; y < h; y++) { + // Assume increasing Y + unsigned short *line_ptr = reinterpret_cast<unsigned short *>( + &buf.at(static_cast<size_t>(pixel_data_size * y * + exr_image->width) + + channel_offset_list[c] * + static_cast<size_t>(exr_image->width))); for (int x = 0; x < exr_image->width; x++) { unsigned short val = reinterpret_cast<unsigned short **>( exr_image->images)[c][(y + start_y) * exr_image->width + x]; tinyexr::swap2(&val); - // Assume increasing Y - unsigned short *line_ptr = reinterpret_cast<unsigned short *>( - &buf.at(static_cast<size_t>(pixel_data_size * y * - exr_image->width) + - channel_offset_list[c] * - static_cast<size_t>(exr_image->width))); - line_ptr[x] = val; + // line_ptr[x] = val; + tinyexr::cpy2(line_ptr + x, &val); } } } else { @@ -11390,6 +11729,12 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image, } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { for (int y = 0; y < h; y++) { + // Assume increasing Y + unsigned short *line_ptr = reinterpret_cast<unsigned short *>( + &buf.at(static_cast<size_t>(pixel_data_size * y * + exr_image->width) + + channel_offset_list[c] * + static_cast<size_t>(exr_image->width))); for (int x = 0; x < exr_image->width; x++) { tinyexr::FP32 f32; f32.f = reinterpret_cast<float **>( @@ -11400,30 +11745,26 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image, tinyexr::swap2(reinterpret_cast<unsigned short *>(&h16.u)); - // Assume increasing Y - unsigned short *line_ptr = reinterpret_cast<unsigned short *>( - &buf.at(static_cast<size_t>(pixel_data_size * y * - exr_image->width) + - channel_offset_list[c] * - static_cast<size_t>(exr_image->width))); - line_ptr[x] = h16.u; + // line_ptr[x] = h16.u; + tinyexr::cpy2(line_ptr + x, &(h16.u)); } } } else if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { for (int y = 0; y < h; y++) { + // Assume increasing Y + float *line_ptr = reinterpret_cast<float *>(&buf.at( + static_cast<size_t>(pixel_data_size * y * exr_image->width) + + channel_offset_list[c] * + static_cast<size_t>(exr_image->width))); for (int x = 0; x < exr_image->width; x++) { float val = reinterpret_cast<float **>( exr_image->images)[c][(y + start_y) * exr_image->width + x]; tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); - // Assume increasing Y - float *line_ptr = reinterpret_cast<float *>(&buf.at( - static_cast<size_t>(pixel_data_size * y * exr_image->width) + - channel_offset_list[c] * - static_cast<size_t>(exr_image->width))); - line_ptr[x] = val; + // line_ptr[x] = val; + tinyexr::cpy4(line_ptr + x, &val); } } } else { @@ -11431,18 +11772,18 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image, } } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_UINT) { for (int y = 0; y < h; y++) { + // Assume increasing Y + unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at( + static_cast<size_t>(pixel_data_size * y * exr_image->width) + + channel_offset_list[c] * static_cast<size_t>(exr_image->width))); for (int x = 0; x < exr_image->width; x++) { unsigned int val = reinterpret_cast<unsigned int **>( exr_image->images)[c][(y + start_y) * exr_image->width + x]; tinyexr::swap4(&val); - // Assume increasing Y - unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at( - static_cast<size_t>(pixel_data_size * y * exr_image->width) + - channel_offset_list[c] * - static_cast<size_t>(exr_image->width))); - line_ptr[x] = val; + // line_ptr[x] = val; + tinyexr::cpy4(line_ptr + x, &val); } } } @@ -11611,26 +11952,22 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header, const char *filename, const char **err) { if (exr_image == NULL || filename == NULL || exr_header->compression_type < 0) { - if (err) { - (*err) = "Invalid argument."; - } + tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } #if !TINYEXR_USE_PIZ if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { - if (err) { - (*err) = "PIZ compression is not supported in this build."; - } + tinyexr::SetErrorMessage("PIZ compression is not supported in this build", + err); return 0; } #endif #if !TINYEXR_USE_ZFP if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { - if (err) { - (*err) = "ZFP compression is not supported in this build."; - } + tinyexr::SetErrorMessage("ZFP compression is not supported in this build", + err); return 0; } #endif @@ -11642,9 +11979,7 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header, FILE *fp = fopen(filename, "wb"); #endif if (!fp) { - if (err) { - (*err) = "Cannot write a file."; - } + tinyexr::SetErrorMessage("Cannot write a file", err); return TINYEXR_ERROR_CANT_OPEN_FILE; } @@ -11663,27 +11998,23 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header, int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { if (deep_image == NULL) { - if (err) { - (*err) = "Invalid argument."; - } + tinyexr::SetErrorMessage("Invalid argument for LoadDeepEXR", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } #ifdef _MSC_VER FILE *fp = NULL; errno_t errcode = fopen_s(&fp, filename, "rb"); - if ((!errcode) || (!fp)) { - if (err) { - (*err) = "Cannot read file."; - } + if ((0 != errcode) || (!fp)) { + tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), + err); return TINYEXR_ERROR_CANT_OPEN_FILE; } #else FILE *fp = fopen(filename, "rb"); if (!fp) { - if (err) { - (*err) = "Cannot read file."; - } + tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), + err); return TINYEXR_ERROR_CANT_OPEN_FILE; } #endif @@ -11696,9 +12027,8 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { if (filesize == 0) { fclose(fp); - if (err) { - (*err) = "File size is zero."; - } + tinyexr::SetErrorMessage("File size is zero : " + std::string(filename), + err); return TINYEXR_ERROR_INVALID_FILE; } @@ -11719,9 +12049,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { const char header[] = {0x76, 0x2f, 0x31, 0x01}; if (memcmp(marker, header, 4) != 0) { - if (err) { - (*err) = "Invalid magic number."; - } + tinyexr::SetErrorMessage("Invalid magic number", err); return TINYEXR_ERROR_INVALID_MAGIC_NUMBER; } marker += 4; @@ -11732,9 +12060,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { // ver 2.0, scanline, deep bit on(0x800) // must be [2, 0, 0, 0] if (marker[0] != 2 || marker[1] != 8 || marker[2] != 0 || marker[3] != 0) { - if (err) { - (*err) = "Unsupported version or scanline."; - } + tinyexr::SetErrorMessage("Unsupported version or scanline", err); return TINYEXR_ERROR_UNSUPPORTED_FORMAT; } @@ -11775,9 +12101,9 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { if (attr_name.compare("compression") == 0) { compression_type = data[0]; if (compression_type > TINYEXR_COMPRESSIONTYPE_PIZ) { - if (err) { - (*err) = "Unsupported compression type."; - } + std::stringstream ss; + ss << "Unsupported compression type : " << compression_type; + tinyexr::SetErrorMessage(ss.str(), err); return TINYEXR_ERROR_UNSUPPORTED_FORMAT; } @@ -11794,18 +12120,14 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { // ySampling: int if (!tinyexr::ReadChannelInfo(channels, data)) { - if (err) { - (*err) = "Failed to parse channel info."; - } + tinyexr::SetErrorMessage("Failed to parse channel info", err); return TINYEXR_ERROR_INVALID_DATA; } num_channels = static_cast<int>(channels.size()); if (num_channels < 1) { - if (err) { - (*err) = "Invalid channels format."; - } + tinyexr::SetErrorMessage("Invalid channels format", err); return TINYEXR_ERROR_INVALID_DATA; } @@ -11877,9 +12199,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { #endif // OK } else { - if (err) { - (*err) = "Unsupported format."; - } + tinyexr::SetErrorMessage("Unsupported compression format", err); return TINYEXR_ERROR_UNSUPPORTED_FORMAT; } @@ -11936,8 +12256,9 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { unsigned long dstLen = static_cast<unsigned long>(pixelOffsetTable.size() * sizeof(int)); if (!tinyexr::DecompressZip( - reinterpret_cast<unsigned char *>(&pixelOffsetTable.at(0)), &dstLen, - data_ptr + 28, static_cast<unsigned long>(packedOffsetTableSize))) { + reinterpret_cast<unsigned char *>(&pixelOffsetTable.at(0)), + &dstLen, data_ptr + 28, + static_cast<unsigned long>(packedOffsetTableSize))) { return false; } @@ -11955,9 +12276,9 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { unsigned long dstLen = static_cast<unsigned long>(unpackedSampleDataSize); if (dstLen) { if (!tinyexr::DecompressZip( - reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen, - data_ptr + 28 + packedOffsetTableSize, - static_cast<unsigned long>(packedSampleDataSize))) { + reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen, + data_ptr + 28 + packedOffsetTableSize, + static_cast<unsigned long>(packedSampleDataSize))) { return false; } assert(dstLen == static_cast<unsigned long>(unpackedSampleDataSize)); @@ -12006,8 +12327,10 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { if (channels[c].pixel_type == 0) { // UINT for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) { - unsigned int ui = *reinterpret_cast<unsigned int *>( + unsigned int ui; + unsigned int *src_ptr = reinterpret_cast<unsigned int *>( &sample_data.at(size_t(data_offset) + x * sizeof(int))); + tinyexr::cpy4(&ui, src_ptr); deep_image->image[c][y][x] = static_cast<float>(ui); // @fixme } data_offset += @@ -12015,16 +12338,19 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { } else if (channels[c].pixel_type == 1) { // half for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) { tinyexr::FP16 f16; - f16.u = *reinterpret_cast<unsigned short *>( + const unsigned short *src_ptr = reinterpret_cast<unsigned short *>( &sample_data.at(size_t(data_offset) + x * sizeof(short))); + tinyexr::cpy2(&(f16.u), src_ptr); tinyexr::FP32 f32 = half_to_float(f16); deep_image->image[c][y][x] = f32.f; } data_offset += sizeof(short) * static_cast<size_t>(samples_per_line); } else { // float for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) { - float f = *reinterpret_cast<float *>( + float f; + const float *src_ptr = reinterpret_cast<float *>( &sample_data.at(size_t(data_offset) + x * sizeof(float))); + tinyexr::cpy4(&f, src_ptr); deep_image->image[c][y][x] = f; } data_offset += sizeof(float) * static_cast<size_t>(samples_per_line); @@ -12065,6 +12391,13 @@ void InitEXRImage(EXRImage *exr_image) { exr_image->num_tiles = 0; } +void FreeEXRErrorMessage(const char *msg) { + if (msg) { + free(reinterpret_cast<void *>(const_cast<char *>(msg))); + } + return; +} + void InitEXRHeader(EXRHeader *exr_header) { if (exr_header == NULL) { return; @@ -12096,6 +12429,10 @@ int FreeEXRHeader(EXRHeader *exr_header) { } } + if (exr_header->custom_attributes) { + free(exr_header->custom_attributes); + } + return TINYEXR_SUCCESS; } @@ -12125,6 +12462,7 @@ int FreeEXRImage(EXRImage *exr_image) { free(exr_image->tiles[tid].images); } } + free(exr_image->tiles); } return TINYEXR_SUCCESS; @@ -12133,9 +12471,8 @@ int FreeEXRImage(EXRImage *exr_image) { int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version, const char *filename, const char **err) { if (exr_header == NULL || exr_version == NULL || filename == NULL) { - if (err) { - (*err) = "Invalid argument."; - } + tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile", + err); return TINYEXR_ERROR_INVALID_ARGUMENT; } @@ -12146,9 +12483,7 @@ int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version, FILE *fp = fopen(filename, "rb"); #endif if (!fp) { - if (err) { - (*err) = "Cannot read file."; - } + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); return TINYEXR_ERROR_CANT_OPEN_FILE; } @@ -12166,9 +12501,8 @@ int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version, fclose(fp); if (ret != filesize) { - if (err) { - (*err) = "fread error."; - } + tinyexr::SetErrorMessage("fread() error on " + std::string(filename), + err); return TINYEXR_ERROR_INVALID_FILE; } } @@ -12185,10 +12519,13 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers, if (memory == NULL || exr_headers == NULL || num_headers == NULL || exr_version == NULL) { // Invalid argument + tinyexr::SetErrorMessage( + "Invalid argument for ParseEXRMultipartHeaderFromMemory", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } if (size < tinyexr::kEXRVersionSize) { + tinyexr::SetErrorMessage("Data size too short", err); return TINYEXR_ERROR_INVALID_DATA; } @@ -12207,13 +12544,7 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers, marker, marker_size); if (ret != TINYEXR_SUCCESS) { - if (err) { -#ifdef _WIN32 - (*err) = _strdup(err_str.c_str()); // may leak -#else - (*err) = strdup(err_str.c_str()); // may leak -#endif - } + tinyexr::SetErrorMessage(err_str, err); return ret; } @@ -12224,9 +12555,8 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers, // `chunkCount` must exist in the header. if (info.chunk_count == 0) { - if (err) { - (*err) = "`chunkCount' attribute is not found in the header."; - } + tinyexr::SetErrorMessage( + "`chunkCount' attribute is not found in the header.", err); return TINYEXR_ERROR_INVALID_DATA; } @@ -12261,9 +12591,8 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers, const char *filename, const char **err) { if (exr_headers == NULL || num_headers == NULL || exr_version == NULL || filename == NULL) { - if (err) { - (*err) = "Invalid argument."; - } + tinyexr::SetErrorMessage( + "Invalid argument for ParseEXRMultipartHeaderFromFile()", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } @@ -12274,9 +12603,7 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers, FILE *fp = fopen(filename, "rb"); #endif if (!fp) { - if (err) { - (*err) = "Cannot read file."; - } + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); return TINYEXR_ERROR_CANT_OPEN_FILE; } @@ -12294,9 +12621,7 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers, fclose(fp); if (ret != filesize) { - if (err) { - (*err) = "fread error."; - } + tinyexr::SetErrorMessage("`fread' error. file may be corrupted.", err); return TINYEXR_ERROR_INVALID_FILE; } } @@ -12405,9 +12730,8 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images, const size_t size, const char **err) { if (exr_images == NULL || exr_headers == NULL || num_parts == 0 || memory == NULL || (size <= tinyexr::kEXRVersionSize)) { - if (err) { - (*err) = "Invalid argument."; - } + tinyexr::SetErrorMessage( + "Invalid argument for LoadEXRMultipartImageFromMemory()", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } @@ -12415,9 +12739,7 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images, size_t total_header_size = 0; for (unsigned int i = 0; i < num_parts; i++) { if (exr_headers[i]->header_len == 0) { - if (err) { - (*err) = "EXRHeader is not initialized."; - } + tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } @@ -12452,9 +12774,8 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images, tinyexr::swap8(&offset); if (offset >= size) { - if (err) { - (*err) = "Invalid offset size."; - } + tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.", + err); return TINYEXR_ERROR_INVALID_DATA; } @@ -12479,14 +12800,19 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images, tinyexr::swap4(&part_no); if (part_no != i) { - assert(0); + tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.", + err); return TINYEXR_ERROR_INVALID_DATA; } } + std::string e; int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table, - memory, size); + memory, size, &e); if (ret != TINYEXR_SUCCESS) { + if (!e.empty()) { + tinyexr::SetErrorMessage(e, err); + } return ret; } } @@ -12499,9 +12825,8 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images, unsigned int num_parts, const char *filename, const char **err) { if (exr_images == NULL || exr_headers == NULL || num_parts == 0) { - if (err) { - (*err) = "Invalid argument."; - } + tinyexr::SetErrorMessage( + "Invalid argument for LoadEXRMultipartImageFromFile", err); return TINYEXR_ERROR_INVALID_ARGUMENT; } @@ -12512,9 +12837,7 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images, FILE *fp = fopen(filename, "rb"); #endif if (!fp) { - if (err) { - (*err) = "Cannot read file."; - } + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); return TINYEXR_ERROR_CANT_OPEN_FILE; } @@ -12670,5 +12993,10 @@ int SaveEXR(const float *data, int width, int height, int components, return ret; } +#ifdef __clang__ +// zero-as-null-ppinter-constant +#pragma clang diagnostic pop +#endif + #endif // TINYEXR_IMPLEMENTATION_DEIFNED #endif // TINYEXR_IMPLEMENTATION |