diff options
Diffstat (limited to 'servers')
63 files changed, 1049 insertions, 847 deletions
diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp index 569832b8a8..a5866bb380 100644 --- a/servers/audio/effects/audio_effect_record.cpp +++ b/servers/audio/effects/audio_effect_record.cpp @@ -112,7 +112,7 @@ void AudioEffectRecordInstance::init() { ring_buffer_read_pos = 0; //We start a new recording - recording_data.resize(0); //Clear data completely and reset length + recording_data.clear(); //Clear data completely and reset length is_recording = true; #ifdef NO_THREADS diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index c89f811678..f00b8077d1 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -456,10 +456,12 @@ void AudioServer::_mix_step() { case AudioStreamPlaybackListNode::AWAITING_DELETION: case AudioStreamPlaybackListNode::FADE_OUT_TO_DELETION: playback_list.erase(playback, [](AudioStreamPlaybackListNode *p) { - if (p->prev_bus_details) + if (p->prev_bus_details) { delete p->prev_bus_details; - if (p->bus_details) + } + if (p->bus_details) { delete p->bus_details; + } p->stream_playback.unref(); delete p; }); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 01f58e37eb..d880df2a9b 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -139,10 +139,6 @@ void DisplayServer::mouse_warp_to_position(const Point2i &p_to) { WARN_PRINT("Mouse warping is not supported by this display server."); } -Point2i DisplayServer::mouse_get_absolute_position() const { - ERR_FAIL_V_MSG(Point2i(), "Mouse is not supported by this display server."); -} - Point2i DisplayServer::mouse_get_position() const { ERR_FAIL_V_MSG(Point2i(), "Mouse is not supported by this display server."); } @@ -159,6 +155,10 @@ String DisplayServer::clipboard_get() const { ERR_FAIL_V_MSG(String(), "Clipboard is not supported by this display server."); } +bool DisplayServer::clipboard_has() const { + return !clipboard_get().is_empty(); +} + void DisplayServer::clipboard_set_primary(const String &p_text) { WARN_PRINT("Primary clipboard is not supported by this display server."); } @@ -228,14 +228,6 @@ String DisplayServer::ime_get_text() const { ERR_FAIL_V_MSG(String(), "IME or NOTIFICATION_WM_IME_UPDATEnot supported by this display server."); } -void DisplayServer::console_set_visible(bool p_enabled) { - WARN_PRINT("Console window not supported by this display server."); -} - -bool DisplayServer::is_console_visible() const { - return false; -} - void DisplayServer::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) { WARN_PRINT("Virtual keyboard not supported by this display server."); } @@ -324,6 +316,11 @@ void DisplayServer::set_icon(const Ref<Image> &p_icon) { WARN_PRINT("Icon not supported by this display server."); } +int64_t DisplayServer::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const { + WARN_PRINT("Native handle not supported by this display server."); + return 0; +} + void DisplayServer::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { WARN_PRINT("Changing the VSync mode is not supported by this display server."); } @@ -367,11 +364,11 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("mouse_warp_to_position", "position"), &DisplayServer::mouse_warp_to_position); ClassDB::bind_method(D_METHOD("mouse_get_position"), &DisplayServer::mouse_get_position); - ClassDB::bind_method(D_METHOD("mouse_get_absolute_position"), &DisplayServer::mouse_get_absolute_position); ClassDB::bind_method(D_METHOD("mouse_get_button_state"), &DisplayServer::mouse_get_button_state); ClassDB::bind_method(D_METHOD("clipboard_set", "clipboard"), &DisplayServer::clipboard_set); ClassDB::bind_method(D_METHOD("clipboard_get"), &DisplayServer::clipboard_get); + ClassDB::bind_method(D_METHOD("clipboard_has"), &DisplayServer::clipboard_has); ClassDB::bind_method(D_METHOD("clipboard_set_primary", "clipboard_primary"), &DisplayServer::clipboard_set_primary); ClassDB::bind_method(D_METHOD("clipboard_get_primary"), &DisplayServer::clipboard_get_primary); @@ -383,6 +380,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("screen_get_scale", "screen"), &DisplayServer::screen_get_scale, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_is_touchscreen", "screen"), &DisplayServer::screen_is_touchscreen, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_get_max_scale"), &DisplayServer::screen_get_max_scale); + ClassDB::bind_method(D_METHOD("screen_get_refresh_rate", "screen"), &DisplayServer::screen_get_refresh_rate, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_set_orientation", "orientation", "screen"), &DisplayServer::screen_set_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_get_orientation", "screen"), &DisplayServer::screen_get_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW)); @@ -396,6 +394,8 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("create_sub_window", "mode", "vsync_mode", "flags", "rect"), &DisplayServer::create_sub_window, DEFVAL(Rect2i())); ClassDB::bind_method(D_METHOD("delete_sub_window", "window_id"), &DisplayServer::delete_sub_window); + ClassDB::bind_method(D_METHOD("window_get_native_handle", "handle_type", "window_id"), &DisplayServer::window_get_native_handle, DEFVAL(MAIN_WINDOW_ID)); + ClassDB::bind_method(D_METHOD("window_set_title", "title", "window_id"), &DisplayServer::window_set_title, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_set_mouse_passthrough", "region", "window_id"), &DisplayServer::window_set_mouse_passthrough, DEFVAL(MAIN_WINDOW_ID)); @@ -446,9 +446,6 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("ime_get_selection"), &DisplayServer::ime_get_selection); ClassDB::bind_method(D_METHOD("ime_get_text"), &DisplayServer::ime_get_text); - ClassDB::bind_method(D_METHOD("console_set_visible", "console_visible"), &DisplayServer::console_set_visible); - ClassDB::bind_method(D_METHOD("is_console_visible"), &DisplayServer::is_console_visible); - ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position", "multiline", "max_length", "cursor_start", "cursor_end"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2i()), DEFVAL(false), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("virtual_keyboard_hide"), &DisplayServer::virtual_keyboard_hide); @@ -493,7 +490,6 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_CURSOR_SHAPE); BIND_ENUM_CONSTANT(FEATURE_CUSTOM_CURSOR_SHAPE); BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG); - BIND_ENUM_CONSTANT(FEATURE_CONSOLE_WINDOW); BIND_ENUM_CONSTANT(FEATURE_IME); BIND_ENUM_CONSTANT(FEATURE_WINDOW_TRANSPARENCY); BIND_ENUM_CONSTANT(FEATURE_HIDPI); @@ -544,6 +540,7 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(WINDOW_MODE_MINIMIZED); BIND_ENUM_CONSTANT(WINDOW_MODE_MAXIMIZED); BIND_ENUM_CONSTANT(WINDOW_MODE_FULLSCREEN); + BIND_ENUM_CONSTANT(WINDOW_MODE_EXCLUSIVE_FULLSCREEN); BIND_ENUM_CONSTANT(WINDOW_FLAG_RESIZE_DISABLED); BIND_ENUM_CONSTANT(WINDOW_FLAG_BORDERLESS); @@ -564,6 +561,10 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(VSYNC_ENABLED); BIND_ENUM_CONSTANT(VSYNC_ADAPTIVE); BIND_ENUM_CONSTANT(VSYNC_MAILBOX); + + BIND_ENUM_CONSTANT(DISPLAY_HANDLE); + BIND_ENUM_CONSTANT(WINDOW_HANDLE); + BIND_ENUM_CONSTANT(WINDOW_VIEW); } void DisplayServer::register_create_function(const char *p_name, CreateFunction p_function, GetRenderingDriversFunction p_get_drivers) { diff --git a/servers/display_server.h b/servers/display_server.h index a84290be77..19bb111094 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -53,7 +53,8 @@ public: WINDOW_MODE_WINDOWED, WINDOW_MODE_MINIMIZED, WINDOW_MODE_MAXIMIZED, - WINDOW_MODE_FULLSCREEN + WINDOW_MODE_FULLSCREEN, + WINDOW_MODE_EXCLUSIVE_FULLSCREEN, }; // Keep the VSyncMode enum values in sync with the `display/window/vsync/vsync_mode` @@ -65,6 +66,12 @@ public: VSYNC_MAILBOX }; + enum HandleType { + DISPLAY_HANDLE, + WINDOW_HANDLE, + WINDOW_VIEW, + }; + typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, VSyncMode, uint32_t, const Size2i &, Error &r_error); typedef Vector<String> (*GetRenderingDriversFunction)(); @@ -105,7 +112,6 @@ public: FEATURE_CURSOR_SHAPE, FEATURE_CUSTOM_CURSOR_SHAPE, FEATURE_NATIVE_DIALOG, - FEATURE_CONSOLE_WINDOW, FEATURE_IME, FEATURE_WINDOW_TRANSPARENCY, FEATURE_HIDPI, @@ -157,11 +163,11 @@ public: virtual void mouse_warp_to_position(const Point2i &p_to); virtual Point2i mouse_get_position() const; - virtual Point2i mouse_get_absolute_position() const; virtual MouseButton mouse_get_button_state() const; virtual void clipboard_set(const String &p_text); virtual String clipboard_get() const; + virtual bool clipboard_has() const; virtual void clipboard_set_primary(const String &p_text); virtual String clipboard_get_primary() const; @@ -169,6 +175,8 @@ public: SCREEN_OF_MAIN_WINDOW = -1 }; + const float SCREEN_REFRESH_RATE_FALLBACK = 60.0; // Returned by screen_get_refresh_rate if the method fails. Most screens are 60hz as of 2022. + virtual int get_screen_count() const = 0; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; @@ -183,6 +191,7 @@ public: } return scale; } + virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const; // Keep the ScreenOrientation enum values in sync with the `display/window/handheld/orientation` @@ -233,6 +242,8 @@ public: virtual void show_window(WindowID p_id); virtual void delete_sub_window(WindowID p_id); + virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const; + virtual WindowID get_window_at_screen_position(const Point2i &p_position) const = 0; virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) = 0; @@ -304,9 +315,6 @@ public: virtual Point2i ime_get_selection() const; virtual String ime_get_text() const; - virtual void console_set_visible(bool p_enabled); - virtual bool is_console_visible() const; - virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); virtual void virtual_keyboard_hide(); @@ -391,6 +399,7 @@ VARIANT_ENUM_CAST(DisplayServer::MouseMode) VARIANT_ENUM_CAST(DisplayServer::ScreenOrientation) VARIANT_ENUM_CAST(DisplayServer::WindowMode) VARIANT_ENUM_CAST(DisplayServer::WindowFlags) +VARIANT_ENUM_CAST(DisplayServer::HandleType) VARIANT_ENUM_CAST(DisplayServer::CursorShape) VARIANT_ENUM_CAST(DisplayServer::VSyncMode) diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h index 4ef9dc622f..f74a8fad23 100644 --- a/servers/display_server_headless.h +++ b/servers/display_server_headless.h @@ -62,6 +62,7 @@ public: int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return 96; /* 0 might cause issues */ } float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return 1; } float screen_get_max_scale() const override { return 1; } + float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return SCREEN_REFRESH_RATE_FALLBACK; } Vector<DisplayServer::WindowID> get_window_list() const override { return Vector<DisplayServer::WindowID>(); } diff --git a/servers/physics_3d/godot_shape_3d.cpp b/servers/physics_3d/godot_shape_3d.cpp index 26fa470233..666e773c1c 100644 --- a/servers/physics_3d/godot_shape_3d.cpp +++ b/servers/physics_3d/godot_shape_3d.cpp @@ -52,11 +52,11 @@ subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. */ -#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.0002 -#define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.9998 +constexpr double edge_support_threshold = 0.0002; +constexpr double face_support_threshold = 0.9998; -#define _CYLINDER_EDGE_IS_VALID_SUPPORT_THRESHOLD 0.002 -#define _CYLINDER_FACE_IS_VALID_SUPPORT_THRESHOLD 0.999 +constexpr double cylinder_edge_support_threshold = 0.002; +constexpr double cylinder_face_support_threshold = 0.999; void GodotShape3D::configure(const AABB &p_aabb) { aabb = p_aabb; @@ -184,7 +184,7 @@ Vector3 GodotSeparationRayShape3D::get_support(const Vector3 &p_normal) const { } void GodotSeparationRayShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { - if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(p_normal.z) < edge_support_threshold) { r_amount = 2; r_type = FEATURE_EDGE; r_supports[0] = Vector3(0, 0, 0); @@ -335,7 +335,7 @@ void GodotBoxShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 * Vector3 axis; axis[i] = 1.0; real_t dot = p_normal.dot(axis); - if (Math::abs(dot) > _FACE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(dot) > face_support_threshold) { //Vector3 axis_b; bool neg = dot < 0; @@ -376,7 +376,7 @@ void GodotBoxShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 * Vector3 axis; axis[i] = 1.0; - if (Math::abs(p_normal.dot(axis)) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(p_normal.dot(axis)) < edge_support_threshold) { r_amount = 2; r_type = FEATURE_EDGE; @@ -522,7 +522,7 @@ void GodotCapsuleShape3D::get_supports(const Vector3 &p_normal, int p_max, Vecto real_t d = n.y; - if (Math::abs(d) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(d) < edge_support_threshold) { // make it flat n.y = 0.0; n.normalize(); @@ -703,7 +703,7 @@ Vector3 GodotCylinderShape3D::get_support(const Vector3 &p_normal) const { void GodotCylinderShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { real_t d = p_normal.y; - if (Math::abs(d) > _CYLINDER_FACE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(d) > cylinder_face_support_threshold) { real_t h = (d > 0) ? height : -height; Vector3 n = p_normal; @@ -718,7 +718,7 @@ void GodotCylinderShape3D::get_supports(const Vector3 &p_normal, int p_max, Vect r_supports[1].x += radius; r_supports[2] = n; r_supports[2].z += radius; - } else if (Math::abs(d) < _CYLINDER_EDGE_IS_VALID_SUPPORT_THRESHOLD) { + } else if (Math::abs(d) < cylinder_edge_support_threshold) { // make it flat Vector3 n = p_normal; n.y = 0.0; @@ -911,7 +911,7 @@ void GodotConvexPolygonShape3D::get_supports(const Vector3 &p_normal, int p_max, } for (int i = 0; i < fc; i++) { - if (faces[i].plane.normal.dot(p_normal) > _FACE_IS_VALID_SUPPORT_THRESHOLD) { + if (faces[i].plane.normal.dot(p_normal) > face_support_threshold) { int ic = faces[i].indices.size(); const int *ind = faces[i].indices.ptr(); @@ -940,7 +940,7 @@ void GodotConvexPolygonShape3D::get_supports(const Vector3 &p_normal, int p_max, for (int i = 0; i < ec; i++) { real_t dot = (vertices[edges[i].a] - vertices[edges[i].b]).normalized().dot(p_normal); dot = ABS(dot); - if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD && (edges[i].a == vtx || edges[i].b == vtx)) { + if (dot < edge_support_threshold && (edges[i].a == vtx || edges[i].b == vtx)) { r_amount = 2; r_type = FEATURE_EDGE; r_supports[0] = vertices[edges[i].a]; @@ -1140,7 +1140,7 @@ void GodotFaceShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 Vector3 n = p_normal; /** TEST FACE AS SUPPORT **/ - if (Math::abs(normal.dot(n)) > _FACE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(normal.dot(n)) > face_support_threshold) { r_amount = 3; r_type = FEATURE_FACE; for (int i = 0; i < 3; i++) { @@ -1174,7 +1174,7 @@ void GodotFaceShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 // check if edge is valid as a support real_t dot = (vertex[i] - vertex[nx]).normalized().dot(n); dot = ABS(dot); - if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { + if (dot < edge_support_threshold) { r_amount = 2; r_type = FEATURE_EDGE; r_supports[0] = vertex[i]; diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/servers/physics_3d/godot_soft_body_3d.cpp index 1de27760d5..095050b7f3 100644 --- a/servers/physics_3d/godot_soft_body_3d.cpp +++ b/servers/physics_3d/godot_soft_body_3d.cpp @@ -245,7 +245,7 @@ void GodotSoftBody3D::update_area() { const Vector3 a = x1 - x0; const Vector3 b = x2 - x0; const Vector3 cr = vec3_cross(a, b); - face.ra = cr.length(); + face.ra = cr.length() * 0.5; } // Node area. diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 3fbf4fe436..bf8b6379d2 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -80,7 +80,7 @@ ShaderTypes *shader_types = nullptr; PhysicsServer3D *_createGodotPhysics3DCallback() { - bool using_threads = GLOBAL_GET("physics/3d/run_on_thread"); + bool using_threads = GLOBAL_GET("physics/3d/run_on_separate_thread"); PhysicsServer3D *physics_server = memnew(GodotPhysicsServer3D(using_threads)); @@ -88,7 +88,7 @@ PhysicsServer3D *_createGodotPhysics3DCallback() { } PhysicsServer2D *_createGodotPhysics2DCallback() { - bool using_threads = GLOBAL_GET("physics/2d/run_on_thread"); + bool using_threads = GLOBAL_GET("physics/2d/run_on_separate_thread"); PhysicsServer2D *physics_server = memnew(GodotPhysicsServer2D(using_threads)); diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h index f02a01c97d..7032f3fb03 100644 --- a/servers/rendering/rasterizer_dummy.h +++ b/servers/rendering/rasterizer_dummy.h @@ -109,7 +109,7 @@ public: void environment_set_canvas_max_layer(RID p_env, int p_max_layer) override {} void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) override {} - void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) override {} + void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) override {} void environment_glow_set_use_bicubic_upscale(bool p_enable) override {} void environment_glow_set_use_high_quality(bool p_enable) override {} @@ -120,7 +120,7 @@ public: void environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) override {} void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {} - void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override {} + void environment_set_sdfgi(RID p_env, bool p_enable, int p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override {} void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override {} void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override {} diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index f5e2cbcd6c..418d2bc42e 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -1440,7 +1440,7 @@ void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p ERR_FAIL_COND(!occluder); if (occluder->polygon.is_valid()) { - LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_polygon); + LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(occluder->polygon); if (occluder_poly) { occluder_poly->owners.erase(occluder); } diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 4ab50782df..7183fd110f 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -115,6 +115,43 @@ RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) return uniform_set; } +RID EffectsRD::_get_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps) { + TexturePair tp; + tp.texture1 = p_texture1; + tp.texture2 = p_texture2; + + if (texture_pair_to_uniform_set_cache.has(tp)) { + RID uniform_set = texture_pair_to_uniform_set_cache[tp]; + if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + return uniform_set; + } + } + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); + u.ids.push_back(p_texture1); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 1; + u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); + u.ids.push_back(p_texture2); + uniforms.push_back(u); + } + // anything with the same configuration (one texture in binding 0 for set 0), is good + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 2); + + texture_pair_to_uniform_set_cache[tp] = uniform_set; + + return uniform_set; +} + RID EffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { if (texture_to_compute_uniform_set_cache.has(p_texture)) { RID uniform_set = texture_to_compute_uniform_set_cache[p_texture]; @@ -828,6 +865,7 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone tonemap.push_constant.use_glow = p_settings.use_glow; tonemap.push_constant.glow_intensity = p_settings.glow_intensity; + tonemap.push_constant.glow_map_strength = p_settings.glow_map_strength; tonemap.push_constant.glow_levels[0] = p_settings.glow_levels[0]; // clean this up to just pass by pointer or something tonemap.push_constant.glow_levels[1] = p_settings.glow_levels[1]; tonemap.push_constant.glow_levels[2] = p_settings.glow_levels[2]; @@ -867,7 +905,7 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass())); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture_pair(p_settings.glow_texture, p_settings.glow_map, true), 2); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3); RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); @@ -907,7 +945,7 @@ void EffectsRD::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_colo RD::get_singleton()->draw_list_bind_render_pipeline(p_subpass_draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, p_dst_format_id, false, RD::get_singleton()->draw_list_get_current_pass())); RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_for_input(p_source_color), 0); RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); // should be set to a default texture, it's ignored - RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2); // should be set to a default texture, it's ignored + RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture_pair(p_settings.glow_texture, p_settings.glow_map, true), 2); // should be set to a default texture, it's ignored RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3); RD::get_singleton()->draw_list_bind_index_array(p_subpass_draw_list, index_array); @@ -1415,7 +1453,6 @@ void EffectsRD::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_ RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); - ss_effects.used_full_mips_last_frame = use_mips; ss_effects.used_full_mips_last_frame = use_full_mips; ss_effects.used_half_size_last_frame = use_half_size; } diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index a3fb4db3df..1a080756a8 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -274,7 +274,7 @@ private: uint32_t glow_texture_size[2]; // 8 - 40 float glow_intensity; // 4 - 44 - uint32_t pad3; // 4 - 48 + float glow_map_strength; // 4 - 48 uint32_t glow_mode; // 4 - 52 float glow_levels[7]; // 28 - 80 @@ -874,6 +874,7 @@ private: } }; + Map<TexturePair, RID> texture_pair_to_uniform_set_cache; Map<RID, RID> texture_to_compute_uniform_set_cache; Map<TexturePair, RID> texture_pair_to_compute_uniform_set_cache; Map<TexturePair, RID> image_pair_to_compute_uniform_set_cache; @@ -882,6 +883,7 @@ private: RID _get_uniform_set_from_image(RID p_texture); RID _get_uniform_set_for_input(RID p_texture); RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); + RID _get_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler); RID _get_compute_uniform_set_from_texture_pair(RID p_texture, RID p_texture2, bool p_use_mipmaps = false); @@ -943,10 +945,12 @@ public: GlowMode glow_mode = GLOW_MODE_ADD; float glow_intensity = 1.0; + float glow_map_strength = 0.0f; float glow_levels[7] = { 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0 }; Vector2i glow_texture_size; bool glow_use_bicubic_upscale = false; RID glow_texture; + RID glow_map; RS::EnvironmentToneMapper tonemap_mode = RS::ENV_TONE_MAPPER_LINEAR; float exposure = 1.0; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 36604073cc..87301a9d3a 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1081,6 +1081,10 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con distance = -distance_max; } + if (p_render_data->cam_ortogonal) { + distance = 1.0; + } + uint32_t indices; surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices); if (p_render_data->render_info) { diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index a27ea75017..7987a98b0e 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -463,7 +463,6 @@ SceneShaderForwardClustered::MaterialData::~MaterialData() { RendererStorageRD::MaterialData *SceneShaderForwardClustered::_create_material_func(ShaderData *p_shader) { MaterialData *material_data = memnew(MaterialData); material_data->shader_data = p_shader; - material_data->last_frame = false; //update will happen later anyway so do nothing. return material_data; } diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index 8e7bbad63e..33049fad9c 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -189,7 +189,6 @@ public: } struct MaterialData : public RendererStorageRD::MaterialData { - uint64_t last_frame; ShaderData *shader_data; RID uniform_set; uint64_t last_pass = 0; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index b9c51f5461..778d7baa5d 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -1042,7 +1042,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<GeometryInstance *> &p_in RENDER_TIMESTAMP("Render Material"); { - RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true, 0); + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true, false); //regular forward for now Vector<Color> clear = { Color(0, 0, 0, 0), @@ -1429,6 +1429,10 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const distance = -distance_max; } + if (p_render_data->cam_ortogonal) { + distance = 1.0; + } + uint32_t indices; surf->lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices); if (p_render_data->render_info) { diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 1613a307ec..0b99948063 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -452,7 +452,6 @@ SceneShaderForwardMobile::MaterialData::~MaterialData() { RendererStorageRD::MaterialData *SceneShaderForwardMobile::_create_material_func(ShaderData *p_shader) { MaterialData *material_data = memnew(MaterialData); material_data->shader_data = p_shader; - material_data->last_frame = false; //update will happen later anyway so do nothing. return material_data; } diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index c136afd9f3..92db15e3b0 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -163,7 +163,6 @@ public: } struct MaterialData : public RendererStorageRD::MaterialData { - uint64_t last_frame; ShaderData *shader_data; RID uniform_set; uint64_t last_pass = 0; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 7e188926e0..0f3daef371 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1377,14 +1377,6 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p if (md->shader_data->uses_time) { time_used = true; } - if (md->last_frame != RendererCompositorRD::singleton->get_frame_number()) { - md->last_frame = RendererCompositorRD::singleton->get_frame_number(); - if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) { - // uniform set may be gone because a dependency was erased. In this case, it will happen - // if a texture is deleted, so just re-create it. - storage->material_force_update_textures(material, RendererStorageRD::SHADER_TYPE_2D); - } - } } } @@ -2240,7 +2232,6 @@ RendererCanvasRenderRD::MaterialData::~MaterialData() { RendererStorageRD::MaterialData *RendererCanvasRenderRD::_create_material_func(ShaderData *p_shader) { MaterialData *material_data = memnew(MaterialData); material_data->shader_data = p_shader; - material_data->last_frame = false; //update will happen later anyway so do nothing. return material_data; } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index b409264c9a..84f64b6fda 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -200,7 +200,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender { } struct MaterialData : public RendererStorageRD::MaterialData { - uint64_t last_frame; ShaderData *shader_data; RID uniform_set; diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp index 7ea117ef33..0d9477d850 100644 --- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp @@ -54,7 +54,7 @@ void RendererSceneEnvironmentRD::set_tonemap(RS::EnvironmentToneMapper p_tone_ma auto_exp_scale = p_auto_exp_scale; } -void RendererSceneEnvironmentRD::set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { +void RendererSceneEnvironmentRD::set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) { ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7"); glow_enabled = p_enable; glow_levels = p_levels; @@ -66,9 +66,11 @@ void RendererSceneEnvironmentRD::set_glow(bool p_enable, Vector<float> p_levels, glow_hdr_bleed_threshold = p_hdr_bleed_threshold; glow_hdr_bleed_scale = p_hdr_bleed_scale; glow_hdr_luminance_cap = p_hdr_luminance_cap; + glow_map_strength = p_glow_map_strength; + glow_map = p_glow_map; } -void RendererSceneEnvironmentRD::set_sdfgi(bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { +void RendererSceneEnvironmentRD::set_sdfgi(bool p_enable, int p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { sdfgi_enabled = p_enable; sdfgi_cascades = p_cascades; sdfgi_min_cell_size = p_min_cell_size; diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h index 9e36a61870..ed26fd467b 100644 --- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h @@ -102,6 +102,8 @@ public: float glow_hdr_bleed_threshold = 1.0; float glow_hdr_luminance_cap = 12.0; float glow_hdr_bleed_scale = 2.0; + float glow_map_strength = 0.0f; + RID glow_map = RID(); /// SSAO @@ -133,7 +135,7 @@ public: /// SDFGI bool sdfgi_enabled = false; - RS::EnvironmentSDFGICascades sdfgi_cascades; + int sdfgi_cascades = 6; float sdfgi_min_cell_size = 0.2; bool sdfgi_use_occlusion = false; float sdfgi_bounce_feedback = 0.0; @@ -154,8 +156,8 @@ public: void set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source); void set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale); - void set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap); - void set_sdfgi(bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias); + void set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map); + void set_sdfgi(bool p_enable, int p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias); void set_fog(bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective); void set_volumetric_fog(bool p_enable, float p_density, const Color &p_scatterin, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject); void set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance); diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp index 73cb088f6a..3069b1c379 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp @@ -42,14 +42,13 @@ const Vector3i RendererSceneGIRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFF void RendererSceneGIRD::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size, RendererSceneGIRD *p_gi) { storage = p_gi->storage; gi = p_gi; - cascade_mode = p_env->sdfgi_cascades; + num_cascades = p_env->sdfgi_cascades; min_cell_size = p_env->sdfgi_min_cell_size; uses_occlusion = p_env->sdfgi_use_occlusion; y_scale_mode = p_env->sdfgi_y_scale; static const float y_scale[3] = { 1.0, 1.5, 2.0 }; y_mult = y_scale[y_scale_mode]; - static const int cascasde_size[3] = { 4, 6, 8 }; - cascades.resize(cascasde_size[cascade_mode]); + cascades.resize(num_cascades); probe_axis_count = SDFGI::PROBE_DIVISOR + 1; solid_cell_ratio = gi->sdfgi_solid_cell_ratio; solid_cell_count = uint32_t(float(cascade_size * cascade_size * cascade_size) * solid_cell_ratio); @@ -716,7 +715,10 @@ void RendererSceneGIRD::SDFGI::create(RendererSceneEnvironmentRD *p_env, const V u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 13; RID parent_average; - if (i < cascades.size() - 1) { + if (cascades.size() == 1) { + // If there is only one SDFGI cascade, we can't use the previous cascade for blending. + parent_average = cascades[i].lightprobe_average_tex; + } else if (i < cascades.size() - 1) { parent_average = cascades[i + 1].lightprobe_average_tex; } else { parent_average = cascades[i - 1].lightprobe_average_tex; //to use something, but it won't be used diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h index a407199d0a..5e55262798 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h @@ -495,7 +495,7 @@ public: float solid_cell_ratio = 0; uint32_t solid_cell_count = 0; - RS::EnvironmentSDFGICascades cascade_mode; + int num_cascades = 6; float min_cell_size = 0; uint32_t probe_axis_count = 0; //amount of probes per axis, this is an odd number because it encloses endpoints diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index a499cedd2c..43a1812f89 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -65,7 +65,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment static const uint32_t history_frames_to_converge[RS::ENV_SDFGI_CONVERGE_MAX] = { 5, 10, 15, 20, 25, 30 }; uint32_t requested_history_size = history_frames_to_converge[gi.sdfgi_frames_to_converge]; - if (rb->sdfgi && (rb->sdfgi->cascade_mode != env->sdfgi_cascades || rb->sdfgi->min_cell_size != env->sdfgi_min_cell_size || requested_history_size != rb->sdfgi->history_size || rb->sdfgi->uses_occlusion != env->sdfgi_use_occlusion || rb->sdfgi->y_scale_mode != env->sdfgi_y_scale)) { + if (rb->sdfgi && (rb->sdfgi->num_cascades != env->sdfgi_cascades || rb->sdfgi->min_cell_size != env->sdfgi_min_cell_size || requested_history_size != rb->sdfgi->history_size || rb->sdfgi->uses_occlusion != env->sdfgi_use_occlusion || rb->sdfgi->y_scale_mode != env->sdfgi_y_scale)) { //configuration changed, erase rb->sdfgi->erase(); memdelete(rb->sdfgi); @@ -289,10 +289,10 @@ void RendererSceneRenderRD::environment_set_tonemap(RID p_env, RS::EnvironmentTo env->set_tonemap(p_tone_mapper, p_exposure, p_white, p_auto_exposure, p_min_luminance, p_max_luminance, p_auto_exp_speed, p_auto_exp_scale); } -void RendererSceneRenderRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { +void RendererSceneRenderRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) { RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); - env->set_glow(p_enable, p_levels, p_intensity, p_strength, p_mix, p_bloom_threshold, p_blend_mode, p_hdr_bleed_threshold, p_hdr_bleed_scale, p_hdr_luminance_cap); + env->set_glow(p_enable, p_levels, p_intensity, p_strength, p_mix, p_bloom_threshold, p_blend_mode, p_hdr_bleed_threshold, p_hdr_bleed_scale, p_hdr_luminance_cap, p_glow_map_strength, p_glow_map); } void RendererSceneRenderRD::environment_glow_set_use_bicubic_upscale(bool p_enable) { @@ -303,7 +303,7 @@ void RendererSceneRenderRD::environment_glow_set_use_high_quality(bool p_enable) glow_high_quality = p_enable; } -void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { +void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, int p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); @@ -514,7 +514,7 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba ambient_color_sky_mix = env->ambient_sky_contribution; const float ambient_energy = env->ambient_light_energy; ambient_color = env->ambient_light; - ambient_color.to_linear(); + ambient_color = ambient_color.to_linear(); ambient_color.r *= ambient_energy; ambient_color.g *= ambient_energy; ambient_color.b *= ambient_energy; @@ -533,7 +533,7 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba } else { const float bg_energy = env->bg_energy; Color panorama_color = ((environment_background == RS::ENV_BG_CLEAR_COLOR) ? storage->get_default_clear_color() : env->bg_color); - panorama_color.to_linear(); + panorama_color = panorama_color.to_linear(); panorama_color.r *= bg_energy; panorama_color.g *= bg_energy; panorama_color.b *= bg_energy; @@ -925,7 +925,7 @@ void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool } for (int i = 0; i < 4; i++) { //clear subdivisions - shadow_atlas->quadrants[i].shadows.resize(0); + shadow_atlas->quadrants[i].shadows.clear(); shadow_atlas->quadrants[i].shadows.resize(1 << shadow_atlas->quadrants[i].subdivision); } @@ -972,7 +972,7 @@ void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, i } } - shadow_atlas->quadrants[p_quadrant].shadows.resize(0); + shadow_atlas->quadrants[p_quadrant].shadows.clear(); shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv * subdiv); shadow_atlas->quadrants[p_quadrant].subdivision = subdiv; @@ -1132,11 +1132,11 @@ bool RendererSceneRenderRD::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_ return false; } -bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { +bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); ERR_FAIL_COND_V(!shadow_atlas, false); - LightInstance *li = light_instance_owner.get_or_null(p_light_intance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); ERR_FAIL_COND_V(!li, false); if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) { @@ -1185,8 +1185,8 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i bool should_realloc = false; bool should_redraw = false; - if (shadow_atlas->shadow_owners.has(p_light_intance)) { - old_key = shadow_atlas->shadow_owners[p_light_intance]; + if (shadow_atlas->shadow_owners.has(p_light_instance)) { + old_key = shadow_atlas->shadow_owners[p_light_instance]; old_quadrant = (old_key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; old_shadow = old_key & ShadowAtlas::SHADOW_INDEX_MASK; @@ -1230,7 +1230,7 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; _shadow_atlas_invalidate_shadow(sh, p_atlas, shadow_atlas, new_quadrant, new_shadow); - sh->owner = p_light_intance; + sh->owner = p_light_instance; sh->alloc_tick = tick; sh->version = p_light_version; @@ -1241,7 +1241,7 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i ShadowAtlas::Quadrant::Shadow *extra_sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_omni_shadow]; _shadow_atlas_invalidate_shadow(extra_sh, p_atlas, shadow_atlas, new_quadrant, new_omni_shadow); - extra_sh->owner = p_light_intance; + extra_sh->owner = p_light_instance; extra_sh->alloc_tick = tick; extra_sh->version = p_light_version; } @@ -1249,7 +1249,7 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i li->shadow_atlases.insert(p_atlas); //update it in map - shadow_atlas->shadow_owners[p_light_intance] = new_key; + shadow_atlas->shadow_owners[p_light_instance] = new_key; //make it dirty, as it should redraw anyway return true; } @@ -1270,10 +1270,10 @@ void RendererSceneRenderRD::_shadow_atlas_invalidate_shadow(RendererSceneRenderR omni_shadow->owner = RID(); } + p_shadow_atlas->shadow_owners.erase(p_shadow->owner); p_shadow->version = 0; p_shadow->owner = RID(); sli->shadow_atlases.erase(p_atlas); - p_shadow_atlas->shadow_owners.erase(p_shadow->owner); } } @@ -1920,6 +1920,11 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { rb->ambient_buffer = RID(); rb->reflection_buffer = RID(); } + + if (rb->gi.voxel_gi_buffer.is_valid()) { + RD::get_singleton()->free(rb->gi.voxel_gi_buffer); + rb->gi.voxel_gi_buffer = RID(); + } } void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatrix &p_camera) { @@ -2496,8 +2501,17 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.glow_texture_size.y = rb->blur[1].mipmaps[0].height; tonemap.glow_use_bicubic_upscale = glow_bicubic_upscale; tonemap.glow_texture = rb->blur[1].texture; + if (env->glow_map.is_valid()) { + tonemap.glow_map_strength = env->glow_map_strength; + tonemap.glow_map = storage->texture_get_rd_texture(env->glow_map); + } else { + tonemap.glow_map_strength = 0.0f; + tonemap.glow_map = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + } + } else { tonemap.glow_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + tonemap.glow_map = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); } if (rb->screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) { @@ -2590,6 +2604,7 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr tonemap.use_glow = false; tonemap.glow_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + tonemap.glow_map = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); tonemap.use_auto_exposure = false; tonemap.exposure_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); @@ -2636,8 +2651,12 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) { if (p_shadow_atlas.is_valid()) { RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas); - Size2 rtsize = storage->render_target_get_size(rb->render_target); + if (shadow_atlas_texture.is_null()) { + shadow_atlas_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + } + + Size2 rtsize = storage->render_target_get_size(rb->render_target); effects->copy_to_fb_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, true); } } @@ -3993,7 +4012,6 @@ RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_fog_shader_funcs() RendererStorageRD::MaterialData *RendererSceneRenderRD::_create_fog_material_func(FogShaderData *p_shader) { FogMaterialData *material_data = memnew(FogMaterialData); material_data->shader_data = p_shader; - material_data->last_frame = false; //update will happen later anyway so do nothing. return material_data; } @@ -4011,6 +4029,9 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) { RD::get_singleton()->free(rb->volumetric_fog->prev_light_density_map); RD::get_singleton()->free(rb->volumetric_fog->light_density_map); RD::get_singleton()->free(rb->volumetric_fog->fog_map); + RD::get_singleton()->free(rb->volumetric_fog->density_map); + RD::get_singleton()->free(rb->volumetric_fog->light_map); + RD::get_singleton()->free(rb->volumetric_fog->emissive_map); if (rb->volumetric_fog->fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) { RD::get_singleton()->free(rb->volumetric_fog->fog_uniform_set); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 6432ca99f0..899d2d763d 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -942,7 +942,6 @@ private: }; struct FogMaterialData : public RendererStorageRD::MaterialData { - uint64_t last_frame; FogShaderData *shader_data; RID uniform_set; bool uniform_set_updated; @@ -984,7 +983,7 @@ public: virtual RID shadow_atlas_create() override; virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) override; virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override; - virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override; + virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override; _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) { ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); ERR_FAIL_COND_V(!atlas, false); @@ -1062,7 +1061,7 @@ public: virtual bool is_environment(RID p_env) const override; - virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) override; + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) override; virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) override; virtual void environment_glow_set_use_high_quality(bool p_enable) override; @@ -1093,7 +1092,7 @@ public: bool environment_is_ssr_enabled(RID p_env) const; bool environment_is_sdfgi_enabled(RID p_env) const; - virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override; + virtual void environment_set_sdfgi(RID p_env, bool p_enable, int p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override; virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override; virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override; virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) override; diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index f0419b7907..f6f39230f8 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -590,6 +590,7 @@ void RendererSceneSkyRD::Sky::free(RendererStorageRD *p_storage) { if (material.is_valid()) { p_storage->free(material); + material = RID(); } } @@ -750,7 +751,6 @@ RendererStorageRD::ShaderData *RendererSceneSkyRD::_create_sky_shader_funcs() { RendererStorageRD::MaterialData *RendererSceneSkyRD::_create_sky_material_func(SkyShaderData *p_shader) { SkyMaterialData *material_data = memnew(SkyMaterialData); material_data->shader_data = p_shader; - material_data->last_frame = false; //update will happen later anyway so do nothing. return material_data; } diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h index 46d376e667..d81a415c2d 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h @@ -228,7 +228,6 @@ public: } sky_shader; struct SkyMaterialData : public RendererStorageRD::MaterialData { - uint64_t last_frame; SkyShaderData *shader_data; RID uniform_set; bool uniform_set_updated; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 19075fab86..145c4f902e 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -2962,24 +2962,19 @@ bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<St return true; } -void RendererStorageRD::_material_uniform_set_erased(const RID &p_set, void *p_material) { +void RendererStorageRD::_material_uniform_set_erased(void *p_material) { RID rid = *(RID *)p_material; Material *material = base_singleton->material_owner.get_or_null(rid); if (material) { + if (material->data) { + // Uniform set may be gone because a dependency was erased. This happens + // if a texture is deleted, so re-create it. + base_singleton->_material_queue_update(material, false, true); + } material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); } } -void RendererStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) { - Material *material = material_owner.get_or_null(p_material); - if (material->shader_type != p_shader_type) { - return; - } - if (material->data) { - material->data->update_parameters(material->params, false, true); - } -} - void RendererStorageRD::_update_queued_materials() { while (material_update_list.first()) { Material *material = material_update_list.first()->self(); @@ -5882,8 +5877,6 @@ RendererStorageRD::ShaderData *RendererStorageRD::_create_particles_shader_func( } bool RendererStorageRD::ParticlesMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - uniform_set_updated = true; - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, base_singleton->particles_shader.shader.version_get_shader(shader_data->version, 0), 3); } @@ -5894,7 +5887,6 @@ RendererStorageRD::ParticlesMaterialData::~ParticlesMaterialData() { RendererStorageRD::MaterialData *RendererStorageRD::_create_particles_material_func(ParticlesShaderData *p_shader) { ParticlesMaterialData *material_data = memnew(ParticlesMaterialData); material_data->shader_data = p_shader; - material_data->last_frame = false; //update will happen later anyway so do nothing. return material_data; } @@ -6246,7 +6238,7 @@ void RendererStorageRD::skeleton_allocate_data(RID p_skeleton, int p_bones, bool if (skeleton->buffer.is_valid()) { RD::get_singleton()->free(skeleton->buffer); skeleton->buffer = RID(); - skeleton->data.resize(0); + skeleton->data.clear(); skeleton->uniform_set_mi = RID(); } diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 8c04274c3f..43bbcf6520 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -177,7 +177,7 @@ public: Vector<RID> texture_cache; }; typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *); - static void _material_uniform_set_erased(const RID &p_set, void *p_material); + static void _material_uniform_set_erased(void *p_material); enum DefaultRDTexture { DEFAULT_RD_TEXTURE_WHITE, @@ -910,10 +910,8 @@ private: } struct ParticlesMaterialData : public MaterialData { - uint64_t last_frame = 0; ParticlesShaderData *shader_data = nullptr; RID uniform_set; - bool uniform_set_updated = false; virtual void set_render_priority(int p_priority) {} virtual void set_next_pass(RID p_pass) {} @@ -1448,7 +1446,6 @@ public: void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters); void material_update_dependency(RID p_material, DependencyTracker *p_instance); - void material_force_update_textures(RID p_material, ShaderType p_shader_type); void material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function); diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl index fdc7729338..52787bb204 100644 --- a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl @@ -1,6 +1,6 @@ #define LIGHT_BAKE_DISABLED 0 -#define LIGHT_BAKE_DYNAMIC 1 -#define LIGHT_BAKE_STATIC 2 +#define LIGHT_BAKE_STATIC 1 +#define LIGHT_BAKE_DYNAMIC 2 struct LightData { //this structure needs to be as packed as possible highp vec3 position; diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl index 948c6e1e39..41d41758f4 100644 --- a/servers/rendering/renderer_rd/shaders/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl @@ -45,6 +45,7 @@ layout(set = 0, binding = 0) uniform sampler2D source_color; layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; layout(set = 2, binding = 0) uniform sampler2D source_glow; +layout(set = 2, binding = 1) uniform sampler2D glow_map; #ifdef USE_1D_LUT layout(set = 3, binding = 0) uniform sampler2D source_color_correction; @@ -63,7 +64,7 @@ layout(push_constant, binding = 1, std430) uniform Params { uvec2 glow_texture_size; float glow_intensity; - uint pad3; + float glow_map_strength; uint glow_mode; float glow_levels[7]; @@ -405,6 +406,9 @@ void main() { #ifndef SUBPASS if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) { vec3 glow = gather_glow(source_glow, uv_interp) * params.luminance_multiplier; + if (params.glow_map_strength > 0.001) { + glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); + } color.rgb = mix(color.rgb, glow, params.glow_intensity); } @@ -425,9 +429,11 @@ void main() { #ifndef SUBPASS // Glow - if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) { vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity * params.luminance_multiplier; + if (params.glow_map_strength > 0.001) { + glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); + } // high dynamic range -> SRGB glow = apply_tonemapping(glow, params.white); diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h index 20ca49cd71..406d946e12 100644 --- a/servers/rendering/renderer_scene.h +++ b/servers/rendering/renderer_scene.h @@ -131,7 +131,7 @@ public: virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) = 0; - virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) = 0; virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; @@ -149,7 +149,7 @@ public: virtual void environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) = 0; virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; - virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; + virtual void environment_set_sdfgi(RID p_env, bool p_enable, int p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0; virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) = 0; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 8ded180633..5b2be8e174 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -3871,8 +3871,12 @@ void RendererSceneCull::update_dirty_instances() { void RendererSceneCull::update() { //optimize bvhs - for (uint32_t i = 0; i < scenario_owner.get_rid_count(); i++) { - Scenario *s = scenario_owner.get_ptr_by_index(i); + + uint32_t rid_count = scenario_owner.get_rid_count(); + RID *rids = (RID *)alloca(sizeof(RID) * rid_count); + scenario_owner.fill_owned_buffer(rids); + for (uint32_t i = 0; i < rid_count; i++) { + Scenario *s = scenario_owner.get_or_null(rids[i]); s->indexers[Scenario::INDEXER_GEOMETRY].optimize_incremental(indexer_update_iterations); s->indexers[Scenario::INDEXER_VOLUMES].optimize_incremental(indexer_update_iterations); } diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 071d88233f..ed0229f0f9 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -1113,7 +1113,7 @@ public: PASS6(environment_set_ssil, RID, bool, float, float, float, float) PASS6(environment_set_ssil_quality, RS::EnvironmentSSILQuality, bool, float, int, float, float) - PASS11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, RS::EnvironmentGlowBlendMode, float, float, float) + PASS13(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, RS::EnvironmentGlowBlendMode, float, float, float, float, RID) PASS1(environment_glow_set_use_bicubic_upscale, bool) PASS1(environment_glow_set_use_high_quality, bool) @@ -1127,7 +1127,7 @@ public: PASS2(environment_set_volumetric_fog_volume_size, int, int) PASS1(environment_set_volumetric_fog_filter_active, bool) - PASS11(environment_set_sdfgi, RID, bool, RS::EnvironmentSDFGICascades, float, RS::EnvironmentSDFGIYScale, bool, float, bool, float, float, float) + PASS11(environment_set_sdfgi, RID, bool, int, float, RS::EnvironmentSDFGIYScale, bool, float, bool, float, float, float) PASS1(environment_set_sdfgi_ray_count, RS::EnvironmentSDFGIRayCount) PASS1(environment_set_sdfgi_frames_to_converge, RS::EnvironmentSDFGIFramesToConverge) PASS1(environment_set_sdfgi_frames_to_update_light, RS::EnvironmentSDFGIFramesToUpdateLight) diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index f99d34d292..3eb90ccc4d 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -123,7 +123,7 @@ public: virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0; #endif - virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) = 0; virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; @@ -140,7 +140,7 @@ public: virtual void environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) = 0; virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; - virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; + virtual void environment_set_sdfgi(RID p_env, bool p_enable, int p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0; virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) = 0; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 17a665922f..5a84bace2d 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -549,8 +549,13 @@ void RendererViewport::draw_viewports() { // get our xr interface in case we need it Ref<XRInterface> xr_interface; - if (XRServer::get_singleton() != nullptr) { - xr_interface = XRServer::get_singleton()->get_primary_interface(); + XRServer *xr_server = XRServer::get_singleton(); + if (xr_server != nullptr) { + // let our XR server know we're about to render our frames so we can get our frame timing + xr_server->pre_render(); + + // retrieve the interface responsible for rendering + xr_interface = xr_server->get_primary_interface(); } if (Engine::get_singleton()->is_editor_hint()) { @@ -582,19 +587,26 @@ void RendererViewport::draw_viewports() { bool visible = vp->viewport_to_screen_rect != Rect2(); - if (vp->use_xr && xr_interface.is_valid()) { - visible = true; // XR viewport is always visible regardless of update mode, output is sent to HMD. - - // Override our size, make sure it matches our required size and is created as a stereo target - Size2 xr_size = xr_interface->get_render_target_size(); - - // Would have been nice if we could call viewport_set_size here, - // but alas that takes our RID and we now have our pointer, - // also we only check if view_count changes in render_target_set_size so we need to call that for this to reliably change - vp->occlusion_buffer_dirty = vp->occlusion_buffer_dirty || (vp->size != xr_size); - vp->size = xr_size; - uint32_t view_count = xr_interface->get_view_count(); - RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count); + if (vp->use_xr) { + if (xr_interface.is_valid()) { + // Override our size, make sure it matches our required size and is created as a stereo target + Size2 xr_size = xr_interface->get_render_target_size(); + + // Would have been nice if we could call viewport_set_size here, + // but alas that takes our RID and we now have our pointer, + // also we only check if view_count changes in render_target_set_size so we need to call that for this to reliably change + vp->occlusion_buffer_dirty = vp->occlusion_buffer_dirty || (vp->size != xr_size); + vp->size = xr_size; + uint32_t view_count = xr_interface->get_view_count(); + RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count); + + // Inform xr interface we're about to render its viewport, if this returns false we don't render + visible = xr_interface->pre_draw_viewport(vp->render_target); + } else { + // don't render anything + visible = false; + vp->size = Size2(); + } } if (vp->update_mode == RS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) { @@ -647,7 +659,7 @@ void RendererViewport::draw_viewports() { // measure // commit our eyes - Vector<BlitToScreen> blits = xr_interface->commit_views(vp->render_target, vp->viewport_to_screen_rect); + Vector<BlitToScreen> blits = xr_interface->post_draw_viewport(vp->render_target, vp->viewport_to_screen_rect); if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && blits.size() > 0) { if (!blit_to_screen_list.has(vp->viewport_to_screen)) { blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>(); @@ -657,9 +669,6 @@ void RendererViewport::draw_viewports() { blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]); } } - - // and for our frame timing, mark when we've finished committing our eyes - XRServer::get_singleton()->_mark_commit(); } else { RSG::storage->render_target_set_external_texture(vp->render_target, 0); @@ -813,7 +822,7 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { ERR_FAIL_COND(!viewport); if (p_active) { - ERR_FAIL_COND_MSG(active_viewports.find(viewport) != -1, "Can't make active a Viewport that is already active."); + ERR_FAIL_COND_MSG(active_viewports.has(viewport), "Can't make active a Viewport that is already active."); viewport->occlusion_buffer_dirty = true; active_viewports.push_back(viewport); } else { diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 46fb3c8537..6fc5d0b3e8 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -451,7 +451,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier); ClassDB::bind_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::compute_list_end, DEFVAL(BARRIER_MASK_ALL)); - ClassDB::bind_method(D_METHOD("free", "rid"), &RenderingDevice::free); + ClassDB::bind_method(D_METHOD("free_rid", "rid"), &RenderingDevice::free); ClassDB::bind_method(D_METHOD("capture_timestamp", "name"), &RenderingDevice::capture_timestamp); ClassDB::bind_method(D_METHOD("get_captured_timestamps_count"), &RenderingDevice::get_captured_timestamps_count); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 3e74741de0..655a32a805 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -742,7 +742,7 @@ public: virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0; virtual bool uniform_set_is_valid(RID p_uniform_set) = 0; - typedef void (*UniformSetInvalidatedCallback)(const RID &, void *); + typedef void (*UniformSetInvalidatedCallback)(void *); virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata) = 0; virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp index 19cde610ba..e50ac42027 100644 --- a/servers/rendering/rendering_device_binds.cpp +++ b/servers/rendering/rendering_device_binds.cpp @@ -99,11 +99,11 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String if (reading_versions) { String l = line.strip_edges(); if (!l.is_empty()) { - if (l.find("=") == -1) { + if (!l.contains("=")) { base_error = "Missing `=` in '" + l + "'. Version syntax is `version = \"<defines with C escaping>\";`."; break; } - if (l.find(";") == -1) { + if (!l.contains(";")) { // We don't require a semicolon per se, but it's needed for clang-format to handle things properly. base_error = "Missing `;` in '" + l + "'. Version syntax is `version = \"<defines with C escaping>\";`."; break; diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index d7e9d210db..d93aad5d7b 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -93,6 +93,12 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { RSG::rasterizer->end_frame(p_swap_buffers); + XRServer *xr_server = XRServer::get_singleton(); + if (xr_server != nullptr) { + // let our XR server know we're done so we can get our frame timing + xr_server->end_frame(); + } + RSG::canvas->update_visibility_notifiers(); RSG::scene->update_visibility_notifiers(); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index ead49f053c..6d2c36537b 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -259,7 +259,6 @@ public: command_queue.push(RSG::storage, &RendererStorage::mesh_initialize, mesh); command_queue.push(RSG::storage, &RendererStorage::mesh_set_blend_shape_count, mesh, p_blend_shape_count); for (int i = 0; i < p_surfaces.size(); i++) { - RSG::storage->mesh_add_surface(mesh, p_surfaces[i]); command_queue.push(RSG::storage, &RendererStorage::mesh_add_surface, mesh, p_surfaces[i]); } } @@ -629,7 +628,7 @@ public: FUNC6(environment_set_ssil, RID, bool, float, float, float, float) FUNC6(environment_set_ssil_quality, EnvironmentSSILQuality, bool, float, int, float, float) - FUNC11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float) + FUNC13(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float, float, RID) FUNC1(environment_glow_set_use_bicubic_upscale, bool) FUNC1(environment_glow_set_use_high_quality, bool) @@ -643,7 +642,7 @@ public: FUNC2(environment_set_volumetric_fog_volume_size, int, int) FUNC1(environment_set_volumetric_fog_filter_active, bool) - FUNC11(environment_set_sdfgi, RID, bool, EnvironmentSDFGICascades, float, EnvironmentSDFGIYScale, bool, float, bool, float, float, float) + FUNC11(environment_set_sdfgi, RID, bool, int, float, EnvironmentSDFGIYScale, bool, float, bool, float, float, float) FUNC1(environment_set_sdfgi_ray_count, EnvironmentSDFGIRayCount) FUNC1(environment_set_sdfgi_frames_to_converge, EnvironmentSDFGIFramesToConverge) FUNC1(environment_set_sdfgi_frames_to_update_light, EnvironmentSDFGIFramesToUpdateLight) diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index b0629de2f0..5b43ca4bcd 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -182,7 +182,7 @@ static String _mkid(const String &p_id) { static String f2sp0(float p_float) { String num = rtoss(p_float); - if (num.find(".") == -1 && num.find("e") == -1) { + if (!num.contains(".") && !num.contains("e")) { num += ".0"; } return num; @@ -813,6 +813,9 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) { code += scode; //use directly + if (bnode->use_comma_between_statements && i + 1 < bnode->statements.size()) { + code += ","; + } } else { code += _mktab(p_level) + scode + ";\n"; } @@ -832,16 +835,49 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene } else { declaration += _prestr(vdnode->precision) + _typestr(vdnode->datatype); } + declaration += " "; for (int i = 0; i < vdnode->declarations.size(); i++) { + bool is_array = vdnode->declarations[i].size > 0; if (i > 0) { declaration += ","; - } else { - declaration += " "; } declaration += _mkid(vdnode->declarations[i].name); - if (vdnode->declarations[i].initializer) { - declaration += "="; - declaration += _dump_node_code(vdnode->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + if (is_array) { + declaration += "["; + if (vdnode->declarations[i].size_expression != nullptr) { + declaration += _dump_node_code(vdnode->declarations[i].size_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } else { + declaration += itos(vdnode->declarations[i].size); + } + declaration += "]"; + } + + if (!is_array || vdnode->declarations[i].single_expression) { + if (!vdnode->declarations[i].initializer.is_empty()) { + declaration += "="; + declaration += _dump_node_code(vdnode->declarations[i].initializer[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } + } else { + int size = vdnode->declarations[i].initializer.size(); + if (size > 0) { + declaration += "="; + if (vdnode->datatype == SL::TYPE_STRUCT) { + declaration += _mkid(vdnode->struct_name); + } else { + declaration += _typestr(vdnode->datatype); + } + declaration += "["; + declaration += itos(size); + declaration += "]"; + declaration += "("; + for (int j = 0; j < size; j++) { + if (j > 0) { + declaration += ","; + } + declaration += _dump_node_code(vdnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } + declaration += ")"; + } } } @@ -943,58 +979,6 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene } code += ")"; } break; - case SL::Node::TYPE_ARRAY_DECLARATION: { - SL::ArrayDeclarationNode *adnode = (SL::ArrayDeclarationNode *)p_node; - String declaration; - declaration += _constr(adnode->is_const); - if (adnode->datatype == SL::TYPE_STRUCT) { - declaration += _mkid(adnode->struct_name); - } else { - declaration += _prestr(adnode->precision) + _typestr(adnode->datatype); - } - for (int i = 0; i < adnode->declarations.size(); i++) { - if (i > 0) { - declaration += ","; - } else { - declaration += " "; - } - declaration += _mkid(adnode->declarations[i].name); - declaration += "["; - if (adnode->size_expression != nullptr) { - declaration += _dump_node_code(adnode->size_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } else { - declaration += itos(adnode->declarations[i].size); - } - declaration += "]"; - if (adnode->declarations[i].single_expression) { - declaration += "="; - declaration += _dump_node_code(adnode->declarations[i].initializer[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } else { - int sz = adnode->declarations[i].initializer.size(); - if (sz > 0) { - declaration += "="; - if (adnode->datatype == SL::TYPE_STRUCT) { - declaration += _mkid(adnode->struct_name); - } else { - declaration += _typestr(adnode->datatype); - } - declaration += "["; - declaration += itos(sz); - declaration += "]"; - declaration += "("; - for (int j = 0; j < sz; j++) { - declaration += _dump_node_code(adnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - if (j != sz - 1) { - declaration += ", "; - } - } - declaration += ")"; - } - } - } - - code += declaration; - } break; case SL::Node::TYPE_ARRAY: { SL::ArrayNode *anode = (SL::ArrayNode *)p_node; bool use_fragment_varying = false; @@ -1306,10 +1290,10 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } else if (cfnode->flow_op == SL::FLOW_OP_FOR) { String left = _dump_node_code(cfnode->blocks[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - String middle = _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - String right = _dump_node_code(cfnode->expressions[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + String middle = _dump_node_code(cfnode->blocks[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + String right = _dump_node_code(cfnode->blocks[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += _mktab(p_level) + "for (" + left + ";" + middle + ";" + right + ")\n"; - code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + code += _dump_node_code(cfnode->blocks[3], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) { if (cfnode->expressions.size()) { diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 7641943fe9..ead196b7dd 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -35,18 +35,6 @@ #define HAS_WARNING(flag) (warning_flags & flag) -static bool _is_text_char(char32_t c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; -} - -static bool _is_number(char32_t c) { - return (c >= '0' && c <= '9'); -} - -static bool _is_hex(char32_t c) { - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); -} - String ShaderLanguage::get_operator_text(Operator p_op) { static const char *op_names[OP_MAX] = { "==", "!=", @@ -543,7 +531,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { default: { char_idx--; //go back one, since we have no idea what this is - if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) { + if (is_digit(GETCHAR(0)) || (GETCHAR(0) == '.' && is_digit(GETCHAR(1)))) { // parse number bool hexa_found = false; bool period_found = false; @@ -584,7 +572,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { const char32_t symbol = String::char_lowercase(GETCHAR(i)); bool error = false; - if (_is_number(symbol)) { + if (is_digit(symbol)) { if (end_suffix_found) { error = true; } @@ -617,8 +605,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { break; } } - } else if (!hexa_found || !_is_hex(symbol)) { - if (_is_text_char(symbol)) { + } else if (!hexa_found || !is_hex_digit(symbol)) { + if (is_ascii_identifier_char(symbol)) { error = true; } else { break; @@ -649,7 +637,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant"); } } else if (period_found || exponent_found || float_suffix_found) { // Float - if (exponent_found && (!_is_number(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+" + if (exponent_found && (!is_digit(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+" return _make_token(TK_ERROR, "Invalid (float) numeric constant"); } if (period_found) { @@ -660,7 +648,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { } } else { //checks for eg. "1." or "1.99" notations - if (last_char != '.' && !_is_number(last_char)) { + if (last_char != '.' && !is_digit(last_char)) { return _make_token(TK_ERROR, "Invalid (float) numeric constant"); } } @@ -723,11 +711,11 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_PERIOD); } - if (_is_text_char(GETCHAR(0))) { + if (is_ascii_identifier_char(GETCHAR(0))) { // parse identifier String str; - while (_is_text_char(GETCHAR(0))) { + while (is_ascii_identifier_char(GETCHAR(0))) { str += char32_t(GETCHAR(0)); char_idx++; } @@ -2742,13 +2730,13 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI //stage based function const StageFunctionInfo &sf = p_function_info.stage_functions[name]; if (argcount != sf.arguments.size()) { - _set_error(vformat("Invalid number of arguments when calling stage function '%s', which expects %d arguments.", String(name), sf.arguments.size())); + _set_error(vformat(RTR("Invalid number of arguments when calling stage function '%s', which expects %d arguments."), String(name), sf.arguments.size())); return false; } //validate arguments for (int i = 0; i < argcount; i++) { if (args[i] != sf.arguments[i].type) { - _set_error(vformat("Invalid argument type when calling stage function '%s', type expected is '%s'.", String(name), String(get_datatype_name(sf.arguments[i].type)))); + _set_error(vformat(RTR("Invalid argument type when calling stage function '%s', type expected is '%s'."), String(name), get_datatype_name(sf.arguments[i].type))); return false; } } @@ -2852,7 +2840,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } } if (error) { - _set_error(vformat("Expected integer constant within %s..%s range.", min, max)); + _set_error(vformat(RTR("Expected integer constant within [%d..%d] range."), min, max)); return false; } } @@ -2871,7 +2859,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } if (arg_idx < argcount) { if (p_func->arguments[arg_idx + 1]->type != Node::TYPE_VARIABLE && p_func->arguments[arg_idx + 1]->type != Node::TYPE_MEMBER && p_func->arguments[arg_idx + 1]->type != Node::TYPE_ARRAY) { - _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member."); + _set_error(vformat(RTR("Argument %d of function '%s' is not a variable, array, or member."), arg_idx + 1, String(name))); return false; } @@ -2895,7 +2883,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI fail = true; } else { if (shader->varyings.has(varname)) { - _set_error(vformat("Varyings cannot be passed for '%s' parameter!", "out")); + _set_error(vformat(RTR("Varyings cannot be passed for the '%s' parameter."), "out")); return false; } if (p_function_info.built_ins.has(varname)) { @@ -2908,7 +2896,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } } if (fail) { - _set_error(vformat("Constant value cannot be passed for '%s' parameter!", "out")); + _set_error(vformat(RTR("A constant value cannot be passed for the '%s' parameter."), "out")); return false; } @@ -2921,7 +2909,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI n = static_cast<const MemberNode *>(n)->owner; } if (n->type != Node::TYPE_VARIABLE && n->type != Node::TYPE_ARRAY) { - _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member."); + _set_error(vformat(RTR("Argument %d of function '%s' is not a variable, array, or member."), arg_idx + 1, String(name))); return false; } if (n->type == Node::TYPE_VARIABLE) { @@ -2951,7 +2939,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } if (!valid) { - _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' can only take a local variable, array or member."); + _set_error(vformat(RTR("Argument %d of function '%s' can only take a local variable, array, or member."), arg_idx + 1, String(name))); return false; } } @@ -2998,16 +2986,15 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI arglist += get_datatype_name(builtin_func_defs[builtin_idx].args[i]); } - String err = "Built-in function \"" + String(name) + "(" + arglist + ")\" is supported only on high-end platform!"; - _set_error(err); + _set_error(vformat(RTR("Built-in function \"%s(%s)\" is only supported on high-end platforms."), String(name), arglist)); return false; } if (failed_builtin) { - String err = "Invalid arguments for built-in function: " + String(name) + "("; + String arg_list; for (int i = 0; i < argcount; i++) { if (i > 0) { - err += ","; + arg_list += ","; } String arg_name; @@ -3021,10 +3008,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI arg_name += itos(args3[i]); arg_name += "]"; } - err += arg_name; + arg_list += arg_name; } - err += ")"; - _set_error(err); + _set_error(vformat(RTR("Invalid arguments for the built-in function: \"%s(%s)\"."), String(name), arg_list)); return false; } @@ -3041,7 +3027,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } if (name == exclude_function) { - _set_error("Recursion is not allowed"); + _set_error(RTR("Recursion is not allowed.")); return false; } @@ -3054,7 +3040,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } if (!shader->functions[i].callable) { - _set_error("Function '" + String(name) + " can't be called from source code."); + _set_error(vformat(RTR("Function '%s' can't be called from source code."), String(name))); return false; } @@ -3113,7 +3099,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI arg_name += "]"; } - _set_error(vformat("Invalid argument for \"%s(%s)\" function: argument %s should be %s but is %s.", String(name), arg_list, j + 1, func_arg_name, arg_name)); + _set_error(vformat(RTR("Invalid argument for \"%s(%s)\" function: argument %d should be %s but is %s."), String(name), arg_list, j + 1, func_arg_name, arg_name)); fail = true; break; } @@ -3150,9 +3136,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } if (last_arg_count > args.size()) { - _set_error(vformat("Too few arguments for \"%s(%s)\" call. Expected at least %s but received %s.", String(name), arg_list, last_arg_count, args.size())); + _set_error(vformat(RTR("Too few arguments for \"%s(%s)\" call. Expected at least %d but received %d."), String(name), arg_list, last_arg_count, args.size())); } else if (last_arg_count < args.size()) { - _set_error(vformat("Too many arguments for \"%s(%s)\" call. Expected at most %s but received %s.", String(name), arg_list, last_arg_count, args.size())); + _set_error(vformat(RTR("Too many arguments for \"%s(%s)\" call. Expected at most %d but received %d."), String(name), arg_list, last_arg_count, args.size())); } return false; @@ -3190,7 +3176,7 @@ bool ShaderLanguage::_compare_datatypes(DataType p_datatype_a, String p_datatype type_name2 += "]"; } - _set_error("Invalid assignment of '" + type_name2 + "' to '" + type_name + "'"); + _set_error(vformat(RTR("Invalid assignment of '%s' to '%s'."), type_name2, type_name)); } return result; } @@ -3235,7 +3221,7 @@ bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Functio return true; } else if (tk.type != TK_COMMA) { // something is broken - _set_error("Expected ',' or ')' after argument"); + _set_error(RTR("Expected ',' or ')' after argument.")); return false; } } @@ -4247,14 +4233,14 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false); FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument]; if (arg->tex_builtin_check) { - _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other)."); + _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other)."), p_argument, String(p_name))); return false; } else if (arg->tex_argument_check) { //was checked, verify that filter and repeat are the same if (arg->tex_argument_filter == p_filter && arg->tex_argument_repeat == p_repeat) { return true; } else { - _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using textures that differ in either filter or repeat setting."); + _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using textures that differ in either filter or repeat setting."), p_argument, String(p_name))); return false; } } else { @@ -4281,14 +4267,14 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false); FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument]; if (arg->tex_argument_check) { - _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other)."); + _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other)."), p_argument, String(p_name))); return false; } else if (arg->tex_builtin_check) { //was checked, verify that the built-in is the same if (arg->tex_builtin == p_builtin) { return true; } else { - _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using different built-ins. Only calling with the same built-in is supported."); + _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using different built-ins. Only calling with the same built-in is supported."), p_argument, String(p_name))); return false; } } else { @@ -4318,7 +4304,7 @@ Error ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo & error = true; } if (error) { - _set_error("Array size is already defined!"); + _set_error(vformat(RTR("Array size is already defined."))); return ERR_PARSE_ERROR; } @@ -4327,7 +4313,7 @@ Error ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo & if (tk.type == TK_BRACKET_CLOSE) { if (p_forbid_unknown_size) { - _set_error("Unknown array size is forbidden in that context!"); + _set_error(vformat(RTR("Unknown array size is forbidden in that context."))); return ERR_PARSE_ERROR; } if (r_unknown_size != nullptr) { @@ -4364,7 +4350,7 @@ Error ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo & } } } else if (n->type == Node::TYPE_OPERATOR) { - _set_error("Array size expressions are not yet implemented."); + _set_error(vformat(RTR("Array size expressions are not supported."))); return ERR_PARSE_ERROR; } if (r_size_expression != nullptr) { @@ -4376,13 +4362,13 @@ Error ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo & } if (array_size <= 0) { - _set_error("Expected single integer constant > 0"); + _set_error(RTR("Expected a positive integer constant.")); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { - _set_error("Expected ']'"); + _set_expected_error("]"); return ERR_PARSE_ERROR; } @@ -4409,7 +4395,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc struct_name = tk.text; } else { if (!is_token_variable_datatype(tk.type)) { - _set_error("Invalid data type for array"); + _set_error(RTR("Invalid data type for the array.")); return nullptr; } type = get_token_datatype(tk.type); @@ -4422,7 +4408,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc } tk = _get_token(); } else { - _set_error("Expected '['"); + _set_expected_error("["); return nullptr; } } @@ -4460,20 +4446,20 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc break; } else { if (auto_size) { - _set_error("Expected '}' or ','"); + _set_expected_error("}", ","); } else { - _set_error("Expected ')' or ','"); + _set_expected_error(")", ","); } return nullptr; } idx++; } if (!auto_size && !undefined_size && an->initializer.size() != array_size) { - _set_error("Array size mismatch"); + _set_error(RTR("Array size mismatch.")); return nullptr; } } else { - _set_error("Expected array initialization!"); + _set_error(RTR("Expected array initialization.")); return nullptr; } @@ -4503,7 +4489,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc Node *n = _parse_and_reduce_expression(p_block, p_function_info); if (!n) { - _set_error("Invalid data type for array"); + _set_error(RTR("Invalid data type for the array.")); return nullptr; } @@ -4526,30 +4512,32 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc } tk = _get_token(); } else { - _set_error("Expected '['"); + _set_expected_error("["); return nullptr; } if (type != p_type || struct_name != p_struct_name || array_size != p_array_size) { - String error_str = "Cannot convert from '"; + String from; if (type == TYPE_STRUCT) { - error_str += struct_name; + from += struct_name; } else { - error_str += get_datatype_name(type); + from += get_datatype_name(type); } - error_str += "["; - error_str += itos(array_size); - error_str += "]'"; - error_str += " to '"; + from += "["; + from += itos(array_size); + from += "]'"; + + String to; if (type == TYPE_STRUCT) { - error_str += p_struct_name; + to += p_struct_name; } else { - error_str += get_datatype_name(p_type); + to += get_datatype_name(p_type); } - error_str += "["; - error_str += itos(p_array_size); - error_str += "]'"; - _set_error(error_str); + to += "["; + to += itos(p_array_size); + to += "]'"; + + _set_error(vformat(RTR("Cannot convert from '%s' to '%s'."), from, to)); return nullptr; } } @@ -4580,19 +4568,19 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc break; } else { if (auto_size) { - _set_error("Expected '}' or ','"); + _set_expected_error("}", ","); } else { - _set_error("Expected ')' or ','"); + _set_expected_error(")", ","); } return nullptr; } } if (an->initializer.size() != p_array_size) { - _set_error("Array size mismatch"); + _set_error(RTR("Array size mismatch.")); return nullptr; } } else { - _set_error("Expected array initialization!"); + _set_error(RTR("Expected array initialization.")); return nullptr; } @@ -4623,7 +4611,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons tk = _get_token(); if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' in expression"); + _set_error(RTR("Expected ')' in expression.")); return nullptr; } @@ -4671,7 +4659,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } else if (tk.type == TK_TYPE_VOID) { //make sure void is not used in expression - _set_error("Void value not allowed in Expression"); + _set_error(RTR("Void value not allowed in expression.")); return nullptr; } else if (is_token_nonvoid_datatype(tk.type) || tk.type == TK_CURLY_BRACKET_OPEN) { if (tk.type == TK_CURLY_BRACKET_OPEN) { @@ -4700,7 +4688,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expr = _parse_array_constructor(p_block, p_function_info); } else { if (tk.type != TK_PARENTHESIS_OPEN) { - _set_error("Expected '(' after type name"); + _set_error(RTR("Expected '(' after the type name.")); return nullptr; } //basic type constructor @@ -4733,7 +4721,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) { - _set_error("No matching constructor found for: '" + String(funcname->name) + "'"); + _set_error(vformat(RTR("No matching constructor found for: '%s'."), String(funcname->name))); return nullptr; } @@ -4790,7 +4778,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (i + 1 < pstruct->members.size()) { tk = _get_token(); if (tk.type != TK_COMMA) { - _set_error("Expected ','"); + _set_expected_error(","); return nullptr; } } @@ -4798,7 +4786,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } tk = _get_token(); if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')'"); + _set_expected_error(")"); return nullptr; } @@ -4822,7 +4810,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons ShaderLanguage::BlockNode *bnode = p_block; while (bnode) { if (bnode->variables.has(name)) { - _set_error("Expected function name"); + _set_error(RTR("Expected a function name.")); return nullptr; } bnode = bnode->parent_block; @@ -4859,7 +4847,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) { - _set_error("No matching function found for: '" + String(funcname->name) + "'"); + _set_error(vformat(RTR("No matching function found for: '%s'."), String(funcname->name))); return nullptr; } completion_class = TAG_GLOBAL; // reset sub-class @@ -4912,7 +4900,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (shader->varyings.has(varname)) { switch (shader->varyings[varname].stage) { case ShaderNode::Varying::STAGE_UNKNOWN: { - _set_error(vformat("Varying '%s' must be assigned in the vertex or fragment function first!", varname)); + _set_error(vformat(RTR("Varying '%s' must be assigned in the vertex or fragment function first."), varname)); return nullptr; } case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT: @@ -4938,7 +4926,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } if (error) { - _set_error(vformat("Varying '%s' cannot be passed for the '%s' parameter in that context!", varname, _get_qualifier_str(arg_qual))); + _set_error(vformat(RTR("Varying '%s' cannot be passed for the '%s' parameter in that context."), varname, _get_qualifier_str(arg_qual))); return nullptr; } } @@ -4985,7 +4973,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } if (error) { - _set_error(vformat("Constant value cannot be passed for '%s' parameter!", _get_qualifier_str(arg_qual))); + _set_error(vformat(RTR("A constant value cannot be passed for '%s' parameter."), _get_qualifier_str(arg_qual))); return nullptr; } } @@ -5067,12 +5055,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons idx++; } if (!found) { - _set_error("Unknown identifier in expression: " + String(identifier)); + _set_error(vformat(RTR("Unknown identifier in expression: '%s'."), String(identifier))); return nullptr; } } else { if (!_find_identifier(p_block, false, p_function_info, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) { - _set_error("Unknown identifier in expression: " + String(identifier)); + _set_error(vformat(RTR("Unknown identifier in expression: '%s'."), String(identifier))); return nullptr; } if (ident_type == IDENTIFIER_VARYING) { @@ -5114,7 +5102,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } if (ident_type == IDENTIFIER_FUNCTION) { - _set_error("Can't use function as identifier: " + String(identifier)); + _set_error(vformat(RTR("Can't use function as identifier: '%s'."), String(identifier))); return nullptr; } if (is_const) { @@ -5136,7 +5124,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (tk.type == TK_OP_ASSIGN) { if (is_const) { - _set_error("Constants cannot be modified."); + _set_error(RTR("Constants cannot be modified.")); return nullptr; } assign_expression = _parse_array_constructor(p_block, p_function_info, data_type, struct_name, array_size); @@ -5159,7 +5147,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } if (index_expression->get_array_size() != 0 || (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT)) { - _set_error("Only integer expressions are allowed for indexing."); + _set_error(RTR("Only integer expressions are allowed for indexing.")); return nullptr; } @@ -5169,7 +5157,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (!cnode->values.is_empty()) { int value = cnode->values[0].sint; if (value < 0 || value >= array_size) { - _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1)); + _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), value, 0, array_size - 1)); return nullptr; } } @@ -5178,7 +5166,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { - _set_error("Expected ']'"); + _set_expected_error("]"); return nullptr; } } else { @@ -5208,9 +5196,15 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons #ifdef DEBUG_ENABLED if (check_warnings) { StringName func_name; + BlockNode *b = p_block; - if (p_block && p_block->parent_function) { - func_name = p_block->parent_function->name; + while (b) { + if (b->parent_function) { + func_name = b->parent_function->name; + break; + } else { + b = b->parent_block; + } } _parse_used_identifier(identifier, ident_type, func_name); @@ -5246,21 +5240,34 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expression.push_back(e); continue; } else { - if (tk.type != TK_SEMICOLON) { - _set_error("Expected expression, found: " + get_token_text(tk)); - return nullptr; - } else { -#ifdef DEBUG_ENABLED - if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) { - _add_line_warning(ShaderWarning::FORMATTING_ERROR, "Empty statement. Remove ';' to fix this warning."); - } -#endif // DEBUG_ENABLED + bool valid = false; + if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_FOR_EXPRESSION && tk.type == TK_PARENTHESIS_CLOSE) { + valid = true; _set_tkpos(prepos); OperatorNode *func = alloc_node<OperatorNode>(); func->op = OP_EMPTY; expr = func; } + if (!valid) { + if (tk.type != TK_SEMICOLON) { + _set_error(vformat(RTR("Expected expression, found: '%s'."), get_token_text(tk))); + return nullptr; + } else { +#ifdef DEBUG_ENABLED + if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_FOR_INIT && p_block->block_type != BlockNode::BLOCK_TYPE_FOR_CONDITION)) { + if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) { + _add_line_warning(ShaderWarning::FORMATTING_ERROR, RTR("Empty statement. Remove ';' to fix this warning.")); + } + } +#endif // DEBUG_ENABLED + _set_tkpos(prepos); + + OperatorNode *func = alloc_node<OperatorNode>(); + func->op = OP_EMPTY; + expr = func; + } + } } ERR_FAIL_COND_V(!expr, nullptr); @@ -5299,7 +5306,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } if (identifier == StringName()) { - _set_error("Expected identifier as member"); + _set_error(RTR("Expected an identifier as a member.")); return nullptr; } String ident = identifier; @@ -5544,12 +5551,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } if (mix_error) { - _set_error("Cannot combine symbols from different sets in expression ." + ident); + _set_error(vformat(RTR("Cannot combine symbols from different sets in expression '.%s'."), ident)); return nullptr; } if (!ok) { - _set_error("Invalid member for " + (dt == TYPE_STRUCT ? st : get_datatype_name(dt)) + " expression: ." + ident); + _set_error(vformat(RTR("Invalid member for '%s' expression: '.%s'."), (dt == TYPE_STRUCT ? st : get_datatype_name(dt)), ident)); return nullptr; } @@ -5569,7 +5576,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons tk = _get_token(); if (tk.type == TK_OP_ASSIGN) { if (last_type == IDENTIFIER_CONSTANT) { - _set_error("Constants cannot be modified."); + _set_error(RTR("Constants cannot be modified.")); return nullptr; } Node *assign_expression = _parse_array_constructor(p_block, p_function_info, member_type, member_struct_name, array_size); @@ -5594,7 +5601,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } if (index_expression->get_array_size() != 0 || (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT)) { - _set_error("Only integer expressions are allowed for indexing."); + _set_error(RTR("Only integer expressions are allowed for indexing.")); return nullptr; } @@ -5604,7 +5611,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (!cnode->values.is_empty()) { int value = cnode->values[0].sint; if (value < 0 || value >= array_size) { - _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1)); + _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), value, 0, array_size - 1)); return nullptr; } } @@ -5613,7 +5620,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { - _set_error("Expected ']'"); + _set_expected_error("]"); return nullptr; } mn->index_expression = index_expression; @@ -5640,7 +5647,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } if (index->get_array_size() != 0 || (index->get_datatype() != TYPE_INT && index->get_datatype() != TYPE_UINT)) { - _set_error("Only integer expressions are allowed for indexing."); + _set_error(RTR("Only integer expressions are allowed for indexing.")); return nullptr; } @@ -5651,7 +5658,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (index->type == Node::TYPE_CONSTANT) { uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint; if (index_constant >= (uint32_t)expr->get_array_size()) { - _set_error(vformat("Index [%s] out of range [%s..%s]", index_constant, 0, expr->get_array_size() - 1)); + _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), index_constant, 0, expr->get_array_size() - 1)); return nullptr; } } @@ -5669,7 +5676,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (index->type == Node::TYPE_CONSTANT) { uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint; if (index_constant >= 2) { - _set_error("Index out of range (0-1)"); + _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), index_constant, 0, 1)); return nullptr; } } @@ -5703,7 +5710,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (index->type == Node::TYPE_CONSTANT) { uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint; if (index_constant >= 3) { - _set_error("Index out of range (0-2)"); + _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), index_constant, 0, 2)); return nullptr; } } @@ -5736,7 +5743,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (index->type == Node::TYPE_CONSTANT) { uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint; if (index_constant >= 4) { - _set_error("Index out of range (0-3)"); + _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), index_constant, 0, 3)); return nullptr; } } @@ -5762,7 +5769,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } break; default: { - _set_error("Object of type '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' can't be indexed"); + _set_error(vformat(RTR("An object of type '%s' can't be indexed."), (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())))); return nullptr; } } @@ -5777,7 +5784,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { - _set_error("Expected ']' after indexing expression"); + _set_expected_error("]"); return nullptr; } @@ -5787,12 +5794,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons op->arguments.push_back(expr); if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) { - _set_error("Invalid base type for increment/decrement operator"); + _set_error(RTR("Invalid base type for increment/decrement operator.")); return nullptr; } if (!_validate_assign(expr, p_function_info)) { - _set_error("Invalid use of increment/decrement operator in constant expression."); + _set_error(RTR("Invalid use of increment/decrement operator in a constant expression.")); return nullptr; } expr = op; @@ -5909,7 +5916,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons o.op = OP_SELECT_ELSE; break; default: { - _set_error("Invalid token for operator: " + get_token_text(tk)); + _set_error(vformat(RTR("Invalid token for the operator: '%s'."), get_token_text(tk))); return nullptr; } } @@ -6088,7 +6095,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expr_pos++; if (expr_pos == expression.size()) { //can happen.. - _set_error("Unexpected end of expression..."); + _set_error(RTR("Unexpected end of expression.")); return nullptr; } } @@ -6098,7 +6105,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons OperatorNode *op = alloc_node<OperatorNode>(); op->op = expression[i].op; if ((op->op == OP_INCREMENT || op->op == OP_DECREMENT) && !_validate_assign(expression[i + 1].node, p_function_info)) { - _set_error("Can't use increment/decrement operator in constant expression."); + _set_error(RTR("Can't use increment/decrement operator in a constant expression.")); return nullptr; } op->arguments.push_back(expression[i + 1].node); @@ -6110,7 +6117,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons String at; for (int j = 0; j < op->arguments.size(); j++) { if (j > 0) { - at += " and "; + at += ", "; } at += get_datatype_name(op->arguments[j]->get_datatype()); if (!op->arguments[j]->is_indexed() && op->arguments[j]->get_array_size() > 0) { @@ -6119,7 +6126,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons at += "]"; } } - _set_error("Invalid arguments to unary operator '" + get_operator_text(op->op) + "' :" + at); + _set_error(vformat(RTR("Invalid arguments to unary operator '%s': %s."), get_operator_text(op->op), at)); return nullptr; } expression.remove_at(i + 1); @@ -6127,12 +6134,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } else if (is_ternary) { if (next_op < 1 || next_op >= (expression.size() - 1)) { - _set_error("Parser bug..."); + _set_parsing_error(); ERR_FAIL_V(nullptr); } if (next_op + 2 >= expression.size() || !expression[next_op + 2].is_op || expression[next_op + 2].op != OP_SELECT_ELSE) { - _set_error("Missing matching ':' for select operator"); + _set_error(RTR("Missing matching ':' for select operator.")); return nullptr; } @@ -6148,7 +6155,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons String at; for (int i = 0; i < op->arguments.size(); i++) { if (i > 0) { - at += " and "; + at += ", "; } at += get_datatype_name(op->arguments[i]->get_datatype()); if (!op->arguments[i]->is_indexed() && op->arguments[i]->get_array_size() > 0) { @@ -6157,7 +6164,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons at += "]"; } } - _set_error("Invalid argument to ternary ?: operator: " + at); + _set_error(vformat(RTR("Invalid argument to ternary operator: '%s'."), at)); return nullptr; } @@ -6167,7 +6174,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } else { if (next_op < 1 || next_op >= (expression.size() - 1)) { - _set_error("Parser bug..."); + _set_parsing_error(); ERR_FAIL_V(nullptr); } @@ -6175,7 +6182,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons op->op = expression[next_op].op; if (expression[next_op - 1].is_op) { - _set_error("Parser bug..."); + _set_parsing_error(); ERR_FAIL_V(nullptr); } @@ -6193,7 +6200,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons // can be followed by a unary op in a valid combination, // due to how precedence works, unaries will always disappear first - _set_error("Parser bug..."); + _set_parsing_error(); } op->arguments.push_back(expression[next_op - 1].node); //expression goes as left @@ -6206,7 +6213,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons String at; for (int i = 0; i < op->arguments.size(); i++) { if (i > 0) { - at += " and "; + at += ", "; } if (op->arguments[i]->get_datatype() == TYPE_STRUCT) { at += op->arguments[i]->get_datatype_name(); @@ -6219,7 +6226,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons at += "]"; } } - _set_error("Invalid arguments to operator '" + get_operator_text(op->op) + "' :" + at); + _set_error(vformat(RTR("Invalid arguments to operator '%s': '%s'."), get_operator_text(op->op), at)); return nullptr; } @@ -6359,22 +6366,26 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_SWITCH) { if (tk.type != TK_CF_CASE && tk.type != TK_CF_DEFAULT && tk.type != TK_CURLY_BRACKET_CLOSE) { - _set_error("Switch may contains only case and default blocks"); + _set_error(vformat(RTR("A switch may only contain '%s' and '%s' blocks."), "case", "default")); return ERR_PARSE_ERROR; } } bool is_struct = shader->structs.has(tk.text); + bool is_var_init = false; + bool is_condition = false; if (tk.type == TK_CURLY_BRACKET_CLOSE) { //end of block if (p_just_one) { - _set_error("Unexpected '}'"); + _set_expected_error("}"); return ERR_PARSE_ERROR; } return OK; } else if (tk.type == TK_CONST || is_token_precision(tk.type) || is_token_nonvoid_datatype(tk.type) || is_struct) { + is_var_init = true; + String struct_name = ""; if (is_struct) { struct_name = tk.text; @@ -6406,18 +6417,18 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun is_struct = shader->structs.has(tk.text); // check again. } if (is_struct && precision != PRECISION_DEFAULT) { - _set_error("Precision modifier cannot be used on structs."); + _set_error(RTR("The precision modifier cannot be used on structs.")); return ERR_PARSE_ERROR; } if (!is_token_nonvoid_datatype(tk.type)) { - _set_error("Expected datatype after precision"); + _set_error(RTR("Expected variable type after precision modifier.")); return ERR_PARSE_ERROR; } } if (!is_struct) { if (!is_token_variable_datatype(tk.type)) { - _set_error("Invalid data type for variable (samplers not allowed)"); + _set_error(RTR("Invalid variable type (samplers are not allowed).")); return ERR_PARSE_ERROR; } } @@ -6428,17 +6439,23 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } - Node *vardecl = nullptr; int array_size = 0; bool fixed_array_size = false; bool first = true; + VariableDeclarationNode *vdnode = alloc_node<VariableDeclarationNode>(); + vdnode->precision = precision; + if (is_struct) { + vdnode->struct_name = struct_name; + vdnode->datatype = TYPE_STRUCT; + } else { + vdnode->datatype = type; + }; + vdnode->is_const = is_const; + do { bool unknown_size = false; - Node *size_expr = nullptr; - - ArrayDeclarationNode *anode = nullptr; - ArrayDeclarationNode::Declaration adecl; + VariableDeclarationNode::Declaration decl; tk = _get_token(); @@ -6446,17 +6463,16 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun first = false; if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) { - _set_error("Expected identifier or '[' after datatype."); + _set_error(RTR("Expected an identifier or '[' after type.")); return ERR_PARSE_ERROR; } if (tk.type == TK_BRACKET_OPEN) { - Error error = _parse_array_size(p_block, p_function_info, false, &size_expr, &array_size, &unknown_size); + Error error = _parse_array_size(p_block, p_function_info, false, &decl.size_expression, &array_size, &unknown_size); if (error != OK) { return error; } - adecl.single_expression = false; - adecl.size = array_size; + decl.size = array_size; fixed_array_size = true; tk = _get_token(); @@ -6464,7 +6480,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } if (tk.type != TK_IDENTIFIER) { - _set_error("Expected identifier!"); + _set_error(RTR("Expected an identifier.")); return ERR_PARSE_ERROR; } @@ -6472,17 +6488,24 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun ShaderLanguage::IdentifierType itype; if (_find_identifier(p_block, true, p_function_info, name, (ShaderLanguage::DataType *)nullptr, &itype)) { if (itype != IDENTIFIER_FUNCTION) { - _set_error("Redefinition of '" + String(name) + "'"); + _set_redefinition_error(String(name)); return ERR_PARSE_ERROR; } } - - adecl.name = name; + decl.name = name; #ifdef DEBUG_ENABLED - if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG)) { - if (p_block && p_block->parent_function) { - StringName func_name = p_block->parent_function->name; + if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG) && p_block) { + FunctionNode *parent_function = nullptr; + { + BlockNode *block = p_block; + while (block && !block->parent_function) { + block = block->parent_block; + } + parent_function = block->parent_function; + } + if (parent_function) { + StringName func_name = parent_function->name; if (!used_local_vars.has(func_name)) { used_local_vars.insert(func_name, Map<StringName, Usage>()); @@ -6503,50 +6526,29 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun tk = _get_token(); - bool is_array_decl = var.array_size > 0 || unknown_size; - if (tk.type == TK_BRACKET_OPEN) { if (RenderingServer::get_singleton()->is_low_end() && is_const) { - _set_error("Local const arrays are supported only on high-end platform!"); + _set_error(RTR("Local const arrays are only supported on high-end platforms.")); return ERR_PARSE_ERROR; } - Error error = _parse_array_size(p_block, p_function_info, false, &size_expr, &var.array_size, &unknown_size); + Error error = _parse_array_size(p_block, p_function_info, false, &decl.size_expression, &var.array_size, &unknown_size); if (error != OK) { return error; } - adecl.single_expression = false; - adecl.size = var.array_size; + decl.size = var.array_size; array_size = var.array_size; - is_array_decl = true; tk = _get_token(); } - if (is_array_decl) { - { - anode = alloc_node<ArrayDeclarationNode>(); - - if (is_struct) { - anode->struct_name = struct_name; - anode->datatype = TYPE_STRUCT; - } else { - anode->datatype = type; - } - - anode->precision = precision; - anode->is_const = is_const; - anode->size_expression = size_expr; - - vardecl = (Node *)anode; - } - + if (var.array_size > 0 || unknown_size) { bool full_def = false; if (tk.type == TK_OP_ASSIGN) { if (RenderingServer::get_singleton()->is_low_end()) { - _set_error("Array initialization is supported only on high-end platform!"); + _set_error(RTR("Array initialization is only supported on high-end platforms.")); return ERR_PARSE_ERROR; } @@ -6558,11 +6560,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun Node *n = _parse_and_reduce_expression(p_block, p_function_info); if (!n) { - _set_error("Expected correct array initializer!"); + _set_error(RTR("Expected array initializer.")); return ERR_PARSE_ERROR; } else { if (unknown_size) { - adecl.size = n->get_array_size(); + decl.size = n->get_array_size(); var.array_size = n->get_array_size(); } @@ -6570,15 +6572,15 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } - adecl.single_expression = true; - adecl.initializer.push_back(n); + decl.single_expression = true; + decl.initializer.push_back(n); } tk = _get_token(); } else { if (tk.type != TK_CURLY_BRACKET_OPEN) { if (unknown_size) { - _set_error("Expected '{'"); + _set_expected_error("{"); return ERR_PARSE_ERROR; } @@ -6589,11 +6591,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun precision2 = get_token_precision(tk.type); tk = _get_token(); if (shader->structs.has(tk.text)) { - _set_error("Precision modifier cannot be used on structs."); + _set_error(RTR("The precision modifier cannot be used on structs.")); return ERR_PARSE_ERROR; } if (!is_token_nonvoid_datatype(tk.type)) { - _set_error("Expected datatype after precision"); + _set_error(RTR("Expected data type after precision modifier.")); return ERR_PARSE_ERROR; } } @@ -6606,7 +6608,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun struct_name2 = tk.text; } else { if (!is_token_variable_datatype(tk.type)) { - _set_error("Invalid data type for array"); + _set_error(RTR("Invalid data type for the array.")); return ERR_PARSE_ERROR; } type2 = get_token_datatype(tk.type); @@ -6626,38 +6628,40 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } tk = _get_token(); } else { - _set_error("Expected '['"); + _set_expected_error("["); return ERR_PARSE_ERROR; } if (precision != precision2 || type != type2 || struct_name != struct_name2 || var.array_size != array_size2) { - String error_str = "Cannot convert from '"; + String from; if (precision2 != PRECISION_DEFAULT) { - error_str += get_precision_name(precision2); - error_str += " "; + from += get_precision_name(precision2); + from += " "; } if (type2 == TYPE_STRUCT) { - error_str += struct_name2; + from += struct_name2; } else { - error_str += get_datatype_name(type2); + from += get_datatype_name(type2); } - error_str += "["; - error_str += itos(array_size2); - error_str += "]'"; - error_str += " to '"; + from += "["; + from += itos(array_size2); + from += "]'"; + + String to; if (precision != PRECISION_DEFAULT) { - error_str += get_precision_name(precision); - error_str += " "; + to += get_precision_name(precision); + to += " "; } if (type == TYPE_STRUCT) { - error_str += struct_name; + to += struct_name; } else { - error_str += get_datatype_name(type); + to += get_datatype_name(type); } - error_str += "["; - error_str += itos(var.array_size); - error_str += "]'"; - _set_error(error_str); + to += "["; + to += itos(var.array_size); + to += "]'"; + + _set_error(vformat(RTR("Cannot convert from '%s' to '%s'."), from, to)); return ERR_PARSE_ERROR; } } @@ -6666,13 +6670,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun if (unknown_size) { if (!curly) { - _set_error("Expected '{'"); + _set_expected_error("{"); return ERR_PARSE_ERROR; } } else { if (full_def) { if (curly) { - _set_error("Expected '('"); + _set_expected_error("("); return ERR_PARSE_ERROR; } } @@ -6685,8 +6689,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } - if (anode->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { - _set_error("Expected constant expression"); + if (is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { + _set_error(RTR("Expected a constant expression.")); return ERR_PARSE_ERROR; } @@ -6696,28 +6700,28 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun tk = _get_token(); if (tk.type == TK_COMMA) { - adecl.initializer.push_back(n); + decl.initializer.push_back(n); continue; } else if (!curly && tk.type == TK_PARENTHESIS_CLOSE) { - adecl.initializer.push_back(n); + decl.initializer.push_back(n); break; } else if (curly && tk.type == TK_CURLY_BRACKET_CLOSE) { - adecl.initializer.push_back(n); + decl.initializer.push_back(n); break; } else { if (curly) { - _set_error("Expected '}' or ','"); + _set_expected_error("}", ","); } else { - _set_error("Expected ')' or ','"); + _set_expected_error(")", ","); } return ERR_PARSE_ERROR; } } if (unknown_size) { - adecl.size = adecl.initializer.size(); - var.array_size = adecl.initializer.size(); - } else if (adecl.initializer.size() != var.array_size) { - _set_error("Array size mismatch"); + decl.size = decl.initializer.size(); + var.array_size = decl.initializer.size(); + } else if (decl.initializer.size() != var.array_size) { + _set_error(RTR("Array size mismatch.")); return ERR_PARSE_ERROR; } tk = _get_token(); @@ -6725,48 +6729,31 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } } else { if (unknown_size) { - _set_error("Expected array initialization"); + _set_error(RTR("Expected array initialization.")); return ERR_PARSE_ERROR; } - if (anode->is_const) { - _set_error("Expected initialization of constant"); + if (is_const) { + _set_error(RTR("Expected initialization of constant.")); return ERR_PARSE_ERROR; } } array_size = var.array_size; - anode->declarations.push_back(adecl); } else if (tk.type == TK_OP_ASSIGN) { - VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>(); - if (is_struct) { - node->struct_name = struct_name; - node->datatype = TYPE_STRUCT; - } else { - node->datatype = type; - } - node->precision = precision; - node->is_const = is_const; - vardecl = (Node *)node; - - VariableDeclarationNode::Declaration decl; - decl.name = name; - decl.initializer = nullptr; - //variable created with assignment! must parse an expression Node *n = _parse_and_reduce_expression(p_block, p_function_info); if (!n) { return ERR_PARSE_ERROR; } - if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { + if (is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { OperatorNode *op = ((OperatorNode *)n); for (int i = 1; i < op->arguments.size(); i++) { if (!_check_node_constness(op->arguments[i])) { - _set_error("Expected constant expression for argument '" + itos(i - 1) + "' of function call after '='"); + _set_error(vformat(RTR("Expected constant expression for argument %d of function call after '='."), i - 1)); return ERR_PARSE_ERROR; } } } - decl.initializer = n; if (n->type == Node::TYPE_CONSTANT) { ConstantNode *const_node = static_cast<ConstantNode *>(n); @@ -6778,49 +6765,32 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun if (!_compare_datatypes(var.type, var.struct_name, var.array_size, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) { return ERR_PARSE_ERROR; } + + decl.initializer.push_back(n); tk = _get_token(); - node->declarations.push_back(decl); } else { if (is_const) { - _set_error("Expected initialization of constant"); + _set_error(RTR("Expected initialization of constant.")); return ERR_PARSE_ERROR; } - - VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>(); - if (is_struct) { - node->struct_name = struct_name; - node->datatype = TYPE_STRUCT; - } else { - node->datatype = type; - } - node->precision = precision; - vardecl = (Node *)node; - - VariableDeclarationNode::Declaration decl; - decl.name = name; - decl.initializer = nullptr; - node->declarations.push_back(decl); } - p_block->statements.push_back(vardecl); + vdnode->declarations.push_back(decl); p_block->variables[name] = var; if (!fixed_array_size) { array_size = 0; } - if (tk.type == TK_COMMA) { - if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR) { - _set_error("Multiple declarations in 'for' loop are not implemented yet."); - return ERR_PARSE_ERROR; - } - } else if (tk.type == TK_SEMICOLON) { + if (tk.type == TK_SEMICOLON) { break; - } else { - _set_error("Expected ',' or ';' after variable"); + } else if (tk.type != TK_COMMA) { + _set_expected_error(",", ";"); return ERR_PARSE_ERROR; } } while (tk.type == TK_COMMA); //another variable + + p_block->statements.push_back((Node *)vdnode); } else if (tk.type == TK_CURLY_BRACKET_OPEN) { //a sub block, just because.. BlockNode *block = alloc_node<BlockNode>(); @@ -6833,7 +6803,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun //if () {} tk = _get_token(); if (tk.type != TK_PARENTHESIS_OPEN) { - _set_error("Expected '(' after if"); + _set_expected_after_error("(", "if"); return ERR_PARSE_ERROR; } @@ -6845,13 +6815,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } if (n->get_datatype() != TYPE_BOOL) { - _set_error("Expected boolean expression"); + _set_error(RTR("Expected a boolean expression.")); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' after expression"); + _set_expected_error(")"); return ERR_PARSE_ERROR; } @@ -6881,14 +6851,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } } else if (tk.type == TK_CF_SWITCH) { if (RenderingServer::get_singleton()->is_low_end()) { - _set_error("\"switch\" operator is supported only on high-end platform!"); + _set_error(vformat(RTR("The '%s' operator is only supported on high-end platforms."), "switch")); return ERR_PARSE_ERROR; } // switch() {} tk = _get_token(); if (tk.type != TK_PARENTHESIS_OPEN) { - _set_error("Expected '(' after switch"); + _set_expected_after_error("(", "switch"); return ERR_PARSE_ERROR; } ControlFlowNode *cf = alloc_node<ControlFlowNode>(); @@ -6898,17 +6868,17 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } if (n->get_datatype() != TYPE_INT) { - _set_error("Expected integer expression"); + _set_error(RTR("Expected an integer expression.")); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' after expression"); + _set_expected_error(")"); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_CURLY_BRACKET_OPEN) { - _set_error("Expected '{' after switch statement"); + _set_expected_after_error("{", "switch"); return ERR_PARSE_ERROR; } BlockNode *switch_block = alloc_node<BlockNode>(); @@ -6929,10 +6899,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun if (tk.type == TK_CF_CASE || tk.type == TK_CF_DEFAULT) { if (prev_type == TK_CF_DEFAULT) { if (tk.type == TK_CF_CASE) { - _set_error("Cases must be defined before default case."); + _set_error(RTR("Cases must be defined before default case.")); return ERR_PARSE_ERROR; } else if (prev_type == TK_CF_DEFAULT) { - _set_error("Default case must be defined only once."); + _set_error(RTR("Default case must be defined only once.")); return ERR_PARSE_ERROR; } } @@ -6951,7 +6921,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } if (constants.has(cn->values[0].sint)) { - _set_error("Duplicated case label: '" + itos(cn->values[0].sint) + "'"); + _set_error(vformat(RTR("Duplicated case label: %d."), cn->values[0].sint)); return ERR_PARSE_ERROR; } constants.insert(cn->values[0].sint); @@ -6963,7 +6933,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun ConstantNode::Value v; _find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, nullptr, nullptr, nullptr, &v); if (constants.has(v.sint)) { - _set_error("Duplicated case label: '" + itos(v.sint) + "'"); + _set_error(vformat(RTR("Duplicated case label: %d."), v.sint)); return ERR_PARSE_ERROR; } constants.insert(v.sint); @@ -6990,7 +6960,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_SWITCH)) { - _set_error("case must be placed within switch block"); + _set_error(vformat(RTR("'%s' must be placed within a '%s' block."), "case", "switch")); return ERR_PARSE_ERROR; } @@ -7019,7 +6989,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } } if (!correct_constant_expression) { - _set_error("Expected integer constant"); + _set_error(RTR("Expected an integer constant.")); return ERR_PARSE_ERROR; } @@ -7043,7 +7013,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun tk = _get_token(); if (tk.type != TK_COLON) { - _set_error("Expected ':'"); + _set_expected_error(":"); return ERR_PARSE_ERROR; } @@ -7071,14 +7041,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_SWITCH)) { - _set_error("default must be placed within switch block"); + _set_error(vformat(RTR("'%s' must be placed within a '%s' block."), "default", "switch")); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_COLON) { - _set_error("Expected ':'"); + _set_expected_error(":"); return ERR_PARSE_ERROR; } @@ -7115,14 +7085,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun tk = _get_token(); if (tk.type != TK_CF_WHILE) { - _set_error("Expected while after do"); + _set_expected_after_error("while", "do"); return ERR_PARSE_ERROR; } } tk = _get_token(); if (tk.type != TK_PARENTHESIS_OPEN) { - _set_error("Expected '(' after while"); + _set_expected_after_error("(", "while"); return ERR_PARSE_ERROR; } @@ -7139,7 +7109,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun tk = _get_token(); if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' after expression"); + _set_expected_error(")"); return ERR_PARSE_ERROR; } if (!is_do) { @@ -7160,7 +7130,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun tk = _get_token(); if (tk.type != TK_SEMICOLON) { - _set_error("Expected ';'"); + _set_expected_error(";"); return ERR_PARSE_ERROR; } } @@ -7168,7 +7138,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun // for() {} tk = _get_token(); if (tk.type != TK_PARENTHESIS_OPEN) { - _set_error("Expected '(' after for"); + _set_expected_after_error("(", "for"); return ERR_PARSE_ERROR; } @@ -7176,43 +7146,35 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun cf->flow_op = FLOW_OP_FOR; BlockNode *init_block = alloc_node<BlockNode>(); - init_block->block_type = BlockNode::BLOCK_TYPE_FOR; + init_block->block_type = BlockNode::BLOCK_TYPE_FOR_INIT; init_block->parent_block = p_block; init_block->single_statement = true; cf->blocks.push_back(init_block); - if (_parse_block(init_block, p_function_info, true, false, false) != OK) { - return ERR_PARSE_ERROR; - } - - Node *n = _parse_and_reduce_expression(init_block, p_function_info); - if (!n) { - return ERR_PARSE_ERROR; - } - - if (n->get_datatype() != TYPE_BOOL) { - _set_error("Middle expression is expected to be boolean."); - return ERR_PARSE_ERROR; - } - - tk = _get_token(); - if (tk.type != TK_SEMICOLON) { - _set_error("Expected ';' after middle expression"); - return ERR_PARSE_ERROR; + Error err = _parse_block(init_block, p_function_info, true, false, false); + if (err != OK) { + return err; } - cf->expressions.push_back(n); - - n = _parse_and_reduce_expression(init_block, p_function_info); - if (!n) { - return ERR_PARSE_ERROR; + BlockNode *condition_block = alloc_node<BlockNode>(); + condition_block->block_type = BlockNode::BLOCK_TYPE_FOR_CONDITION; + condition_block->parent_block = init_block; + condition_block->single_statement = true; + condition_block->use_comma_between_statements = true; + cf->blocks.push_back(condition_block); + err = _parse_block(condition_block, p_function_info, true, false, false); + if (err != OK) { + return err; } - cf->expressions.push_back(n); - - tk = _get_token(); - if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' after third expression"); - return ERR_PARSE_ERROR; + BlockNode *expression_block = alloc_node<BlockNode>(); + expression_block->block_type = BlockNode::BLOCK_TYPE_FOR_EXPRESSION; + expression_block->parent_block = init_block; + expression_block->single_statement = true; + expression_block->use_comma_between_statements = true; + cf->blocks.push_back(expression_block); + err = _parse_block(expression_block, p_function_info, true, false, false); + if (err != OK) { + return err; } BlockNode *block = alloc_node<BlockNode>(); @@ -7220,8 +7182,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun cf->blocks.push_back(block); p_block->statements.push_back(cf); - Error err = _parse_block(block, p_function_info, true, true, true); - if (err) { + err = _parse_block(block, p_function_info, true, true, true); + if (err != OK) { return err; } @@ -7234,12 +7196,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } if (!b) { - _set_error("Bug"); + _set_parsing_error(); return ERR_BUG; } if (b && b->parent_function && p_function_info.main_function) { - _set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name)); + _set_error(vformat(RTR("Using '%s' in the '%s' processor function is incorrect."), "return", b->parent_function->name)); return ERR_PARSE_ERROR; } @@ -7258,7 +7220,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun if (tk.type == TK_SEMICOLON) { //all is good if (b->parent_function->return_type != TYPE_VOID) { - _set_error("Expected return with an expression of type '" + (!return_struct_name.is_empty() ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'"); + _set_error(vformat(RTR("Expected '%s' with an expression of type '%s'."), "return", (!return_struct_name.is_empty() ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string)); return ERR_PARSE_ERROR; } } else { @@ -7270,13 +7232,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } if (b->parent_function->return_type != expr->get_datatype() || b->parent_function->return_array_size != expr->get_array_size() || return_struct_name != expr->get_datatype_name()) { - _set_error("Expected return with an expression of type '" + (!return_struct_name.is_empty() ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'"); + _set_error(vformat(RTR("Expected return with an expression of type '%s'."), (!return_struct_name.is_empty() ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string)); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_SEMICOLON) { - _set_error("Expected ';' after return expression"); + _set_expected_after_error(";", "return"); return ERR_PARSE_ERROR; } @@ -7299,12 +7261,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun b = b->parent_block; } if (!b) { - _set_error("Bug"); + _set_parsing_error(); return ERR_BUG; } if (!b->parent_function->can_discard) { - _set_error("Use of 'discard' is not allowed here."); + _set_error(vformat(RTR("Use of '%s' is not allowed here."), "discard")); return ERR_PARSE_ERROR; } @@ -7314,14 +7276,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun pos = _get_tkpos(); tk = _get_token(); if (tk.type != TK_SEMICOLON) { - _set_error("Expected ';' after discard"); + _set_expected_after_error(";", "discard"); return ERR_PARSE_ERROR; } p_block->statements.push_back(flow); } else if (tk.type == TK_CF_BREAK) { if (!p_can_break) { - _set_error("'break' is not allowed outside of a loop or 'switch' statement"); + _set_error(vformat(RTR("'%s' is not allowed outside of a loop or '%s' statement."), "break", "switch")); return ERR_PARSE_ERROR; } @@ -7331,7 +7293,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun pos = _get_tkpos(); tk = _get_token(); if (tk.type != TK_SEMICOLON) { - _set_error("Expected ';' after break"); + _set_expected_after_error(";", "break"); return ERR_PARSE_ERROR; } @@ -7347,7 +7309,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } else if (tk.type == TK_CF_CONTINUE) { if (!p_can_continue) { - _set_error("'continue' is not allowed outside of a loop"); + _set_error(vformat(RTR("'%s' is not allowed outside of a loop."), "continue")); return ERR_PARSE_ERROR; } @@ -7358,7 +7320,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun tk = _get_token(); if (tk.type != TK_SEMICOLON) { //all is good - _set_error("Expected ';' after continue"); + _set_expected_after_error(";", "continue"); return ERR_PARSE_ERROR; } @@ -7371,11 +7333,52 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun if (!expr) { return ERR_PARSE_ERROR; } + is_condition = expr->type == Node::TYPE_OPERATOR && expr->get_datatype() == TYPE_BOOL; + + if (expr->type == Node::TYPE_OPERATOR) { + OperatorNode *op = static_cast<OperatorNode *>(expr); + if (op->op == OP_EMPTY) { + is_var_init = true; + is_condition = true; + } + } + p_block->statements.push_back(expr); tk = _get_token(); - if (tk.type != TK_SEMICOLON) { - _set_error("Expected ';' after statement"); + if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_CONDITION) { + if (tk.type == TK_COMMA) { + if (!is_condition) { + _set_error(RTR("The middle expression is expected to be a boolean operator.")); + return ERR_PARSE_ERROR; + } + continue; + } + if (tk.type != TK_SEMICOLON) { + _set_expected_error(",", ";"); + return ERR_PARSE_ERROR; + } + } else if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_EXPRESSION) { + if (tk.type == TK_COMMA) { + continue; + } + if (tk.type != TK_PARENTHESIS_CLOSE) { + _set_expected_error(",", ")"); + return ERR_PARSE_ERROR; + } + } else if (tk.type != TK_SEMICOLON) { + _set_expected_error(";"); + return ERR_PARSE_ERROR; + } + } + + if (p_block) { + if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_INIT && !is_var_init) { + _set_error(RTR("The left expression is expected to be a variable declaration.")); + return ERR_PARSE_ERROR; + } + if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_CONDITION && !is_condition) { + _set_error(RTR("The middle expression is expected to be a boolean operator.")); return ERR_PARSE_ERROR; } } @@ -7436,7 +7439,7 @@ Error ShaderLanguage::_validate_datatype(DataType p_type) { } if (invalid_type) { - _set_error(vformat("\"%s\" type is supported only on high-end platform!", get_datatype_name(p_type))); + _set_error(vformat(RTR("The \"%s\" type is only supported on high-end platforms."), get_datatype_name(p_type))); return ERR_UNAVAILABLE; } } @@ -7448,7 +7451,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct TkPos prev_pos; if (tk.type != TK_SHADER_TYPE) { - _set_error("Expected 'shader_type' at the beginning of shader. Valid types are: " + _get_shader_type_list(p_shader_types)); + _set_error(vformat(RTR("Expected '%s' at the beginning of shader. Valid types are: %s."), "shader_type", _get_shader_type_list(p_shader_types))); return ERR_PARSE_ERROR; } @@ -7456,11 +7459,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct _get_completable_identifier(nullptr, COMPLETION_SHADER_TYPE, shader_type_identifier); if (shader_type_identifier == StringName()) { - _set_error("Expected identifier after 'shader_type', indicating type of shader. Valid types are: " + _get_shader_type_list(p_shader_types)); + _set_error(vformat(RTR("Expected an identifier after '%s', indicating the type of shader. Valid types are: %s."), "shader_type", _get_shader_type_list(p_shader_types))); return ERR_PARSE_ERROR; } if (!p_shader_types.has(shader_type_identifier)) { - _set_error("Invalid shader type. Valid types are: " + _get_shader_type_list(p_shader_types)); + _set_error(vformat(RTR("Invalid shader type. Valid types are: %s"), _get_shader_type_list(p_shader_types))); return ERR_PARSE_ERROR; } prev_pos = _get_tkpos(); @@ -7468,7 +7471,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type != TK_SEMICOLON) { _set_tkpos(prev_pos); - _set_error("Expected ';' after 'shader_type <type>'."); + _set_expected_after_error(";", "shader_type " + String(shader_type_identifier)); return ERR_PARSE_ERROR; } @@ -7508,14 +7511,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct _get_completable_identifier(nullptr, COMPLETION_RENDER_MODE, mode); if (mode == StringName()) { - _set_error("Expected identifier for render mode"); + _set_error(RTR("Expected an identifier for render mode.")); return ERR_PARSE_ERROR; } const String smode = String(mode); - if (shader->render_modes.find(mode) != -1) { - _set_error(vformat("Duplicated render mode: '%s'.", smode)); + if (shader->render_modes.has(mode)) { + _set_error(vformat(RTR("Duplicated render mode: '%s'."), smode)); return ERR_PARSE_ERROR; } @@ -7527,11 +7530,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (smode.begins_with(name)) { if (!info.options.is_empty()) { - if (info.options.find(smode.substr(name.length() + 1)) != -1) { + if (info.options.has(smode.substr(name.length() + 1))) { found = true; if (defined_modes.has(name)) { - _set_error(vformat("Redefinition of render mode: '%s'. The %s mode has already been set to '%s'.", smode, name, defined_modes[name])); + _set_error(vformat(RTR("Redefinition of render mode: '%s'. The '%s' mode has already been set to '%s'."), smode, name, defined_modes[name])); return ERR_PARSE_ERROR; } defined_modes.insert(name, smode); @@ -7545,7 +7548,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (!found) { - _set_error(vformat("Invalid render mode: '%s'.", smode)); + _set_error(vformat(RTR("Invalid render mode: '%s'."), smode)); return ERR_PARSE_ERROR; } @@ -7557,7 +7560,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } else if (tk.type == TK_SEMICOLON) { break; //done } else { - _set_error("Unexpected token: " + get_token_text(tk)); + _set_error(vformat(RTR("Unexpected token: '%s'."), get_token_text(tk))); return ERR_PARSE_ERROR; } } @@ -7570,16 +7573,16 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_IDENTIFIER) { st.name = tk.text; if (shader->constants.has(st.name) || shader->structs.has(st.name)) { - _set_error("Redefinition of '" + String(st.name) + "'"); + _set_redefinition_error(String(st.name)); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_CURLY_BRACKET_OPEN) { - _set_error("Expected '{'"); + _set_expected_error("{"); return ERR_PARSE_ERROR; } } else { - _set_error("Expected struct identifier!"); + _set_error(RTR("Expected a struct identifier.")); return ERR_PARSE_ERROR; } @@ -7599,7 +7602,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct DataPrecision precision = DataPrecision::PRECISION_DEFAULT; if (tk.type == TK_STRUCT) { - _set_error("nested structs are not allowed!"); + _set_error(RTR("Nested structs are not allowed.")); return ERR_PARSE_ERROR; } @@ -7618,22 +7621,19 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct #endif // DEBUG_ENABLED struct_dt = true; if (use_precision) { - _set_error("Precision modifier cannot be used on structs."); + _set_error(RTR("The precision modifier cannot be used on structs.")); return ERR_PARSE_ERROR; } } if (!is_token_datatype(tk.type) && !struct_dt) { - _set_error("Expected datatype."); + _set_error(RTR("Expected data type.")); return ERR_PARSE_ERROR; } else { type = struct_dt ? TYPE_STRUCT : get_token_datatype(tk.type); - if (is_sampler_type(type)) { - _set_error("sampler datatype not allowed here"); - return ERR_PARSE_ERROR; - } else if (type == TYPE_VOID) { - _set_error("void datatype not allowed here"); + if (type == TYPE_VOID || is_sampler_type(type)) { + _set_error(vformat(RTR("A '%s' data type is not allowed here."), get_datatype_name(type))); return ERR_PARSE_ERROR; } @@ -7648,7 +7648,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct first = false; if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) { - _set_error("Expected identifier or '['."); + _set_error(RTR("Expected an identifier or '['.")); return ERR_PARSE_ERROR; } @@ -7663,7 +7663,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (tk.type != TK_IDENTIFIER) { - _set_error("Expected identifier!"); + _set_error(RTR("Expected an identifier.")); return ERR_PARSE_ERROR; } @@ -7675,7 +7675,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct member->array_size = array_size; if (member_names.has(member->name)) { - _set_error("Redefinition of '" + String(member->name) + "'"); + _set_redefinition_error(String(member->name)); return ERR_PARSE_ERROR; } member_names.insert(member->name); @@ -7694,7 +7694,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (tk.type != TK_SEMICOLON && tk.type != TK_COMMA) { - _set_error("Expected ',' or ';' after struct member."); + _set_expected_error(",", ";"); return ERR_PARSE_ERROR; } @@ -7704,13 +7704,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } } if (member_count == 0) { - _set_error("Empty structs are not allowed!"); + _set_error(RTR("Empty structs are not allowed.")); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_SEMICOLON) { - _set_error("Expected ';'"); + _set_expected_error(";"); return ERR_PARSE_ERROR; } shader->structs[st.name] = st; @@ -7724,7 +7724,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct case TK_GLOBAL: { tk = _get_token(); if (tk.type != TK_UNIFORM) { - _set_error("Expected 'uniform' after 'global'"); + _set_expected_after_error("uniform", "global"); return ERR_PARSE_ERROR; } uniform_scope = ShaderNode::Uniform::SCOPE_GLOBAL; @@ -7734,7 +7734,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (uniform_scope == ShaderNode::Uniform::SCOPE_LOCAL) { tk = _get_token(); if (tk.type != TK_UNIFORM) { - _set_error("Expected 'uniform' after 'instance'"); + _set_expected_after_error("uniform", "instance"); return ERR_PARSE_ERROR; } uniform_scope = ShaderNode::Uniform::SCOPE_INSTANCE; @@ -7747,7 +7747,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (!uniform) { if (shader_type_identifier == "particles" || shader_type_identifier == "sky" || shader_type_identifier == "fog") { - _set_error(vformat("Varyings cannot be used in '%s' shaders!", shader_type_identifier)); + _set_error(vformat(RTR("Varyings cannot be used in '%s' shaders."), shader_type_identifier)); return ERR_PARSE_ERROR; } } @@ -7762,7 +7762,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (is_token_interpolation(tk.type)) { if (uniform) { - _set_error("Interpolation qualifiers are not supported for uniforms!"); + _set_error(RTR("Interpolation qualifiers are not supported for uniforms.")); return ERR_PARSE_ERROR; } interpolation = get_token_interpolation(tk.type); @@ -7778,38 +7778,38 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (shader->structs.has(tk.text)) { if (uniform) { if (precision_defined) { - _set_error("Precision modifier cannot be used on structs."); + _set_error(RTR("The precision modifier cannot be used on structs.")); return ERR_PARSE_ERROR; } - _set_error("struct datatype is not yet supported for uniforms!"); + _set_error(vformat(RTR("The '%s' data type is not supported for uniforms."), "struct")); return ERR_PARSE_ERROR; } else { - _set_error("struct datatype not allowed here"); + _set_error(vformat(RTR("The '%s' data type not allowed here."), "struct")); return ERR_PARSE_ERROR; } } if (!is_token_datatype(tk.type)) { - _set_error("Expected datatype. "); + _set_error(RTR("Expected data type.")); return ERR_PARSE_ERROR; } type = get_token_datatype(tk.type); if (type == TYPE_VOID) { - _set_error("void datatype not allowed here"); + _set_error(vformat(RTR("The '%s' data type is not allowed here."), "void")); return ERR_PARSE_ERROR; } if (!uniform && (type < TYPE_FLOAT || type > TYPE_MAT4)) { - _set_error("Invalid type for varying, only float,vec2,vec3,vec4,mat2,mat3,mat4 or array of these types allowed."); + _set_error(RTR("Invalid type for varying, only 'float', 'vec2', 'vec3', 'vec4', 'mat2', 'mat3', 'mat4', or arrays of these types are allowed.")); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) { - _set_error("Expected identifier or '['."); + _set_error(RTR("Expected an identifier or '['.")); return ERR_PARSE_ERROR; } @@ -7822,7 +7822,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (tk.type != TK_IDENTIFIER) { - _set_error("Expected identifier!"); + _set_error(RTR("Expected an identifier.")); return ERR_PARSE_ERROR; } @@ -7830,26 +7830,26 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct name = tk.text; if (_find_identifier(nullptr, false, constants, name)) { - _set_error("Redefinition of '" + String(name) + "'"); + _set_redefinition_error(String(name)); return ERR_PARSE_ERROR; } if (has_builtin(p_functions, name)) { - _set_error("Redefinition of '" + String(name) + "'"); + _set_redefinition_error(String(name)); return ERR_PARSE_ERROR; } if (uniform) { - if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) { + if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL && Engine::get_singleton()->is_editor_hint()) { // Type checking for global uniforms is not allowed outside the editor. //validate global uniform DataType gvtype = global_var_get_type_func(name); if (gvtype == TYPE_MAX) { - _set_error("Global uniform '" + String(name) + "' does not exist. Create it in Project Settings."); + _set_error(vformat(RTR("Global uniform '%s' does not exist. Create it in Project Settings."), String(name))); return ERR_PARSE_ERROR; } if (type != gvtype) { - _set_error("Global uniform '" + String(name) + "' must be of type '" + get_datatype_name(gvtype) + "'."); + _set_error(vformat(RTR("Global uniform '%s' must be of type '%s'."), String(name), get_datatype_name(gvtype))); return ERR_PARSE_ERROR; } } @@ -7871,7 +7871,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (is_sampler_type(type)) { if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) { - _set_error("Uniforms with 'instance' qualifiers can't be of sampler type."); + _set_error(vformat(RTR("Uniforms with '%s' qualifiers can't be of sampler type.", "instance"))); return ERR_PARSE_ERROR; } uniform2.texture_order = texture_uniforms++; @@ -7887,7 +7887,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } } else { if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE && (type == TYPE_MAT2 || type == TYPE_MAT3 || type == TYPE_MAT4)) { - _set_error("Uniforms with 'instance' qualifiers can't be of matrix type."); + _set_error(vformat(RTR("Uniforms with '%s' qualifier can't be of matrix type.", "instance"))); return ERR_PARSE_ERROR; } uniform2.texture_order = -1; @@ -7916,11 +7916,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (uniform2.array_size > 0) { if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) { - _set_error("'SCOPE_GLOBAL' qualifier is not yet supported for uniform array!"); + _set_error(vformat(RTR("The '%s' qualifier is not supported for uniform arrays."), "SCOPE_GLOBAL")); return ERR_PARSE_ERROR; } if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) { - _set_error("'SCOPE_INSTANCE' qualifier is not yet supported for uniform array!"); + _set_error(vformat(RTR("The '%s' qualifier is not supported for uniform arrays."), "SCOPE_INSTANCE")); return ERR_PARSE_ERROR; } } @@ -7938,13 +7938,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct completion_line = tk.line; if (!is_token_hint(tk.type)) { - _set_error("Expected valid type hint after ':'."); + _set_error(RTR("Expected valid type hint after ':'.")); return ERR_PARSE_ERROR; } if (uniform2.array_size > 0) { if (tk.type != TK_HINT_COLOR) { - _set_error("This hint is not yet supported for uniform arrays!"); + _set_error(RTR("This hint is not supported for uniform arrays.")); return ERR_PARSE_ERROR; } } @@ -7975,20 +7975,20 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct uniform2.hint = ShaderNode::Uniform::HINT_BLACK_ALBEDO; } else if (tk.type == TK_HINT_COLOR) { if (type != TYPE_VEC4) { - _set_error("Color hint is for vec4 only"); + _set_error(vformat(RTR("Color hint is for '%s' only."), "vec4")); return ERR_PARSE_ERROR; } uniform2.hint = ShaderNode::Uniform::HINT_COLOR; } else if (tk.type == TK_HINT_RANGE) { uniform2.hint = ShaderNode::Uniform::HINT_RANGE; if (type != TYPE_FLOAT && type != TYPE_INT) { - _set_error("Range hint is for float and int only"); + _set_error(vformat(RTR("Range hint is for '%s' and '%s' only."), "float", "int")); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_PARENTHESIS_OPEN) { - _set_error("Expected '(' after hint_range"); + _set_expected_after_error("(", "hint_range"); return ERR_PARSE_ERROR; } @@ -8002,7 +8002,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) { - _set_error("Expected integer constant"); + _set_error(RTR("Expected an integer constant.")); return ERR_PARSE_ERROR; } @@ -8012,7 +8012,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type != TK_COMMA) { - _set_error("Expected ',' after integer constant"); + _set_error(RTR("Expected ',' after integer constant.")); return ERR_PARSE_ERROR; } @@ -8026,7 +8026,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) { - _set_error("Expected integer constant after ','"); + _set_error(RTR("Expected an integer constant after ','.")); return ERR_PARSE_ERROR; } @@ -8039,7 +8039,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) { - _set_error("Expected integer constant after ','"); + _set_error(RTR("Expected an integer constant after ','.")); return ERR_PARSE_ERROR; } @@ -8054,44 +8054,44 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')'"); + _set_expected_error(")"); return ERR_PARSE_ERROR; } } else if (tk.type == TK_HINT_INSTANCE_INDEX) { if (custom_instance_index != -1) { - _set_error("Can only specify 'instance_index' once."); + _set_error(vformat(RTR("Can only specify '%s' once."), "instance_index")); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_PARENTHESIS_OPEN) { - _set_error("Expected '(' after 'instance_index'"); + _set_expected_after_error("(", "instance_index"); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type == TK_OP_SUB) { - _set_error("The instance index can't be negative."); + _set_error(RTR("The instance index can't be negative.")); return ERR_PARSE_ERROR; } if (!tk.is_integer_constant()) { - _set_error("Expected integer constant"); + _set_error(RTR("Expected an integer constant.")); return ERR_PARSE_ERROR; } custom_instance_index = tk.constant; if (custom_instance_index >= MAX_INSTANCE_UNIFORM_INDICES) { - _set_error("Allowed instance uniform indices are 0-" + itos(MAX_INSTANCE_UNIFORM_INDICES - 1)); + _set_error(vformat(RTR("Allowed instance uniform indices must be within [0..%d] range."), MAX_INSTANCE_UNIFORM_INDICES - 1)); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')'"); + _set_expected_error(")"); return ERR_PARSE_ERROR; } } else if (tk.type == TK_FILTER_LINEAR) { @@ -8113,7 +8113,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && uniform2.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) { - _set_error("This hint is only for sampler types"); + _set_error(RTR("This hint is only for sampler types.")); return ERR_PARSE_ERROR; } @@ -8128,7 +8128,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } else { uniform2.instance_index = instance_index++; if (instance_index > MAX_INSTANCE_UNIFORM_INDICES) { - _set_error("Too many 'instance' uniforms in shader, maximum supported is " + itos(MAX_INSTANCE_UNIFORM_INDICES)); + _set_error(vformat(RTR("Too many '%s' uniforms in shader, maximum supported is %d."), "instance", MAX_INSTANCE_UNIFORM_INDICES)); return ERR_PARSE_ERROR; } } @@ -8138,7 +8138,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_OP_ASSIGN) { if (uniform2.array_size > 0) { - _set_error("Setting default value to a uniform array is not yet supported!"); + _set_error(RTR("Setting default values to uniform arrays is not supported.")); return ERR_PARSE_ERROR; } @@ -8147,7 +8147,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } if (expr->type != Node::TYPE_CONSTANT) { - _set_error("Expected constant expression after '='"); + _set_error(RTR("Expected constant expression after '='.")); return ERR_PARSE_ERROR; } @@ -8156,7 +8156,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct uniform2.default_value.resize(cn->values.size()); if (!convert_constant(cn, uniform2.type, uniform2.default_value.ptrw())) { - _set_error("Can't convert constant to " + get_datatype_name(uniform2.type)); + _set_error(vformat(RTR("Can't convert constant to '%s'."), get_datatype_name(uniform2.type))); return ERR_PARSE_ERROR; } tk = _get_token(); @@ -8173,7 +8173,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL; if (tk.type != TK_SEMICOLON) { - _set_error("Expected ';'"); + _set_expected_error(";"); return ERR_PARSE_ERROR; } @@ -8189,9 +8189,9 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) { if (array_size == 0) { - _set_error("Expected ';' or '['"); + _set_expected_error(";", "["); } else { - _set_error("Expected ';'"); + _set_expected_error(";"); } return ERR_PARSE_ERROR; } @@ -8214,7 +8214,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } break; case TK_SHADER_TYPE: { - _set_error("Shader type is already defined."); + _set_error(RTR("Shader type is already defined.")); return ERR_PARSE_ERROR; } break; default: { @@ -8240,19 +8240,23 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (shader->structs.has(tk.text)) { if (precision != PRECISION_DEFAULT) { - _set_error("Precision modifier cannot be used on structs."); + _set_error(RTR("The precision modifier cannot be used on structs.")); return ERR_PARSE_ERROR; } is_struct = true; struct_name = tk.text; } else { if (!is_token_datatype(tk.type)) { - _set_error("Expected constant, function, uniform or varying"); + _set_error(RTR("Expected constant, function, uniform or varying.")); return ERR_PARSE_ERROR; } if (!is_token_variable_datatype(tk.type)) { - _set_error("Invalid data type for constants or function return (samplers not allowed)"); + if (is_constant) { + _set_error(RTR("Invalid constant type (samplers are not allowed).")); + } else { + _set_error(RTR("Invalid function type (samplers are not allowed).")); + } return ERR_PARSE_ERROR; } } @@ -8270,7 +8274,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_BRACKET_OPEN) { if (is_constant && RenderingServer::get_singleton()->is_low_end()) { - _set_error("Global const arrays are only supported on high-end platform!"); + _set_error(RTR("Global constant arrays are only supported on high-end platforms.")); return ERR_PARSE_ERROR; } Error error = _parse_array_size(nullptr, constants, !is_constant, nullptr, &array_size, &unknown_size); @@ -8287,22 +8291,22 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (name == StringName()) { if (is_constant) { - _set_error("Expected identifier or '[' after datatype."); + _set_error(RTR("Expected an identifier or '[' after type.")); } else { - _set_error("Expected function name after datatype."); + _set_error(RTR("Expected a function name after type.")); } return ERR_PARSE_ERROR; } if (shader->structs.has(name) || _find_identifier(nullptr, false, constants, name) || has_builtin(p_functions, name)) { - _set_error("Redefinition of '" + String(name) + "'"); + _set_redefinition_error(String(name)); return ERR_PARSE_ERROR; } tk = _get_token(); if (tk.type != TK_PARENTHESIS_OPEN) { if (type == TYPE_VOID) { - _set_error("Expected '(' after function identifier"); + _set_error(RTR("Expected '(' after function identifier.")); return ERR_PARSE_ERROR; } @@ -8318,7 +8322,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_BRACKET_OPEN) { if (RenderingServer::get_singleton()->is_low_end()) { - _set_error("Global const arrays are only supported on high-end platform!"); + _set_error(RTR("Global const arrays are only supported on high-end platforms.")); return ERR_PARSE_ERROR; } Error error = _parse_array_size(nullptr, constants, false, nullptr, &constant.array_size, &unknown_size); @@ -8330,14 +8334,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_OP_ASSIGN) { if (!is_constant) { - _set_error("Expected 'const' keyword before constant definition"); + _set_error(vformat(RTR("Global non-constant variables are not supported. Expected '%s' keyword before constant definition."), "const")); return ERR_PARSE_ERROR; } if (constant.array_size > 0 || unknown_size) { bool full_def = false; - ArrayDeclarationNode::Declaration decl; + VariableDeclarationNode::Declaration decl; decl.name = name; decl.size = constant.array_size; @@ -8345,7 +8349,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type != TK_CURLY_BRACKET_OPEN) { if (unknown_size) { - _set_error("Expected '{'"); + _set_expected_error("{"); return ERR_PARSE_ERROR; } @@ -8356,7 +8360,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct precision2 = get_token_precision(tk.type); tk = _get_token(); if (!is_token_nonvoid_datatype(tk.type)) { - _set_error("Expected datatype after precision"); + _set_error(RTR("Expected data type after precision modifier.")); return ERR_PARSE_ERROR; } } @@ -8369,7 +8373,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct struct_name2 = tk.text; } else { if (!is_token_variable_datatype(tk.type)) { - _set_error("Invalid data type for array"); + _set_error(RTR("Invalid data type for the array.")); return ERR_PARSE_ERROR; } type2 = get_token_datatype(tk.type); @@ -8389,38 +8393,40 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } tk = _get_token(); } else { - _set_error("Expected '["); + _set_expected_error("["); return ERR_PARSE_ERROR; } if (constant.precision != precision2 || constant.type != type2 || struct_name != struct_name2 || constant.array_size != array_size2) { - String error_str = "Cannot convert from '"; + String from; if (type2 == TYPE_STRUCT) { - error_str += struct_name2; + from += struct_name2; } else { if (precision2 != PRECISION_DEFAULT) { - error_str += get_precision_name(precision2); - error_str += " "; + from += get_precision_name(precision2); + from += " "; } - error_str += get_datatype_name(type2); + from += get_datatype_name(type2); } - error_str += "["; - error_str += itos(array_size2); - error_str += "]'"; - error_str += " to '"; + from += "["; + from += itos(array_size2); + from += "]'"; + + String to; if (type == TYPE_STRUCT) { - error_str += struct_name; + to += struct_name; } else { if (precision != PRECISION_DEFAULT) { - error_str += get_precision_name(precision); - error_str += " "; + to += get_precision_name(precision); + to += " "; } - error_str += get_datatype_name(type); + to += get_datatype_name(type); } - error_str += "["; - error_str += itos(constant.array_size); - error_str += "]'"; - _set_error(error_str); + to += "["; + to += itos(constant.array_size); + to += "]'"; + + _set_error(vformat(RTR("Cannot convert from '%s' to '%s'."), from, to)); return ERR_PARSE_ERROR; } } @@ -8429,13 +8435,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (unknown_size) { if (!curly) { - _set_error("Expected '{'"); + _set_expected_error("{"); return ERR_PARSE_ERROR; } } else { if (full_def) { if (curly) { - _set_error("Expected '('"); + _set_expected_error("("); return ERR_PARSE_ERROR; } } @@ -8449,7 +8455,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { - _set_error("Expected constant expression"); + _set_error(RTR("Expected constant expression.")); return ERR_PARSE_ERROR; } @@ -8469,9 +8475,9 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct break; } else { if (curly) { - _set_error("Expected '}' or ','"); + _set_expected_error("}", ","); } else { - _set_error("Expected ')' or ','"); + _set_expected_error(")", ","); } return ERR_PARSE_ERROR; } @@ -8480,7 +8486,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct decl.size = decl.initializer.size(); constant.array_size = decl.initializer.size(); } else if (decl.initializer.size() != constant.array_size) { - _set_error("Array size mismatch"); + _set_error(RTR("Array size mismatch.")); return ERR_PARSE_ERROR; } } @@ -8508,7 +8514,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct OperatorNode *op = ((OperatorNode *)expr); for (int i = 1; i < op->arguments.size(); i++) { if (!_check_node_constness(op->arguments[i])) { - _set_error("Expected constant expression for argument '" + itos(i - 1) + "' of function call after '='"); + _set_error(vformat(RTR("Expected constant expression for argument %d of function call after '='."), i - 1)); return ERR_PARSE_ERROR; } } @@ -8523,10 +8529,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } else { if (constant.array_size > 0 || unknown_size) { - _set_error("Expected array initialization"); + _set_error(RTR("Expected array initialization.")); return ERR_PARSE_ERROR; } else { - _set_error("Expected initialization of constant"); + _set_error(RTR("Expected initialization of constant.")); return ERR_PARSE_ERROR; } } @@ -8542,18 +8548,18 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_COMMA) { tk = _get_token(); if (tk.type != TK_IDENTIFIER) { - _set_error("Expected identifier after type"); + _set_error(RTR("Expected an identifier after type.")); return ERR_PARSE_ERROR; } name = tk.text; if (_find_identifier(nullptr, false, constants, name)) { - _set_error("Redefinition of '" + String(name) + "'"); + _set_redefinition_error(String(name)); return ERR_PARSE_ERROR; } if (has_builtin(p_functions, name)) { - _set_error("Redefinition of '" + String(name) + "'"); + _set_redefinition_error(String(name)); return ERR_PARSE_ERROR; } @@ -8567,7 +8573,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } else if (tk.type == TK_SEMICOLON) { break; } else { - _set_error("Expected ',' or ';' after constant"); + _set_expected_error(",", ";"); return ERR_PARSE_ERROR; } } @@ -8594,7 +8600,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct for (int i = 0; i < shader->functions.size(); i++) { if (!shader->functions[i].callable && shader->functions[i].name == name) { - _set_error("Redefinition of '" + String(name) + "'"); + _set_redefinition_error(String(name)); return ERR_PARSE_ERROR; } } @@ -8649,14 +8655,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } else if (tk.type == TK_ARG_OUT) { if (is_const) { - _set_error("'out' qualifier cannot be used within a function parameter declared with 'const'."); + _set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "out", "const")); return ERR_PARSE_ERROR; } qualifier = ARGUMENT_QUALIFIER_OUT; tk = _get_token(); } else if (tk.type == TK_ARG_INOUT) { if (is_const) { - _set_error("'inout' qualifier cannot be used within a function parameter declared with 'const'."); + _set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "inout", "const")); return ERR_PARSE_ERROR; } qualifier = ARGUMENT_QUALIFIER_INOUT; @@ -8687,19 +8693,19 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } #endif // DEBUG_ENABLED if (use_precision) { - _set_error("Precision modifier cannot be used on structs."); + _set_error(RTR("The precision modifier cannot be used on structs.")); return ERR_PARSE_ERROR; } } if (!is_struct && !is_token_datatype(tk.type)) { - _set_error("Expected a valid datatype for argument"); + _set_error(RTR("Expected a valid data type for argument.")); return ERR_PARSE_ERROR; } if (qualifier == ARGUMENT_QUALIFIER_OUT || qualifier == ARGUMENT_QUALIFIER_INOUT) { if (is_sampler_type(get_token_datatype(tk.type))) { - _set_error("Opaque types cannot be output parameters."); + _set_error(RTR("Opaque types cannot be output parameters.")); return ERR_PARSE_ERROR; } } @@ -8712,7 +8718,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } if (ptype == TYPE_VOID) { - _set_error("void not allowed in argument"); + _set_error(RTR("Void type not allowed as argument.")); return ERR_PARSE_ERROR; } } @@ -8727,7 +8733,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } if (tk.type != TK_IDENTIFIER) { - _set_error("Expected identifier for argument name"); + _set_error(RTR("Expected an identifier for argument name.")); return ERR_PARSE_ERROR; } @@ -8736,13 +8742,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct ShaderLanguage::IdentifierType itype; if (_find_identifier(func_node->body, false, builtins, pname, (ShaderLanguage::DataType *)nullptr, &itype)) { if (itype != IDENTIFIER_FUNCTION) { - _set_error("Redefinition of '" + String(pname) + "'"); + _set_redefinition_error(String(pname)); return ERR_PARSE_ERROR; } } if (has_builtin(p_functions, pname)) { - _set_error("Redefinition of '" + String(pname) + "'"); + _set_redefinition_error(String(pname)); return ERR_PARSE_ERROR; } @@ -8774,7 +8780,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); //do none and go on } else if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_error("Expected ',' or ')' after identifier"); + _set_expected_error(",", ")"); return ERR_PARSE_ERROR; } } @@ -8782,11 +8788,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (p_functions.has(name)) { //if one of the core functions, make sure they are of the correct form if (func_node->arguments.size() > 0) { - _set_error("Function '" + String(name) + "' expects no arguments."); + _set_error(vformat(RTR("Function '%s' expects no arguments."), String(name))); return ERR_PARSE_ERROR; } if (func_node->return_type != TYPE_VOID) { - _set_error("Function '" + String(name) + "' must be of void return type."); + _set_error(vformat(RTR("Function '%s' must be of '%s' return type."), String(name), "void")); return ERR_PARSE_ERROR; } } @@ -8794,7 +8800,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct //all good let's parse inside the function! tk = _get_token(); if (tk.type != TK_CURLY_BRACKET_OPEN) { - _set_error("Expected '{' to begin function"); + _set_error(RTR("Expected a '{' to begin function.")); return ERR_PARSE_ERROR; } @@ -8808,7 +8814,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (func_node->return_type != DataType::TYPE_VOID) { BlockNode *block = func_node->body; if (_find_last_flow_op_in_block(block, FlowOperation::FLOW_OP_RETURN) != OK) { - _set_error("Expected at least one return statement in a non-void function."); + _set_error(vformat(RTR("Expected at least one '%s' statement in a non-void function."), "return")); return ERR_PARSE_ERROR; } } @@ -8821,7 +8827,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct #ifdef DEBUG_ENABLED if (check_device_limit_warnings && uniform_buffer_exceeded_line != -1) { - _add_warning(ShaderWarning::DEVICE_LIMIT_EXCEEDED, uniform_buffer_exceeded_line, "uniform buffer", { uniform_buffer_size, max_uniform_buffer_size }); + _add_warning(ShaderWarning::DEVICE_LIMIT_EXCEEDED, uniform_buffer_exceeded_line, RTR("uniform buffer"), { uniform_buffer_size, max_uniform_buffer_size }); } #endif // DEBUG_ENABLED return OK; @@ -9095,6 +9101,19 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ } break; case COMPLETION_MAIN_FUNCTION: { for (const KeyValue<StringName, FunctionInfo> &E : p_info.functions) { + if (!E.value.main_function) { + continue; + } + bool found = false; + for (int i = 0; i < shader->functions.size(); i++) { + if (shader->functions[i].name == E.key) { + found = true; + break; + } + } + if (found) { + continue; + } ScriptCodeCompletionOption option(E.key, ScriptCodeCompletionOption::KIND_FUNCTION); r_options->push_back(option); } diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 74f97319fe..f39b21621d 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -362,7 +362,6 @@ public: TYPE_CONTROL_FLOW, TYPE_MEMBER, TYPE_ARRAY, - TYPE_ARRAY_DECLARATION, TYPE_ARRAY_CONSTRUCT, TYPE_STRUCT, }; @@ -428,7 +427,10 @@ public: struct Declaration { StringName name; - Node *initializer; + uint32_t size = 0U; + Node *size_expression = nullptr; + Vector<Node *> initializer; + bool single_expression = false; }; Vector<Declaration> declarations; @@ -471,27 +473,6 @@ public: Node(TYPE_ARRAY_CONSTRUCT) {} }; - struct ArrayDeclarationNode : public Node { - DataPrecision precision = PRECISION_DEFAULT; - DataType datatype = TYPE_VOID; - String struct_name; - bool is_const = false; - Node *size_expression = nullptr; - - struct Declaration { - StringName name; - uint32_t size; - Vector<Node *> initializer; - bool single_expression; - }; - Vector<Declaration> declarations; - - virtual DataType get_datatype() const override { return datatype; } - - ArrayDeclarationNode() : - Node(TYPE_ARRAY_DECLARATION) {} - }; - struct ConstantNode : public Node { DataType datatype = TYPE_VOID; String struct_name = ""; @@ -505,7 +486,7 @@ public: }; Vector<Value> values; - Vector<ArrayDeclarationNode::Declaration> array_declarations; + Vector<VariableDeclarationNode::Declaration> array_declarations; virtual DataType get_datatype() const override { return datatype; } virtual String get_datatype_name() const override { return struct_name; } @@ -523,7 +504,9 @@ public: enum BlockType { BLOCK_TYPE_STANDART, - BLOCK_TYPE_FOR, + BLOCK_TYPE_FOR_INIT, + BLOCK_TYPE_FOR_CONDITION, + BLOCK_TYPE_FOR_EXPRESSION, BLOCK_TYPE_SWITCH, BLOCK_TYPE_CASE, BLOCK_TYPE_DEFAULT, @@ -545,6 +528,7 @@ public: Map<StringName, Variable> variables; List<Node *> statements; bool single_statement = false; + bool use_comma_between_statements = false; BlockNode() : Node(TYPE_BLOCK) {} @@ -964,6 +948,26 @@ private: error_str = p_str; } + void _set_expected_error(const String &p_what) { + _set_error(vformat(RTR("Expected a '%s'."), p_what)); + } + + void _set_expected_error(const String &p_first, const String p_second) { + _set_error(vformat(RTR("Expected a '%s' or '%s'."), p_first, p_second)); + } + + void _set_expected_after_error(const String &p_what, const String &p_after) { + _set_error(vformat(RTR("Expected a '%s' after '%s'."), p_what, p_after)); + } + + void _set_redefinition_error(const String &p_what) { + _set_error(vformat(RTR("Redefinition of '%s'."), p_what)); + } + + void _set_parsing_error() { + _set_error("Parser bug."); + } + static const char *token_names[TK_MAX]; Token _make_token(TokenType p_type, const StringName &p_text = StringName()); diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index 9ae60c14cb..b8bb211a7a 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -435,7 +435,6 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["OBJECT_POSITION"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["UVW"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["EXTENTS"] = constt(ShaderLanguage::TYPE_VEC3); - shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["SDF"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["ALBEDO"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["DENSITY"] = ShaderLanguage::TYPE_FLOAT; diff --git a/servers/rendering/shader_warnings.cpp b/servers/rendering/shader_warnings.cpp index f2e74c4d78..639b9bd165 100644 --- a/servers/rendering/shader_warnings.cpp +++ b/servers/rendering/shader_warnings.cpp @@ -48,23 +48,23 @@ const StringName &ShaderWarning::get_subject() const { String ShaderWarning::get_message() const { switch (code) { case FLOAT_COMPARISON: - return vformat("Direct floating-point comparison (this may not evaluate to `true` as you expect). Instead, use `abs(a - b) < 0.0001` for an approximate but predictable comparison."); + return vformat(RTR("Direct floating-point comparison (this may not evaluate to `true` as you expect). Instead, use `abs(a - b) < 0.0001` for an approximate but predictable comparison.")); case UNUSED_CONSTANT: - return vformat("The const '%s' is declared but never used.", subject); + return vformat(RTR("The const '%s' is declared but never used."), subject); case UNUSED_FUNCTION: - return vformat("The function '%s' is declared but never used.", subject); + return vformat(RTR("The function '%s' is declared but never used."), subject); case UNUSED_STRUCT: - return vformat("The struct '%s' is declared but never used.", subject); + return vformat(RTR("The struct '%s' is declared but never used."), subject); case UNUSED_UNIFORM: - return vformat("The uniform '%s' is declared but never used.", subject); + return vformat(RTR("The uniform '%s' is declared but never used."), subject); case UNUSED_VARYING: - return vformat("The varying '%s' is declared but never used.", subject); + return vformat(RTR("The varying '%s' is declared but never used."), subject); case UNUSED_LOCAL_VARIABLE: - return vformat("The local variable '%s' is declared but never used.", subject); + return vformat(RTR("The local variable '%s' is declared but never used."), subject); case FORMATTING_ERROR: return subject; case DEVICE_LIMIT_EXCEEDED: - return vformat("The total size of the %s for this shader on this device has been exceeded (%s/%s). The shader may not work correctly.", subject, (int)extra_args[0], (int)extra_args[1]); + return vformat(RTR("The total size of the %s for this shader on this device has been exceeded (%d/%d). The shader may not work correctly."), subject, (int)extra_args[0], (int)extra_args[1]); default: break; } diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 020c850f46..584abbc351 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -1927,8 +1927,8 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(LIGHT_PARAM_MAX); BIND_ENUM_CONSTANT(LIGHT_BAKE_DISABLED); - BIND_ENUM_CONSTANT(LIGHT_BAKE_DYNAMIC); BIND_ENUM_CONSTANT(LIGHT_BAKE_STATIC); + BIND_ENUM_CONSTANT(LIGHT_BAKE_DYNAMIC); BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_DUAL_PARABOLOID); BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_CUBE); @@ -2317,7 +2317,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_bg_energy", "env", "energy"), &RenderingServer::environment_set_bg_energy); ClassDB::bind_method(D_METHOD("environment_set_canvas_max_layer", "env", "max_layer"), &RenderingServer::environment_set_canvas_max_layer); ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source"), &RenderingServer::environment_set_ambient_light, DEFVAL(RS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(RS::ENV_REFLECTION_SOURCE_BG)); - ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "levels", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap"), &RenderingServer::environment_set_glow); + ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "levels", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap", "glow_map_strength", "glow_map"), &RenderingServer::environment_set_glow); ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &RenderingServer::environment_set_tonemap); ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "use_1d_color_correction", "color_correction"), &RenderingServer::environment_set_adjustment); ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance"), &RenderingServer::environment_set_ssr); @@ -2388,10 +2388,6 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ENV_SSIL_QUALITY_HIGH); BIND_ENUM_CONSTANT(ENV_SSIL_QUALITY_ULTRA); - BIND_ENUM_CONSTANT(ENV_SDFGI_CASCADES_4); - BIND_ENUM_CONSTANT(ENV_SDFGI_CASCADES_6); - BIND_ENUM_CONSTANT(ENV_SDFGI_CASCADES_8); - BIND_ENUM_CONSTANT(ENV_SDFGI_Y_SCALE_DISABLED); BIND_ENUM_CONSTANT(ENV_SDFGI_Y_SCALE_75_PERCENT); BIND_ENUM_CONSTANT(ENV_SDFGI_Y_SCALE_50_PERCENT); @@ -2775,13 +2771,14 @@ void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry const Geometry3D::MeshData::Face &f = p_mesh_data.faces[i]; for (int j = 2; j < f.indices.size(); j++) { -#define _ADD_VERTEX(m_idx) \ - vertices.push_back(p_mesh_data.vertices[f.indices[m_idx]]); \ - normals.push_back(f.plane.normal); + vertices.push_back(p_mesh_data.vertices[f.indices[0]]); + normals.push_back(f.plane.normal); + + vertices.push_back(p_mesh_data.vertices[f.indices[j - 1]]); + normals.push_back(f.plane.normal); - _ADD_VERTEX(0); - _ADD_VERTEX(j - 1); - _ADD_VERTEX(j); + vertices.push_back(p_mesh_data.vertices[f.indices[j]]); + normals.push_back(f.plane.normal); } } diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 5dbec04665..472fff1bf1 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -447,8 +447,8 @@ public: enum LightBakeMode { LIGHT_BAKE_DISABLED, - LIGHT_BAKE_DYNAMIC, LIGHT_BAKE_STATIC, + LIGHT_BAKE_DYNAMIC, }; virtual void light_set_bake_mode(RID p_light, LightBakeMode p_bake_mode) = 0; @@ -991,7 +991,7 @@ public: ENV_GLOW_BLEND_MODE_MIX, }; - virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) = 0; virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; @@ -1041,19 +1041,13 @@ public: virtual void environment_set_ssil_quality(EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; - enum EnvironmentSDFGICascades { - ENV_SDFGI_CASCADES_4, - ENV_SDFGI_CASCADES_6, - ENV_SDFGI_CASCADES_8, - }; - enum EnvironmentSDFGIYScale { ENV_SDFGI_Y_SCALE_DISABLED, ENV_SDFGI_Y_SCALE_75_PERCENT, ENV_SDFGI_Y_SCALE_50_PERCENT }; - virtual void environment_set_sdfgi(RID p_env, bool p_enable, EnvironmentSDFGICascades p_cascades, float p_min_cell_size, EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; + virtual void environment_set_sdfgi(RID p_env, bool p_enable, int p_cascades, float p_min_cell_size, EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; enum EnvironmentSDFGIRayCount { ENV_SDFGI_RAY_COUNT_4, @@ -1608,7 +1602,6 @@ VARIANT_ENUM_CAST(RenderingServer::EnvironmentToneMapper); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSRRoughnessQuality); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSAOQuality); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSILQuality); -VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGICascades); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGIFramesToConverge); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGIRayCount); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGIFramesToUpdateLight); diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index a2195d1ddf..3c5faa4ef7 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -210,10 +210,14 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_shaped_text_set_preserve_control, "shaped", "enabled"); GDVIRTUAL_BIND(_shaped_text_get_preserve_control, "shaped"); - GDVIRTUAL_BIND(_shaped_text_add_string, "shaped", "text", "fonts", "size", "opentype_features", "language"); + GDVIRTUAL_BIND(_shaped_text_add_string, "shaped", "text", "fonts", "size", "opentype_features", "language", "meta"); GDVIRTUAL_BIND(_shaped_text_add_object, "shaped", "key", "size", "inline_align", "length"); GDVIRTUAL_BIND(_shaped_text_resize_object, "shaped", "key", "size", "inline_align"); + GDVIRTUAL_BIND(_shaped_get_span_count, "shaped"); + GDVIRTUAL_BIND(_shaped_get_span_meta, "shaped", "index"); + GDVIRTUAL_BIND(_shaped_set_span_update_font, "shaped", "index", "fonts", "size", "opentype_features"); + GDVIRTUAL_BIND(_shaped_text_substr, "shaped", "start", "length"); GDVIRTUAL_BIND(_shaped_text_get_parent, "shaped"); @@ -226,8 +230,8 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_shaped_text_is_ready, "shaped"); - GDVIRTUAL_BIND(_shaped_text_get_glyphs, "shaped", "r_glyphs"); - GDVIRTUAL_BIND(_shaped_text_sort_logical, "shaped", "r_glyphs"); + GDVIRTUAL_BIND(_shaped_text_get_glyphs, "shaped"); + GDVIRTUAL_BIND(_shaped_text_sort_logical, "shaped"); GDVIRTUAL_BIND(_shaped_text_get_glyph_count, "shaped"); GDVIRTUAL_BIND(_shaped_text_get_range, "shaped"); @@ -239,7 +243,7 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_shaped_text_get_trim_pos, "shaped"); GDVIRTUAL_BIND(_shaped_text_get_ellipsis_pos, "shaped"); GDVIRTUAL_BIND(_shaped_text_get_ellipsis_glyph_count, "shaped"); - GDVIRTUAL_BIND(_shaped_text_get_ellipsis_glyphs, "shaped", "r_glyphs"); + GDVIRTUAL_BIND(_shaped_text_get_ellipsis_glyphs, "shaped"); GDVIRTUAL_BIND(_shaped_text_overrun_trim_to_width, "shaped", "width", "trim_flags"); @@ -271,6 +275,9 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_format_number, "string", "language"); GDVIRTUAL_BIND(_parse_number, "string", "language"); GDVIRTUAL_BIND(_percent_sign, "language"); + + GDVIRTUAL_BIND(_string_to_upper, "string", "language"); + GDVIRTUAL_BIND(_string_to_lower, "string", "language"); } bool TextServerExtension::has_feature(Feature p_feature) const { @@ -498,7 +505,7 @@ void TextServerExtension::font_set_hinting(RID p_font_rid, TextServer::Hinting p } TextServer::Hinting TextServerExtension::font_get_hinting(RID p_font_rid) const { - int ret; + TextServer::Hinting ret; if (GDVIRTUAL_CALL(_font_get_hinting, p_font_rid, ret)) { return (TextServer::Hinting)ret; } @@ -948,7 +955,7 @@ void TextServerExtension::shaped_text_set_direction(RID p_shaped, TextServer::Di } TextServer::Direction TextServerExtension::shaped_text_get_direction(RID p_shaped) const { - int ret; + TextServer::Direction ret; if (GDVIRTUAL_CALL(_shaped_text_get_direction, p_shaped, ret)) { return (TextServer::Direction)ret; } @@ -956,7 +963,7 @@ TextServer::Direction TextServerExtension::shaped_text_get_direction(RID p_shape } TextServer::Direction TextServerExtension::shaped_text_get_inferred_direction(RID p_shaped) const { - int ret; + TextServer::Direction ret; if (GDVIRTUAL_CALL(_shaped_text_get_inferred_direction, p_shaped, ret)) { return (TextServer::Direction)ret; } @@ -968,7 +975,7 @@ void TextServerExtension::shaped_text_set_orientation(RID p_shaped, TextServer:: } TextServer::Orientation TextServerExtension::shaped_text_get_orientation(RID p_shaped) const { - int ret; + TextServer::Orientation ret; if (GDVIRTUAL_CALL(_shaped_text_get_orientation, p_shaped, ret)) { return (TextServer::Orientation)ret; } @@ -1015,13 +1022,13 @@ bool TextServerExtension::shaped_text_get_preserve_control(RID p_shaped) const { return false; } -bool TextServerExtension::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { +bool TextServerExtension::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { bool ret; Array fonts; for (int i = 0; i < p_fonts.size(); i++) { fonts.push_back(p_fonts[i]); } - if (GDVIRTUAL_CALL(_shaped_text_add_string, p_shaped, p_text, fonts, p_size, p_opentype_features, p_language, ret)) { + if (GDVIRTUAL_CALL(_shaped_text_add_string, p_shaped, p_text, fonts, p_size, p_opentype_features, p_language, p_meta, ret)) { return ret; } return false; @@ -1043,6 +1050,30 @@ bool TextServerExtension::shaped_text_resize_object(RID p_shaped, Variant p_key, return false; } +int TextServerExtension::shaped_get_span_count(RID p_shaped) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_get_span_count, p_shaped, ret)) { + return ret; + } + return 0; +} + +Variant TextServerExtension::shaped_get_span_meta(RID p_shaped, int p_index) const { + Variant ret; + if (GDVIRTUAL_CALL(_shaped_get_span_meta, p_shaped, p_index, ret)) { + return ret; + } + return false; +} + +void TextServerExtension::shaped_set_span_update_font(RID p_shaped, int p_index, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features) { + Array fonts; + for (int i = 0; i < p_fonts.size(); i++) { + fonts.push_back(p_fonts[i]); + } + GDVIRTUAL_CALL(_shaped_set_span_update_font, p_shaped, p_index, fonts, p_size, p_opentype_features); +} + RID TextServerExtension::shaped_text_substr(RID p_shaped, int p_start, int p_length) const { RID ret; if (GDVIRTUAL_CALL(_shaped_text_substr, p_shaped, p_start, p_length, ret)) { @@ -1108,16 +1139,16 @@ bool TextServerExtension::shaped_text_is_ready(RID p_shaped) const { } const Glyph *TextServerExtension::shaped_text_get_glyphs(RID p_shaped) const { - const Glyph *ret; - if (GDVIRTUAL_CALL(_shaped_text_get_glyphs, p_shaped, &ret)) { + GDNativePtr<Glyph> ret; + if (GDVIRTUAL_CALL(_shaped_text_get_glyphs, p_shaped, ret)) { return ret; } return nullptr; } const Glyph *TextServerExtension::shaped_text_sort_logical(RID p_shaped) { - const Glyph *ret; - if (GDVIRTUAL_CALL(_shaped_text_sort_logical, p_shaped, &ret)) { + GDNativePtr<Glyph> ret; + if (GDVIRTUAL_CALL(_shaped_text_sort_logical, p_shaped, ret)) { return ret; } return nullptr; @@ -1180,8 +1211,8 @@ int TextServerExtension::shaped_text_get_ellipsis_pos(RID p_shaped) const { } const Glyph *TextServerExtension::shaped_text_get_ellipsis_glyphs(RID p_shaped) const { - const Glyph *ret; - if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, &ret)) { + GDNativePtr<Glyph> ret; + if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, ret)) { return ret; } return nullptr; @@ -1365,6 +1396,22 @@ String TextServerExtension::percent_sign(const String &p_language) const { return TextServer::percent_sign(p_language); } +String TextServerExtension::string_to_upper(const String &p_string, const String &p_language) const { + String ret; + if (GDVIRTUAL_CALL(_string_to_upper, p_string, p_language, ret)) { + return ret; + } + return p_string; +} + +String TextServerExtension::string_to_lower(const String &p_string, const String &p_language) const { + String ret; + if (GDVIRTUAL_CALL(_string_to_lower, p_string, p_language, ret)) { + return ret; + } + return p_string; +} + TextServerExtension::TextServerExtension() { //NOP } diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index 77f2ced951..9e7f666be1 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -132,7 +132,7 @@ public: virtual void font_set_hinting(RID p_font_rid, Hinting p_hinting) override; virtual Hinting font_get_hinting(RID p_font_rid) const override; GDVIRTUAL2(_font_set_hinting, RID, Hinting); - GDVIRTUAL1RC(/*Hinting*/ int, _font_get_hinting, RID); + GDVIRTUAL1RC(Hinting, _font_get_hinting, RID); virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override; virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override; @@ -317,8 +317,8 @@ public: virtual Direction shaped_text_get_direction(RID p_shaped) const override; virtual Direction shaped_text_get_inferred_direction(RID p_shaped) const override; GDVIRTUAL2(_shaped_text_set_direction, RID, Direction); - GDVIRTUAL1RC(/*Direction*/ int, _shaped_text_get_direction, RID); - GDVIRTUAL1RC(/*Direction*/ int, _shaped_text_get_inferred_direction, RID); + GDVIRTUAL1RC(Direction, _shaped_text_get_direction, RID); + GDVIRTUAL1RC(Direction, _shaped_text_get_inferred_direction, RID); virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; GDVIRTUAL2(_shaped_text_set_bidi_override, RID, const Array &); @@ -331,7 +331,7 @@ public: virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; virtual Orientation shaped_text_get_orientation(RID p_shaped) const override; GDVIRTUAL2(_shaped_text_set_orientation, RID, Orientation); - GDVIRTUAL1RC(/*Orientation*/ int, _shaped_text_get_orientation, RID); + GDVIRTUAL1RC(Orientation, _shaped_text_get_orientation, RID); virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) override; virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const override; @@ -343,13 +343,20 @@ public: GDVIRTUAL2(_shaped_text_set_preserve_control, RID, bool); GDVIRTUAL1RC(bool, _shaped_text_get_preserve_control, RID); - virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override; + virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override; virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1) override; virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override; - GDVIRTUAL6R(bool, _shaped_text_add_string, RID, const String &, const Array &, int, const Dictionary &, const String &); + GDVIRTUAL7R(bool, _shaped_text_add_string, RID, const String &, const Array &, int, const Dictionary &, const String &, const Variant &); GDVIRTUAL5R(bool, _shaped_text_add_object, RID, Variant, const Size2 &, InlineAlignment, int); GDVIRTUAL4R(bool, _shaped_text_resize_object, RID, Variant, const Size2 &, InlineAlignment); + virtual int shaped_get_span_count(RID p_shaped) const override; + virtual Variant shaped_get_span_meta(RID p_shaped, int p_index) const override; + virtual void shaped_set_span_update_font(RID p_shaped, int p_index, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary()) override; + GDVIRTUAL1RC(int, _shaped_get_span_count, RID); + GDVIRTUAL2RC(Variant, _shaped_get_span_meta, RID, int); + GDVIRTUAL5(_shaped_set_span_update_font, RID, int, const Array &, int, const Dictionary &); + virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override; virtual RID shaped_text_get_parent(RID p_shaped) const override; GDVIRTUAL3RC(RID, _shaped_text_substr, RID, int, int); @@ -373,8 +380,8 @@ public: virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override; virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override; virtual int shaped_text_get_glyph_count(RID p_shaped) const override; - GDVIRTUAL2C(_shaped_text_get_glyphs, RID, GDNativePtr<const Glyph *>); - GDVIRTUAL2(_shaped_text_sort_logical, RID, GDNativePtr<const Glyph *>); + GDVIRTUAL1RC(GDNativePtr<Glyph>, _shaped_text_get_glyphs, RID); + GDVIRTUAL1R(GDNativePtr<Glyph>, _shaped_text_sort_logical, RID); GDVIRTUAL1RC(int, _shaped_text_get_glyph_count, RID); virtual Vector2i shaped_text_get_range(RID p_shaped) const override; @@ -393,7 +400,7 @@ public: virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override; GDVIRTUAL1RC(int, _shaped_text_get_trim_pos, RID); GDVIRTUAL1RC(int, _shaped_text_get_ellipsis_pos, RID); - GDVIRTUAL2C(_shaped_text_get_ellipsis_glyphs, RID, GDNativePtr<const Glyph *>); + GDVIRTUAL1RC(GDNativePtr<Glyph>, _shaped_text_get_ellipsis_glyphs, RID); GDVIRTUAL1RC(int, _shaped_text_get_ellipsis_glyph_count, RID); virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override; @@ -449,6 +456,11 @@ public: GDVIRTUAL2RC(String, _parse_number, const String &, const String &); GDVIRTUAL1RC(String, _percent_sign, const String &); + virtual String string_to_upper(const String &p_string, const String &p_language = "") const override; + virtual String string_to_lower(const String &p_string, const String &p_language = "") const override; + GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &); + GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &); + TextServerExtension(); ~TextServerExtension(); }; diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 0cc4358785..b7cd39b9b2 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -363,10 +363,14 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shaped_text_set_preserve_control", "shaped", "enabled"), &TextServer::shaped_text_set_preserve_control); ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_control", "shaped"), &TextServer::shaped_text_get_preserve_control); - ClassDB::bind_method(D_METHOD("shaped_text_add_string", "shaped", "text", "fonts", "size", "opentype_features", "language"), &TextServer::shaped_text_add_string, DEFVAL(Dictionary()), DEFVAL("")); + ClassDB::bind_method(D_METHOD("shaped_text_add_string", "shaped", "text", "fonts", "size", "opentype_features", "language", "meta"), &TextServer::shaped_text_add_string, DEFVAL(Dictionary()), DEFVAL(""), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1)); ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER)); + ClassDB::bind_method(D_METHOD("shaped_get_span_count", "shaped"), &TextServer::shaped_get_span_count); + ClassDB::bind_method(D_METHOD("shaped_get_span_meta", "shaped", "index"), &TextServer::shaped_get_span_meta); + ClassDB::bind_method(D_METHOD("shaped_set_span_update_font", "shaped", "index", "fonts", "size", "opentype_features"), &TextServer::shaped_set_span_update_font, DEFVAL(Dictionary())); + ClassDB::bind_method(D_METHOD("shaped_text_substr", "shaped", "start", "length"), &TextServer::shaped_text_substr); ClassDB::bind_method(D_METHOD("shaped_text_get_parent", "shaped"), &TextServer::shaped_text_get_parent); ClassDB::bind_method(D_METHOD("shaped_text_fit_to_width", "shaped", "width", "jst_flags"), &TextServer::shaped_text_fit_to_width, DEFVAL(JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA)); @@ -422,6 +426,9 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("strip_diacritics", "string"), &TextServer::strip_diacritics); + ClassDB::bind_method(D_METHOD("string_to_upper", "string", "language"), &TextServer::string_to_upper, DEFVAL("")); + ClassDB::bind_method(D_METHOD("string_to_lower", "string", "language"), &TextServer::string_to_lower, DEFVAL("")); + /* Direction */ BIND_ENUM_CONSTANT(DIRECTION_AUTO); BIND_ENUM_CONSTANT(DIRECTION_LTR); @@ -480,6 +487,7 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_BREAK_ITERATORS); BIND_ENUM_CONSTANT(FEATURE_FONT_SYSTEM); BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE); + BIND_ENUM_CONSTANT(FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION); BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA); /* FT Contour Point Types */ diff --git a/servers/text_server.h b/servers/text_server.h index 07f0ae5045..629a633b9f 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -109,7 +109,8 @@ public: FEATURE_BREAK_ITERATORS = 1 << 4, FEATURE_FONT_SYSTEM = 1 << 5, FEATURE_FONT_VARIABLE = 1 << 6, - FEATURE_USE_SUPPORT_DATA = 1 << 7 + FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION = 1 << 7, + FEATURE_USE_SUPPORT_DATA = 1 << 8, }; enum ContourPointTag { @@ -154,20 +155,6 @@ protected: TextServer::Direction direction = DIRECTION_LTR; // Desired text direction. TextServer::Orientation orientation = ORIENTATION_HORIZONTAL; - struct Span { - int start = -1; - int end = -1; - - Vector<RID> fonts; - int font_size = 0; - - Variant embedded_key; - - String language; - Dictionary features; - }; - Vector<Span> spans; - struct EmbeddedObject { int pos = 0; InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER; @@ -386,10 +373,14 @@ public: virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) = 0; virtual bool shaped_text_get_preserve_control(RID p_shaped) const = 0; - virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") = 0; + virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) = 0; virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1) = 0; virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) = 0; + virtual int shaped_get_span_count(RID p_shaped) const = 0; + virtual Variant shaped_get_span_meta(RID p_shaped, int p_index) const = 0; + virtual void shaped_set_span_update_font(RID p_shaped, int p_index, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary()) = 0; + virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const = 0; // Copy shaped substring (e.g. line break) without reshaping, but correctly reordered, preservers range. virtual RID shaped_text_get_parent(RID p_shaped) const = 0; @@ -457,6 +448,10 @@ public: virtual String strip_diacritics(const String &p_string) const; + // Other string operations. + virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0; + virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0; + TextServer(); ~TextServer(); }; @@ -562,7 +557,6 @@ VARIANT_ENUM_CAST(TextServer::SpacingType); VARIANT_ENUM_CAST(TextServer::FontStyle); GDVIRTUAL_NATIVE_PTR(Glyph); -GDVIRTUAL_NATIVE_PTR(Glyph *); GDVIRTUAL_NATIVE_PTR(CaretInfo); #endif // TEXT_SERVER_H diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index 758f2416ec..7ae111b5e7 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -168,8 +168,5 @@ XRInterface::TrackingStatus XRInterface::get_tracking_status() const { return XR_UNKNOWN_TRACKING; } -void XRInterface::notification(int p_what) { -} - void XRInterface::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) { } diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index aee98f8fee..6e105ffc26 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -123,10 +123,13 @@ public: // note, external color/depth/vrs texture support will be added here soon. - virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* commit rendered views to the XR interface */ - virtual void process() = 0; - virtual void notification(int p_what); + virtual void pre_render(){}; + virtual bool pre_draw_viewport(RID p_render_target) { return true; }; /* inform XR interface we are about to start our viewport draw process */ + virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* inform XR interface we finished our viewport draw process */ + virtual void end_frame(){}; + + virtual void notification(int p_what){}; XRInterface(); ~XRInterface(); diff --git a/servers/xr/xr_interface_extension.cpp b/servers/xr/xr_interface_extension.cpp index 9dae3b162d..18131c1e89 100644 --- a/servers/xr/xr_interface_extension.cpp +++ b/servers/xr/xr_interface_extension.cpp @@ -52,9 +52,12 @@ void XRInterfaceExtension::_bind_methods() { GDVIRTUAL_BIND(_get_transform_for_view, "view", "cam_transform"); GDVIRTUAL_BIND(_get_projection_for_view, "view", "aspect", "z_near", "z_far"); - GDVIRTUAL_BIND(_commit_views, "render_target", "screen_rect"); - GDVIRTUAL_BIND(_process); + GDVIRTUAL_BIND(_pre_render); + GDVIRTUAL_BIND(_pre_draw_viewport, "render_target"); + GDVIRTUAL_BIND(_post_draw_viewport, "render_target", "screen_rect"); + GDVIRTUAL_BIND(_end_frame); + GDVIRTUAL_BIND(_notification, "what"); /** input and output **/ @@ -274,7 +277,7 @@ CameraMatrix XRInterfaceExtension::get_projection_for_view(uint32_t p_view, doub void XRInterfaceExtension::add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, double p_k1, double p_k2, double p_upscale, double p_aspect_ratio) { BlitToScreen blit; - ERR_FAIL_COND_MSG(!can_add_blits, "add_blit can only be called from an XR plugin from within _commit_views!"); + ERR_FAIL_COND_MSG(!can_add_blits, "add_blit can only be called from an XR plugin from within _post_draw_viewport!"); blit.render_target = p_render_target; blit.src_rect = p_src_rect; @@ -293,12 +296,31 @@ void XRInterfaceExtension::add_blit(RID p_render_target, Rect2 p_src_rect, Rect2 blits.push_back(blit); } -Vector<BlitToScreen> XRInterfaceExtension::commit_views(RID p_render_target, const Rect2 &p_screen_rect) { +void XRInterfaceExtension::process() { + GDVIRTUAL_CALL(_process); +} + +void XRInterfaceExtension::pre_render() { + GDVIRTUAL_CALL(_pre_render); +} + +bool XRInterfaceExtension::pre_draw_viewport(RID p_render_target) { + bool do_render = true; + + if (GDVIRTUAL_CALL(_pre_draw_viewport, p_render_target, do_render)) { + return do_render; + } else { + // if not implemented we're returning true + return true; + } +} + +Vector<BlitToScreen> XRInterfaceExtension::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) { // This is just so our XR plugin can add blits... blits.clear(); can_add_blits = true; - if (GDVIRTUAL_CALL(_commit_views, p_render_target, p_screen_rect)) { + if (GDVIRTUAL_CALL(_post_draw_viewport, p_render_target, p_screen_rect)) { return blits; } @@ -306,8 +328,8 @@ Vector<BlitToScreen> XRInterfaceExtension::commit_views(RID p_render_target, con return blits; } -void XRInterfaceExtension::process() { - GDVIRTUAL_CALL(_process); +void XRInterfaceExtension::end_frame() { + GDVIRTUAL_CALL(_end_frame); } void XRInterfaceExtension::notification(int p_what) { diff --git a/servers/xr/xr_interface_extension.h b/servers/xr/xr_interface_extension.h index e22ec2b872..5a436b9fd0 100644 --- a/servers/xr/xr_interface_extension.h +++ b/servers/xr/xr_interface_extension.h @@ -109,13 +109,20 @@ public: GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, double, double, double); void add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), double p_k1 = 0.0, double p_k2 = 0.0, double p_upscale = 1.0, double p_aspect_ratio = 1.0); - virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override; - GDVIRTUAL2(_commit_views, RID, const Rect2 &); virtual void process() override; + virtual void pre_render() override; + virtual bool pre_draw_viewport(RID p_render_target) override; + virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) override; + virtual void end_frame() override; virtual void notification(int p_what) override; GDVIRTUAL0(_process); + GDVIRTUAL0(_pre_render); + GDVIRTUAL1R(bool, _pre_draw_viewport, RID); + GDVIRTUAL2(_post_draw_viewport, RID, const Rect2 &); + GDVIRTUAL0(_end_frame); + GDVIRTUAL1(_notification, int); /* access to some internals we need */ diff --git a/servers/xr/xr_pose.cpp b/servers/xr/xr_pose.cpp index 0862fefef5..400f13b9c2 100644 --- a/servers/xr/xr_pose.cpp +++ b/servers/xr/xr_pose.cpp @@ -33,6 +33,10 @@ #include "servers/xr_server.h" void XRPose::_bind_methods() { + BIND_ENUM_CONSTANT(XR_TRACKING_CONFIDENCE_NONE); + BIND_ENUM_CONSTANT(XR_TRACKING_CONFIDENCE_LOW); + BIND_ENUM_CONSTANT(XR_TRACKING_CONFIDENCE_HIGH); + ClassDB::bind_method(D_METHOD("set_has_tracking_data", "has_tracking_data"), &XRPose::set_has_tracking_data); ClassDB::bind_method(D_METHOD("get_has_tracking_data"), &XRPose::get_has_tracking_data); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "has_tracking_data"), "set_has_tracking_data", "get_has_tracking_data"); @@ -53,6 +57,10 @@ void XRPose::_bind_methods() { ClassDB::bind_method(D_METHOD("set_angular_velocity", "velocity"), &XRPose::set_angular_velocity); ClassDB::bind_method(D_METHOD("get_angular_velocity"), &XRPose::get_angular_velocity); ADD_PROPERTY(PropertyInfo(Variant::STRING, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); + + ClassDB::bind_method(D_METHOD("set_tracking_confidence", "tracking_confidence"), &XRPose::set_tracking_confidence); + ClassDB::bind_method(D_METHOD("get_tracking_confidence"), &XRPose::get_tracking_confidence); + ADD_PROPERTY(PropertyInfo(Variant::INT, "tracking_confidence"), "set_tracking_confidence", "get_tracking_confidence"); } void XRPose::set_has_tracking_data(const bool p_has_tracking_data) { @@ -108,3 +116,11 @@ void XRPose::set_angular_velocity(const Vector3 p_velocity) { Vector3 XRPose::get_angular_velocity() const { return angular_velocity; } + +void XRPose::set_tracking_confidence(const XRPose::TrackingConfidence p_tracking_confidence) { + tracking_confidence = p_tracking_confidence; +} + +XRPose::TrackingConfidence XRPose::get_tracking_confidence() const { + return tracking_confidence; +} diff --git a/servers/xr/xr_pose.h b/servers/xr/xr_pose.h index 8c1fc63360..f306c22390 100644 --- a/servers/xr/xr_pose.h +++ b/servers/xr/xr_pose.h @@ -37,12 +37,20 @@ class XRPose : public RefCounted { GDCLASS(XRPose, RefCounted); public: + // TrackingConfidence gives an indication of how reliable our transform data is. + enum TrackingConfidence { + XR_TRACKING_CONFIDENCE_NONE, // No tracking information is available for this pose. + XR_TRACKING_CONFIDENCE_LOW, // Tracking information may be inaccurate or estimated. + XR_TRACKING_CONFIDENCE_HIGH // Tracking information is deemed accurate and up to date. + }; + private: bool has_tracking_data = false; StringName name; Transform3D transform; Vector3 linear_velocity; Vector3 angular_velocity; + TrackingConfidence tracking_confidence = XR_TRACKING_CONFIDENCE_NONE; protected: static void _bind_methods(); @@ -63,6 +71,11 @@ public: void set_angular_velocity(const Vector3 p_velocity); Vector3 get_angular_velocity() const; + + void set_tracking_confidence(const TrackingConfidence p_tracking_confidence); + TrackingConfidence get_tracking_confidence() const; }; +VARIANT_ENUM_CAST(XRPose::TrackingConfidence); + #endif diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp index 74907a5675..7b21eeba04 100644 --- a/servers/xr/xr_positional_tracker.cpp +++ b/servers/xr/xr_positional_tracker.cpp @@ -56,7 +56,7 @@ void XRPositionalTracker::_bind_methods() { ClassDB::bind_method(D_METHOD("has_pose", "name"), &XRPositionalTracker::has_pose); ClassDB::bind_method(D_METHOD("get_pose", "name"), &XRPositionalTracker::get_pose); ClassDB::bind_method(D_METHOD("invalidate_pose", "name"), &XRPositionalTracker::invalidate_pose); - ClassDB::bind_method(D_METHOD("set_pose", "name", "transform", "linear_velocity", "angular_velocity"), &XRPositionalTracker::set_pose); + ClassDB::bind_method(D_METHOD("set_pose", "name", "transform", "linear_velocity", "angular_velocity", "tracking_confidence"), &XRPositionalTracker::set_pose); ADD_SIGNAL(MethodInfo("pose_changed", PropertyInfo(Variant::OBJECT, "pose", PROPERTY_HINT_RESOURCE_TYPE, "XRPose"))); ClassDB::bind_method(D_METHOD("get_input", "name"), &XRPositionalTracker::get_input); @@ -137,7 +137,7 @@ void XRPositionalTracker::invalidate_pose(const StringName &p_action_name) { } } -void XRPositionalTracker::set_pose(const StringName &p_action_name, const Transform3D &p_transform, const Vector3 &p_linear_velocity, const Vector3 &p_angular_velocity) { +void XRPositionalTracker::set_pose(const StringName &p_action_name, const Transform3D &p_transform, const Vector3 &p_linear_velocity, const Vector3 &p_angular_velocity, const XRPose::TrackingConfidence p_tracking_confidence) { Ref<XRPose> new_pose; new_pose.instantiate(); @@ -146,9 +146,10 @@ void XRPositionalTracker::set_pose(const StringName &p_action_name, const Transf new_pose->set_transform(p_transform); new_pose->set_linear_velocity(p_linear_velocity); new_pose->set_angular_velocity(p_angular_velocity); + new_pose->set_tracking_confidence(p_tracking_confidence); poses[p_action_name] = new_pose; - emit_signal("pose_changed", new_pose); + emit_signal(SNAME("pose_changed"), new_pose); // TODO discuss whether we also want to create and emit an InputEventXRPose event } @@ -181,20 +182,20 @@ void XRPositionalTracker::set_input(const StringName &p_action_name, const Varia case Variant::BOOL: { bool pressed = p_value; if (pressed) { - emit_signal("button_pressed", p_action_name); + emit_signal(SNAME("button_pressed"), p_action_name); } else { - emit_signal("button_released", p_action_name); + emit_signal(SNAME("button_released"), p_action_name); } // TODO discuss whether we also want to create and emit an InputEventXRButton event } break; case Variant::FLOAT: { - emit_signal("input_value_changed", p_action_name, p_value); + emit_signal(SNAME("input_value_changed"), p_action_name, p_value); // TODO discuss whether we also want to create and emit an InputEventXRValue event } break; case Variant::VECTOR2: { - emit_signal("input_axis_changed", p_action_name, p_value); + emit_signal(SNAME("input_axis_changed"), p_action_name, p_value); // TODO discuss whether we also want to create and emit an InputEventXRAxis event } break; diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h index 2bcbf2c018..2f358cbb21 100644 --- a/servers/xr/xr_positional_tracker.h +++ b/servers/xr/xr_positional_tracker.h @@ -82,7 +82,7 @@ public: bool has_pose(const StringName &p_action_name) const; Ref<XRPose> get_pose(const StringName &p_action_name) const; void invalidate_pose(const StringName &p_action_name); - void set_pose(const StringName &p_action_name, const Transform3D &p_transform, const Vector3 &p_linear_velocity, const Vector3 &p_angular_velocity); + void set_pose(const StringName &p_action_name, const Transform3D &p_transform, const Vector3 &p_linear_velocity, const Vector3 &p_angular_velocity, const XRPose::TrackingConfidence p_tracking_confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH); Variant get_input(const StringName &p_action_name) const; void set_input(const StringName &p_action_name, const Variant &p_value); diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 69f4c69b53..dbfe76a127 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -65,10 +65,6 @@ void XRServer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "primary_interface"), "set_primary_interface", "get_primary_interface"); - ClassDB::bind_method(D_METHOD("get_last_process_usec"), &XRServer::get_last_process_usec); - ClassDB::bind_method(D_METHOD("get_last_commit_usec"), &XRServer::get_last_commit_usec); - ClassDB::bind_method(D_METHOD("get_last_frame_usec"), &XRServer::get_last_frame_usec); - BIND_ENUM_CONSTANT(TRACKER_HEAD); BIND_ENUM_CONSTANT(TRACKER_CONTROLLER); BIND_ENUM_CONSTANT(TRACKER_BASESTATION); @@ -351,24 +347,9 @@ PackedStringArray XRServer::get_suggested_pose_names(const StringName &p_tracker return arr; } -uint64_t XRServer::get_last_process_usec() { - return last_process_usec; -}; - -uint64_t XRServer::get_last_commit_usec() { - return last_commit_usec; -}; - -uint64_t XRServer::get_last_frame_usec() { - return last_frame_usec; -}; - void XRServer::_process() { /* called from renderer_viewport.draw_viewports right before we start drawing our viewports */ - /* mark for our frame timing */ - last_process_usec = OS::get_singleton()->get_ticks_usec(); - /* process all active interfaces */ for (int i = 0; i < interfaces.size(); i++) { if (!interfaces[i].is_valid()) { @@ -379,13 +360,32 @@ void XRServer::_process() { }; }; -void XRServer::_mark_commit() { - /* time this */ - last_commit_usec = OS::get_singleton()->get_ticks_usec(); +void XRServer::pre_render() { + // called from RendererViewport.draw_viewports right before we start drawing our viewports + // note that we can have multiple interfaces active if we have interfaces that purely handle tracking - /* now store our difference as we may overwrite last_process_usec before this is accessed */ - last_frame_usec = last_commit_usec - last_process_usec; -}; + // process all active interfaces + for (int i = 0; i < interfaces.size(); i++) { + if (!interfaces[i].is_valid()) { + // ignore, not a valid reference + } else if (interfaces[i]->is_initialized()) { + interfaces.write[i]->pre_render(); + }; + }; +} + +void XRServer::end_frame() { + // called from RenderingServerDefault after Vulkan queues have been submitted + + // process all active interfaces + for (int i = 0; i < interfaces.size(); i++) { + if (!interfaces[i].is_valid()) { + // ignore, not a valid reference + } else if (interfaces[i]->is_initialized()) { + interfaces.write[i]->end_frame(); + }; + }; +} XRServer::XRServer() { singleton = this; diff --git a/servers/xr_server.h b/servers/xr_server.h index a820634bd9..d9188d2de1 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -84,10 +84,6 @@ private: Transform3D world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */ Transform3D reference_frame; /* our reference frame */ - uint64_t last_process_usec; /* for frame timing, usec when we did our processing */ - uint64_t last_commit_usec; /* for frame timing, usec when we finished committing both eyes */ - uint64_t last_frame_usec; /* time it took between process and committing, we should probably average this over the last x frames */ - protected: static XRServer *singleton; @@ -175,12 +171,16 @@ public: PackedStringArray get_suggested_pose_names(const StringName &p_tracker_name) const; // Q: Should we add get_suggested_input_names and get_suggested_haptic_names even though we don't use them for the IDE? - uint64_t get_last_process_usec(); - uint64_t get_last_commit_usec(); - uint64_t get_last_frame_usec(); - + // Process is called before we handle our physics process and game process. This is where our interfaces will update controller data and such. void _process(); - void _mark_commit(); + + // Pre-render is called right before we're rendering our viewports. + // This is where interfaces such as OpenVR and OpenXR will update positioning data. + // Many of these interfaces will also do a predictive sync which ensures we run at a steady framerate. + void pre_render(); + + // End-frame is called right after Godot has finished its rendering bits. + void end_frame(); XRServer(); ~XRServer(); |