summaryrefslogtreecommitdiff
path: root/servers
diff options
context:
space:
mode:
Diffstat (limited to 'servers')
-rw-r--r--servers/register_server_types.cpp9
-rw-r--r--servers/rendering/rasterizer.h4
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp103
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp9
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.h5
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp12
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp96
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.h11
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp253
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.h12
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas.glsl7
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl33
-rw-r--r--servers/rendering/rasterizer_rd/shaders/tonemap.glsl24
-rw-r--r--servers/rendering/rendering_server_canvas.cpp161
-rw-r--r--servers/rendering/rendering_server_canvas.h2
-rw-r--r--servers/rendering/rendering_server_raster.h5
-rw-r--r--servers/rendering/rendering_server_scene.cpp6
-rw-r--r--servers/rendering/rendering_server_scene.h1
-rw-r--r--servers/rendering/rendering_server_wrap_mt.h5
-rw-r--r--servers/rendering/shader_types.cpp6
-rw-r--r--servers/rendering_server.cpp808
-rw-r--r--servers/rendering_server.h98
-rw-r--r--servers/text_server.cpp1246
-rw-r--r--servers/text_server.h453
24 files changed, 2654 insertions, 715 deletions
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index 34980aaf66..0ba9ce9e76 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -65,9 +65,9 @@
#include "rendering/rasterizer.h"
#include "rendering/rendering_device.h"
#include "rendering/rendering_device_binds.h"
-
#include "rendering_server.h"
#include "servers/rendering/shader_types.h"
+#include "text_server.h"
#include "xr/xr_interface.h"
#include "xr/xr_positional_tracker.h"
#include "xr_server.h"
@@ -102,6 +102,11 @@ void register_server_types() {
ClassDB::register_virtual_class<DisplayServer>();
ClassDB::register_virtual_class<RenderingServer>();
ClassDB::register_class<AudioServer>();
+
+ ClassDB::register_class<TextServerManager>();
+ ClassDB::register_virtual_class<TextServer>();
+ TextServer::initialize_hex_code_box_fonts();
+
ClassDB::register_virtual_class<PhysicsServer2D>();
ClassDB::register_virtual_class<PhysicsServer3D>();
ClassDB::register_virtual_class<NavigationServer2D>();
@@ -209,6 +214,7 @@ void register_server_types() {
void unregister_server_types() {
memdelete(shader_types);
+ TextServer::finish_hex_code_box_fonts();
}
void register_server_singletons() {
@@ -219,6 +225,7 @@ void register_server_singletons() {
Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton_mut()));
Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton_mut()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton()));
}
diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h
index 4df140f8c3..30577e6247 100644
--- a/servers/rendering/rasterizer.h
+++ b/servers/rendering/rasterizer.h
@@ -109,7 +109,7 @@ public:
virtual void environment_set_tonemap(RID p_env, 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) = 0;
- virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0;
+ virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) = 0;
virtual void environment_set_fog(RID p_env, 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_aerial_perspective) = 0;
@@ -522,6 +522,8 @@ public:
virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) = 0;
virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0;
virtual bool light_directional_get_blend_splits(RID p_light) const = 0;
+ virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0;
+ virtual bool light_directional_is_sky_only(RID p_light) const = 0;
virtual void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) = 0;
virtual RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const = 0;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
index 921a7b966e..f5360cbd36 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
@@ -119,9 +119,9 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
Vector<uint8_t> polygon_buffer;
polygon_buffer.resize(buffer_size * sizeof(float));
Vector<RD::VertexAttribute> descriptions;
- descriptions.resize(4);
+ descriptions.resize(5);
Vector<RID> buffers;
- buffers.resize(4);
+ buffers.resize(5);
{
const uint8_t *r = polygon_buffer.ptr();
@@ -218,7 +218,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
//bones
if ((uint32_t)p_indices.size() == vertex_count * 4 && (uint32_t)p_weights.size() == vertex_count * 4) {
RD::VertexAttribute vd;
- vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ vd.format = RD::DATA_FORMAT_R16G16B16A16_UINT;
vd.offset = base_offset * sizeof(float);
vd.location = RS::ARRAY_BONES;
vd.stride = stride * sizeof(float);
@@ -226,16 +226,42 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
descriptions.write[3] = vd;
const int *bone_ptr = p_bones.ptr();
- const float *weight_ptr = p_weights.ptr();
for (uint32_t i = 0; i < vertex_count; i++) {
uint16_t *bone16w = (uint16_t *)&uptr[base_offset + i * stride];
- uint16_t *weight16w = (uint16_t *)&uptr[base_offset + i * stride + 2];
bone16w[0] = bone_ptr[i * 4 + 0];
bone16w[1] = bone_ptr[i * 4 + 1];
bone16w[2] = bone_ptr[i * 4 + 2];
bone16w[3] = bone_ptr[i * 4 + 3];
+ }
+
+ base_offset += 2;
+ } else {
+ RD::VertexAttribute vd;
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ vd.offset = 0;
+ vd.location = RS::ARRAY_BONES;
+ vd.stride = 0;
+
+ descriptions.write[3] = vd;
+ buffers.write[3] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_BONES);
+ }
+
+ //weights
+ if ((uint32_t)p_weights.size() == vertex_count * 4) {
+ RD::VertexAttribute vd;
+ vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
+ vd.offset = base_offset * sizeof(float);
+ vd.location = RS::ARRAY_WEIGHTS;
+ vd.stride = stride * sizeof(float);
+
+ descriptions.write[4] = vd;
+
+ const float *weight_ptr = p_weights.ptr();
+
+ for (uint32_t i = 0; i < vertex_count; i++) {
+ uint16_t *weight16w = (uint16_t *)&uptr[base_offset + i * stride];
weight16w[0] = CLAMP(weight_ptr[i * 4 + 0] * 65535, 0, 65535);
weight16w[1] = CLAMP(weight_ptr[i * 4 + 1] * 65535, 0, 65535);
@@ -243,16 +269,16 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
weight16w[3] = CLAMP(weight_ptr[i * 4 + 3] * 65535, 0, 65535);
}
- base_offset += 4;
+ base_offset += 2;
} else {
RD::VertexAttribute vd;
- vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
vd.offset = 0;
- vd.location = RS::ARRAY_BONES;
+ vd.location = RS::ARRAY_WEIGHTS;
vd.stride = 0;
- descriptions.write[3] = vd;
- buffers.write[3] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_BONES);
+ descriptions.write[4] = vd;
+ buffers.write[4] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_BONES);
}
//check that everything is as it should be
@@ -1796,22 +1822,25 @@ void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector
ERR_FAIL_COND(!oc);
Vector<Vector2> lines;
- int lc = p_points.size() * 2;
- lines.resize(lc - (p_closed ? 0 : 2));
- {
- Vector2 *w = lines.ptrw();
- const Vector2 *r = p_points.ptr();
+ if (p_points.size()) {
+ int lc = p_points.size() * 2;
- int max = lc / 2;
- if (!p_closed) {
- max--;
- }
- for (int i = 0; i < max; i++) {
- Vector2 a = r[i];
- Vector2 b = r[(i + 1) % (lc / 2)];
- w[i * 2 + 0] = a;
- w[i * 2 + 1] = b;
+ lines.resize(lc - (p_closed ? 0 : 2));
+ {
+ Vector2 *w = lines.ptrw();
+ const Vector2 *r = p_points.ptr();
+
+ int max = lc / 2;
+ if (!p_closed) {
+ max--;
+ }
+ for (int i = 0; i < max; i++) {
+ Vector2 a = r[i];
+ Vector2 b = r[(i + 1) % (lc / 2)];
+ w[i * 2 + 0] = a;
+ w[i * 2 + 1] = b;
+ }
}
}
@@ -1832,7 +1861,7 @@ void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector
if (lines.size()) {
Vector<uint8_t> geometry;
Vector<uint8_t> indices;
- lc = lines.size();
+ int lc = lines.size();
geometry.resize(lc * 6 * sizeof(float));
indices.resize(lc * 3 * sizeof(uint16_t));
@@ -1902,19 +1931,21 @@ void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector
Vector<int> sdf_indices;
- if (p_closed) {
- sdf_indices = Geometry2D::triangulate_polygon(p_points);
- oc->sdf_is_lines = false;
- } else {
- int max = p_points.size();
- sdf_indices.resize(max * 2);
+ if (p_points.size()) {
+ if (p_closed) {
+ sdf_indices = Geometry2D::triangulate_polygon(p_points);
+ oc->sdf_is_lines = false;
+ } else {
+ int max = p_points.size();
+ sdf_indices.resize(max * 2);
- int *iw = sdf_indices.ptrw();
- for (int i = 0; i < max; i++) {
- iw[i * 2 + 0] = i;
- iw[i * 2 + 1] = (i + 1) % max;
+ int *iw = sdf_indices.ptrw();
+ for (int i = 0; i < max; i++) {
+ iw[i * 2 + 0] = i;
+ iw[i * 2 + 1] = (i + 1) % max;
+ }
+ oc->sdf_is_lines = true;
}
- oc->sdf_is_lines = true;
}
if (oc->sdf_index_count != sdf_indices.size() && oc->sdf_point_count != p_points.size() && oc->sdf_vertex_array.is_valid()) {
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
index 97c1e7ba70..df94921652 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
@@ -94,7 +94,7 @@ RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use
u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler);
u.ids.push_back(p_texture);
uniforms.push_back(u);
- //any thing with the same configuration (one texture in binding 0 for set 0), is good
+ //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), 0);
texture_to_uniform_set_cache[p_texture] = uniform_set;
@@ -718,7 +718,10 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer,
tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y;
tonemap.push_constant.glow_mode = p_settings.glow_mode;
- TonemapMode mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL;
+ int mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL;
+ if (p_settings.use_1d_color_correction) {
+ mode += 2;
+ }
tonemap.push_constant.tonemapper = p_settings.tonemap_mode;
tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure;
@@ -1423,6 +1426,8 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
Vector<String> tonemap_modes;
tonemap_modes.push_back("\n");
tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n");
+ tonemap_modes.push_back("\n#define USE_1D_LUT\n");
+ tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
tonemap.shader.initialize(tonemap_modes);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
index a0bdd59fd2..0b8d3a8f27 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
@@ -167,6 +167,8 @@ class RasterizerEffectsRD {
enum TonemapMode {
TONEMAP_MODE_NORMAL,
TONEMAP_MODE_BICUBIC_GLOW_FILTER,
+ TONEMAP_MODE_1D_LUT,
+ TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT,
TONEMAP_MODE_MAX
};
@@ -198,7 +200,7 @@ class RasterizerEffectsRD {
/* tonemap actually writes to a framebuffer, which is
* better to do using the raster pipeline rather than
- * comptute, as that framebuffer might be in different formats
+ * compute, as that framebuffer might be in different formats
*/
struct Tonemap {
TonemapPushConstant push_constant;
@@ -654,6 +656,7 @@ public:
float saturation = 1.0;
bool use_color_correction = false;
+ bool use_1d_color_correction = false;
RID color_correction_texture;
bool use_fxaa = false;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
index 313188ba87..66561958fc 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
@@ -2795,6 +2795,12 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
actions.renames["FOG"] = "custom_fog";
actions.renames["RADIANCE"] = "custom_radiance";
actions.renames["IRRADIANCE"] = "custom_irradiance";
+ actions.renames["BONE_INDICES"] = "bone_attrib";
+ actions.renames["BONE_WEIGHTS"] = "weight_attrib";
+ actions.renames["CUSTOM0"] = "custom0_attrib";
+ actions.renames["CUSTOM1"] = "custom1_attrib";
+ actions.renames["CUSTOM2"] = "custom2_attrib";
+ actions.renames["CUSTOM3"] = "custom3_attrib";
//for light
actions.renames["VIEW"] = "view";
@@ -2817,6 +2823,12 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
actions.usage_defines["UV"] = "#define UV_USED\n";
actions.usage_defines["UV2"] = "#define UV2_USED\n";
+ actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
+ actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
+ actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
+ actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
+ actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
+ actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
actions.usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n";
actions.usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
index 12fcc6fbb9..d6f08370e0 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -1186,6 +1186,11 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm
LightInstance *li = light_instance_owner.getornull(p_directional_light_instances[j]);
ERR_CONTINUE(!li);
+
+ if (storage->light_directional_is_sky_only(li->light)) {
+ continue;
+ }
+
Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
dir.y *= rb->sdfgi->y_mult;
dir.normalize();
@@ -4392,6 +4397,11 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc
RID light = light_instance_get_base_light(light_instance);
l.type = storage->light_get_type(light);
+ if (l.type == RS::LIGHT_DIRECTIONAL && storage->light_directional_is_sky_only(light)) {
+ light_count--;
+ continue;
+ }
+
l.attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
l.energy = storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length();
@@ -5290,8 +5300,6 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu
//tonemap
RasterizerEffectsRD::TonemapSettings tonemap;
- tonemap.color_correction_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
-
if (can_use_effects && env && env->auto_exposure && rb->luminance.current.is_valid()) {
tonemap.use_auto_exposure = true;
tonemap.exposure_texture = rb->luminance.current;
@@ -5328,6 +5336,22 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu
tonemap.exposure = env->exposure;
}
+ tonemap.use_color_correction = false;
+ tonemap.use_1d_color_correction = false;
+ tonemap.color_correction_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+
+ if (can_use_effects && env) {
+ tonemap.use_bcs = env->adjustments_enabled;
+ tonemap.brightness = env->adjustments_brightness;
+ tonemap.contrast = env->adjustments_contrast;
+ tonemap.saturation = env->adjustments_saturation;
+ if (env->adjustments_enabled && env->color_correction.is_valid()) {
+ tonemap.use_color_correction = true;
+ tonemap.use_1d_color_correction = env->use_1d_color_correction;
+ tonemap.color_correction_texture = storage->texture_get_rd_texture(env->color_correction);
+ }
+ }
+
storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap);
}
@@ -5395,6 +5419,18 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s
}
}
+void RasterizerSceneRD::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->adjustments_enabled = p_enable;
+ env->adjustments_brightness = p_brightness;
+ env->adjustments_contrast = p_contrast;
+ env->adjustments_saturation = p_saturation;
+ env->use_1d_color_correction = p_use_1d_color_correction;
+ env->color_correction = p_color_correction;
+}
+
void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
@@ -5931,7 +5967,40 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
RS::LightType type = storage->light_get_type(base);
switch (type) {
case RS::LIGHT_DIRECTIONAL: {
- if (r_directional_light_count >= cluster.max_directional_lights) {
+ // Copy to SkyDirectionalLightData
+ if (r_directional_light_count < sky_scene_state.max_directional_lights) {
+ SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count];
+ Transform light_transform = light_instance_get_base_transform(li);
+ Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
+
+ sky_light_data.direction[0] = world_direction.x;
+ sky_light_data.direction[1] = world_direction.y;
+ sky_light_data.direction[2] = -world_direction.z;
+
+ float sign = storage->light_is_negative(base) ? -1 : 1;
+ sky_light_data.energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
+
+ Color linear_col = storage->light_get_color(base).to_linear();
+ sky_light_data.color[0] = linear_col.r;
+ sky_light_data.color[1] = linear_col.g;
+ sky_light_data.color[2] = linear_col.b;
+
+ sky_light_data.enabled = true;
+
+ float angular_diameter = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+ if (angular_diameter > 0.0) {
+ // I know tan(0) is 0, but let's not risk it with numerical precision.
+ // technically this will keep expanding until reaching the sun, but all we care
+ // is expand until we reach the radius of the near plane (there can't be more occluders than that)
+ angular_diameter = Math::tan(Math::deg2rad(angular_diameter));
+ } else {
+ angular_diameter = 0.0;
+ }
+ sky_light_data.size = angular_diameter;
+ sky_scene_state.ubo.directional_light_count++;
+ }
+
+ if (r_directional_light_count >= cluster.max_directional_lights || storage->light_directional_is_sky_only(base)) {
continue;
}
@@ -6074,27 +6143,6 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
}
}
- // Copy to SkyDirectionalLightData
- if (r_directional_light_count < sky_scene_state.max_directional_lights) {
- SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count];
-
- Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
-
- sky_light_data.direction[0] = world_direction.x;
- sky_light_data.direction[1] = world_direction.y;
- sky_light_data.direction[2] = -world_direction.z;
-
- sky_light_data.energy = light_data.energy / Math_PI;
-
- sky_light_data.color[0] = light_data.color[0];
- sky_light_data.color[1] = light_data.color[1];
- sky_light_data.color[2] = light_data.color[2];
-
- sky_light_data.enabled = true;
- sky_light_data.size = angular_diameter;
- sky_scene_state.ubo.directional_light_count++;
- }
-
r_directional_light_count++;
} break;
case RS::LIGHT_SPOT:
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
index 3d5310bb7e..6aa79208ea 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
@@ -763,6 +763,15 @@ private:
float sdfgi_normal_bias = 1.1;
float sdfgi_probe_bias = 1.1;
RS::EnvironmentSDFGIYScale sdfgi_y_scale = RS::ENV_SDFGI_Y_SCALE_DISABLED;
+
+ /// Adjustments
+
+ bool adjustments_enabled = false;
+ float adjustments_brightness = 1.0f;
+ float adjustments_contrast = 1.0f;
+ float adjustments_saturation = 1.0f;
+ bool use_1d_color_correction = false;
+ RID color_correction = RID();
};
RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
@@ -1571,7 +1580,7 @@ public:
RS::EnvironmentSSRRoughnessQuality environment_get_ssr_roughness_quality() const;
void environment_set_tonemap(RID p_env, 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 environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {}
+ void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction);
virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
index 444ef9c49a..819404b316 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -2398,13 +2398,15 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_
ERR_FAIL_COND(!mesh);
//ensure blend shape consistency
- ERR_FAIL_COND(mesh->blend_shape_count && p_surface.blend_shapes.size() != (int)mesh->blend_shape_count);
+ ERR_FAIL_COND(mesh->blend_shape_count && p_surface.blend_shape_count != mesh->blend_shape_count);
ERR_FAIL_COND(mesh->blend_shape_count && p_surface.bone_aabbs.size() != mesh->bone_aabbs.size());
#ifdef DEBUG_ENABLED
//do a validation, to catch errors first
{
uint32_t stride = 0;
+ uint32_t attrib_stride = 0;
+ uint32_t skin_stride = 0;
for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
if ((p_surface.format & (1 << i))) {
@@ -2418,59 +2420,54 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_
} break;
case RS::ARRAY_NORMAL: {
- if (p_surface.format & RS::ARRAY_COMPRESS_NORMAL) {
- stride += sizeof(int8_t) * 4;
- } else {
- stride += sizeof(float) * 4;
- }
+ stride += sizeof(int32_t);
} break;
case RS::ARRAY_TANGENT: {
- if (p_surface.format & RS::ARRAY_COMPRESS_TANGENT) {
- stride += sizeof(int8_t) * 4;
- } else {
- stride += sizeof(float) * 4;
- }
+ stride += sizeof(int32_t);
} break;
case RS::ARRAY_COLOR: {
- if (p_surface.format & RS::ARRAY_COMPRESS_COLOR) {
- stride += sizeof(int8_t) * 4;
- } else {
- stride += sizeof(float) * 4;
- }
-
+ attrib_stride += sizeof(int16_t) * 4;
} break;
case RS::ARRAY_TEX_UV: {
- if (p_surface.format & RS::ARRAY_COMPRESS_TEX_UV) {
- stride += sizeof(int16_t) * 2;
- } else {
- stride += sizeof(float) * 2;
- }
+ attrib_stride += sizeof(float) * 2;
} break;
case RS::ARRAY_TEX_UV2: {
- if (p_surface.format & RS::ARRAY_COMPRESS_TEX_UV2) {
- stride += sizeof(int16_t) * 2;
- } else {
- stride += sizeof(float) * 2;
- }
+ attrib_stride += sizeof(float) * 2;
} break;
- case RS::ARRAY_BONES: {
- //assumed weights too
-
- //unique format, internally 16 bits, exposed as single array for 32
-
- stride += sizeof(int32_t) * 4;
+ case RS::ARRAY_CUSTOM0:
+ case RS::ARRAY_CUSTOM1:
+ case RS::ARRAY_CUSTOM2:
+ case RS::ARRAY_CUSTOM3: {
+ int idx = i - RS::ARRAY_CUSTOM0;
+ uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT };
+ uint32_t fmt = (p_surface.format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK;
+ uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 };
+ attrib_stride += fmtsize[fmt];
} break;
+ case RS::ARRAY_WEIGHTS:
+ case RS::ARRAY_BONES: {
+ //uses a separate array
+ bool use_8 = p_surface.format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+ skin_stride += sizeof(int16_t) * (use_8 ? 8 : 4);
+ } break;
}
}
}
int expected_size = stride * p_surface.vertex_count;
- ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+ ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of vertex data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+ int expected_attrib_size = attrib_stride * p_surface.vertex_count;
+ ERR_FAIL_COND_MSG(expected_attrib_size != p_surface.attribute_data.size(), "Size of attribute data provided (" + itos(p_surface.attribute_data.size()) + ") does not match expected (" + itos(expected_attrib_size) + ")");
+
+ if ((p_surface.format & RS::ARRAY_FORMAT_WEIGHTS) && (p_surface.format & RS::ARRAY_FORMAT_BONES)) {
+ expected_size = skin_stride * p_surface.vertex_count;
+ ERR_FAIL_COND_MSG(expected_size != p_surface.skin_data.size(), "Size of skin data provided (" + itos(p_surface.skin_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+ }
}
#endif
@@ -2481,6 +2478,12 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_
s->primitive = p_surface.primitive;
s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data);
+ if (p_surface.attribute_data.size()) {
+ s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data);
+ }
+ if (p_surface.skin_data.size()) {
+ s->skin_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.skin_data.size(), p_surface.skin_data);
+ }
s->vertex_count = p_surface.vertex_count;
if (p_surface.index_count) {
@@ -2504,7 +2507,7 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_
s->aabb = p_surface.aabb;
s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
-
+#if 0
for (int i = 0; i < p_surface.blend_shapes.size(); i++) {
if (p_surface.blend_shapes[i].size() != p_surface.vertex_data.size()) {
memdelete(s);
@@ -2513,8 +2516,8 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_
RID vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.blend_shapes[i].size(), p_surface.blend_shapes[i]);
s->blend_shapes.push_back(vertex_buffer);
}
-
- mesh->blend_shape_count = p_surface.blend_shapes.size();
+#endif
+ mesh->blend_shape_count = p_surface.blend_shape_count;
if (mesh->surface_count == 0) {
mesh->bone_aabbs = p_surface.bone_aabbs;
@@ -2596,6 +2599,12 @@ RS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface)
RS::SurfaceData sd;
sd.format = s.format;
sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
+ if (s.attribute_buffer.is_valid()) {
+ sd.attribute_data = RD::get_singleton()->buffer_get_data(s.attribute_buffer);
+ }
+ if (s.skin_buffer.is_valid()) {
+ sd.skin_data = RD::get_singleton()->buffer_get_data(s.skin_buffer);
+ }
sd.vertex_count = s.vertex_count;
sd.index_count = s.index_count;
sd.primitive = s.primitive;
@@ -2613,9 +2622,8 @@ RS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface)
sd.bone_aabbs = s.bone_aabbs;
- for (int i = 0; i < s.blend_shapes.size(); i++) {
- Vector<uint8_t> bs = RD::get_singleton()->buffer_get_data(s.blend_shapes[i]);
- sd.blend_shapes.push_back(bs);
+ if (s.blend_shape_buffer.is_valid()) {
+ sd.blend_shape_data = RD::get_singleton()->buffer_get_data(s.blend_shape_buffer);
}
return sd;
@@ -2750,6 +2758,12 @@ void RasterizerStorageRD::mesh_clear(RID p_mesh) {
for (uint32_t i = 0; i < mesh->surface_count; i++) {
Mesh::Surface &s = *mesh->surfaces[i];
RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions
+ if (s.attribute_buffer.is_valid()) {
+ RD::get_singleton()->free(s.attribute_buffer);
+ }
+ if (s.skin_buffer.is_valid()) {
+ RD::get_singleton()->free(s.skin_buffer);
+ }
if (s.versions) {
memfree(s.versions); //reallocs, so free with memfree.
}
@@ -2765,12 +2779,8 @@ void RasterizerStorageRD::mesh_clear(RID p_mesh) {
memdelete_arr(s.lods);
}
- for (int32_t j = 0; j < s.blend_shapes.size(); j++) {
- RD::get_singleton()->free(s.blend_shapes[j]);
- }
-
- if (s.blend_shape_base_buffer.is_valid()) {
- RD::get_singleton()->free(s.blend_shape_base_buffer);
+ if (s.blend_shape_buffer.is_valid()) {
+ RD::get_singleton()->free(s.blend_shape_buffer);
}
memdelete(mesh->surfaces[i]);
@@ -2796,8 +2806,10 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su
Vector<RID> buffers;
uint32_t stride = 0;
+ uint32_t attribute_stride = 0;
+ uint32_t skin_stride = 0;
- for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
+ for (int i = 0; i < RS::ARRAY_INDEX; i++) {
RD::VertexAttribute vd;
RID buffer;
vd.location = i;
@@ -2805,6 +2817,7 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su
if (!(s->format & (1 << i))) {
// Not supplied by surface, use default value
buffer = mesh_default_rd_buffers[i];
+ vd.stride = 0;
switch (i) {
case RS::ARRAY_VERTEX: {
vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
@@ -2827,20 +2840,31 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su
case RS::ARRAY_TEX_UV2: {
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
} break;
+ case RS::ARRAY_CUSTOM0:
+ case RS::ARRAY_CUSTOM1:
+ case RS::ARRAY_CUSTOM2:
+ case RS::ARRAY_CUSTOM3: {
+ //assumed weights too
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ } break;
case RS::ARRAY_BONES: {
//assumed weights too
vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
} break;
+ case RS::ARRAY_WEIGHTS: {
+ //assumed weights too
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ } break;
}
} else {
//Supplied, use it
- vd.offset = stride;
- vd.stride = 1; //mark that it needs a stride set
- buffer = s->vertex_buffer;
+ vd.stride = 1; //mark that it needs a stride set (default uses 0)
switch (i) {
case RS::ARRAY_VERTEX: {
+ vd.offset = stride;
+
if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
stride += sizeof(float) * 2;
@@ -2849,71 +2873,80 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su
stride += sizeof(float) * 3;
}
+ buffer = s->vertex_buffer;
+
} break;
case RS::ARRAY_NORMAL: {
- if (s->format & RS::ARRAY_COMPRESS_NORMAL) {
- vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM;
- stride += sizeof(int8_t) * 4;
- } else {
- vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- stride += sizeof(float) * 4;
- }
+ vd.offset = stride;
+ vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
+
+ stride += sizeof(uint32_t);
+ buffer = s->vertex_buffer;
} break;
case RS::ARRAY_TANGENT: {
- if (s->format & RS::ARRAY_COMPRESS_TANGENT) {
- vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM;
- stride += sizeof(int8_t) * 4;
- } else {
- vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- stride += sizeof(float) * 4;
- }
+ vd.offset = stride;
+ vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
+ stride += sizeof(uint32_t);
+ buffer = s->vertex_buffer;
} break;
case RS::ARRAY_COLOR: {
- if (s->format & RS::ARRAY_COMPRESS_COLOR) {
- vd.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- stride += sizeof(int8_t) * 4;
- } else {
- vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- stride += sizeof(float) * 4;
- }
+ vd.offset = attribute_stride;
+ vd.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ attribute_stride += sizeof(int16_t) * 4;
+ buffer = s->attribute_buffer;
} break;
case RS::ARRAY_TEX_UV: {
- if (s->format & RS::ARRAY_COMPRESS_TEX_UV) {
- vd.format = RD::DATA_FORMAT_R16G16_SFLOAT;
- stride += sizeof(int16_t) * 2;
- } else {
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- stride += sizeof(float) * 2;
- }
+ vd.offset = attribute_stride;
+
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ attribute_stride += sizeof(float) * 2;
+ buffer = s->attribute_buffer;
} break;
case RS::ARRAY_TEX_UV2: {
- if (s->format & RS::ARRAY_COMPRESS_TEX_UV2) {
- vd.format = RD::DATA_FORMAT_R16G16_SFLOAT;
- stride += sizeof(int16_t) * 2;
- } else {
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- stride += sizeof(float) * 2;
- }
+ vd.offset = attribute_stride;
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ attribute_stride += sizeof(float) * 2;
+ buffer = s->attribute_buffer;
+ } break;
+ case RS::ARRAY_CUSTOM0:
+ case RS::ARRAY_CUSTOM1:
+ case RS::ARRAY_CUSTOM2:
+ case RS::ARRAY_CUSTOM3: {
+ vd.offset = attribute_stride;
+
+ int idx = i - RS::ARRAY_CUSTOM0;
+ uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT };
+ uint32_t fmt = (s->format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK;
+ uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 };
+ RD::DataFormat fmtrd[RS::ARRAY_CUSTOM_MAX] = { RD::DATA_FORMAT_R8G8B8A8_UNORM, RD::DATA_FORMAT_R8G8B8A8_SNORM, RD::DATA_FORMAT_R16G16_SFLOAT, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, RD::DATA_FORMAT_R32_SFLOAT, RD::DATA_FORMAT_R32G32_SFLOAT, RD::DATA_FORMAT_R32G32B32_SFLOAT, RD::DATA_FORMAT_R32G32B32A32_SFLOAT };
+ vd.format = fmtrd[fmt];
+ attribute_stride += fmtsize[fmt];
+ buffer = s->attribute_buffer;
} break;
case RS::ARRAY_BONES: {
- //assumed weights too
-
- //unique format, internally 16 bits, exposed as single array for 32
+ vd.offset = skin_stride;
- vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
- stride += sizeof(int32_t) * 4;
+ vd.format = RD::DATA_FORMAT_R16G16B16A16_UINT;
+ skin_stride += sizeof(int16_t) * 4;
+ buffer = s->skin_buffer;
+ } break;
+ case RS::ARRAY_WEIGHTS: {
+ vd.offset = skin_stride;
+ vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
+ skin_stride += sizeof(int16_t) * 4;
+ buffer = s->skin_buffer;
} break;
}
}
if (!(p_input_mask & (1 << i))) {
- continue; // Shader does not need this, skip it
+ continue; // Shader does not need this, skip it (but computing stride was important anyway)
}
attributes.push_back(vd);
@@ -2922,8 +2955,17 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su
//update final stride
for (int i = 0; i < attributes.size(); i++) {
- if (attributes[i].stride == 1) {
+ if (attributes[i].stride == 0) {
+ continue; //default location
+ }
+ int loc = attributes[i].location;
+
+ if (loc < RS::ARRAY_COLOR) {
attributes.write[i].stride = stride;
+ } else if (loc < RS::ARRAY_BONES) {
+ attributes.write[i].stride = attribute_stride;
+ } else {
+ attributes.write[i].stride = skin_stride;
}
}
@@ -5120,6 +5162,20 @@ bool RasterizerStorageRD::light_directional_get_blend_splits(RID p_light) const
return light->directional_blend_splits;
}
+void RasterizerStorageRD::light_directional_set_sky_only(RID p_light, bool p_sky_only) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->directional_sky_only = p_sky_only;
+}
+
+bool RasterizerStorageRD::light_directional_is_sky_only(RID p_light) const {
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, false);
+
+ return light->directional_sky_only;
+}
+
RS::LightDirectionalShadowMode RasterizerStorageRD::light_directional_get_shadow_mode(RID p_light) {
const Light *light = light_owner.getornull(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
@@ -8249,6 +8305,19 @@ RasterizerStorageRD::RasterizerStorageRD() {
mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
}
+ for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+ buffer.resize(sizeof(float) * 4);
+ {
+ uint8_t *w = buffer.ptrw();
+ float *fptr = (float *)w;
+ fptr[0] = 0.0;
+ fptr[1] = 0.0;
+ fptr[2] = 0.0;
+ fptr[3] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_CUSTOM0 + i] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+ }
+
{ //bones
buffer.resize(sizeof(uint32_t) * 4);
{
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
index 4a708fc94f..d887f122c9 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
@@ -170,6 +170,10 @@ public:
DEFAULT_RD_BUFFER_COLOR,
DEFAULT_RD_BUFFER_TEX_UV,
DEFAULT_RD_BUFFER_TEX_UV2,
+ DEFAULT_RD_BUFFER_CUSTOM0,
+ DEFAULT_RD_BUFFER_CUSTOM1,
+ DEFAULT_RD_BUFFER_CUSTOM2,
+ DEFAULT_RD_BUFFER_CUSTOM3,
DEFAULT_RD_BUFFER_BONES,
DEFAULT_RD_BUFFER_WEIGHTS,
DEFAULT_RD_BUFFER_MAX,
@@ -378,6 +382,8 @@ private:
uint32_t format = 0;
RID vertex_buffer;
+ RID attribute_buffer;
+ RID skin_buffer;
uint32_t vertex_count = 0;
// A different pipeline needs to be allocated
@@ -414,8 +420,7 @@ private:
Vector<AABB> bone_aabbs;
- Vector<RID> blend_shapes;
- RID blend_shape_base_buffer; //source buffer goes here when using blend shapes, and main one is uncompressed
+ RID blend_shape_buffer;
RID material;
@@ -850,6 +855,7 @@ private:
RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
RS::LightDirectionalShadowDepthRangeMode directional_range_mode = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE;
bool directional_blend_splits = false;
+ bool directional_sky_only = false;
uint64_t version = 0;
RasterizerScene::InstanceDependency instance_dependency;
@@ -1537,6 +1543,8 @@ public:
void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode);
void light_directional_set_blend_splits(RID p_light, bool p_enable);
bool light_directional_get_blend_splits(RID p_light) const;
+ void light_directional_set_sky_only(RID p_light, bool p_sky_only);
+ bool light_directional_is_sky_only(RID p_light) const;
void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode);
RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const;
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/rasterizer_rd/shaders/canvas.glsl
index 51d7193a03..7808e7ed52 100644
--- a/servers/rendering/rasterizer_rd/shaders/canvas.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas.glsl
@@ -9,7 +9,8 @@ layout(location = 0) in vec2 vertex_attrib;
layout(location = 3) in vec4 color_attrib;
layout(location = 4) in vec2 uv_attrib;
-layout(location = 6) in uvec4 bones_attrib;
+layout(location = 10) in uvec4 bone_attrib;
+layout(location = 11) in vec4 weight_attrib;
#endif
@@ -61,6 +62,7 @@ void main() {
color = vec4(unpackHalf2x16(draw_data.colors[4]), unpackHalf2x16(draw_data.colors[5]));
}
uvec4 bones = uvec4(0, 0, 0, 0);
+ vec4 bone_weights = vec4(0.0);
#elif defined(USE_ATTRIBUTES)
@@ -68,7 +70,8 @@ void main() {
vec4 color = color_attrib;
vec2 uv = uv_attrib;
- uvec4 bones = bones_attrib;
+ uvec4 bones = bone_attrib;
+ vec4 bone_weights = weight_attrib;
#else
vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
index 285698f060..5d87dec79f 100644
--- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
@@ -24,7 +24,29 @@ layout(location = 4) in vec2 uv_attrib;
layout(location = 5) in vec2 uv2_attrib;
#endif
-layout(location = 6) in uvec4 bone_attrib; // always bound, even if unused
+#if defined(CUSTOM0_USED)
+layout(location = 6) in vec4 custom0_attrib;
+#endif
+
+#if defined(CUSTOM1_USED)
+layout(location = 7) in vec4 custom1_attrib;
+#endif
+
+#if defined(CUSTOM2_USED)
+layout(location = 8) in vec4 custom2_attrib;
+#endif
+
+#if defined(CUSTOM3_USED)
+layout(location = 9) in vec4 custom3_attrib;
+#endif
+
+#if defined(BONES_USED)
+layout(location = 10) in uvec4 bone_attrib;
+#endif
+
+#if defined(WEIGHTS_USED)
+layout(location = 11) in vec4 weight_attrib;
+#endif
/* Varyings */
@@ -116,14 +138,15 @@ void main() {
}
vec3 vertex = vertex_attrib;
- vec3 normal = normal_attrib;
+ vec3 normal = normal_attrib * 2.0 - 1.0;
#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
- vec3 tangent = tangent_attrib.xyz;
- float binormalf = tangent_attrib.a;
+ vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
+ float binormalf = tangent_attrib.a * 2.0 - 1.0;
vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
+#if 0
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_SKELETON)) {
//multimesh, instances are for it
@@ -147,7 +170,7 @@ void main() {
binormal = (vec4(binormal, 0.0) * m).xyz;
#endif
}
-
+#endif
uv_interp = uv_attrib;
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
diff --git a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl
index 4cc4fd3f64..7de91fd541 100644
--- a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl
@@ -23,7 +23,11 @@ layout(location = 0) in vec2 uv_interp;
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 = 3, binding = 0) uniform sampler3D color_correction;
+#ifdef USE_1D_LUT
+layout(set = 3, binding = 0) uniform sampler2D source_color_correction;
+#else
+layout(set = 3, binding = 0) uniform sampler3D source_color_correction;
+#endif
layout(push_constant, binding = 1, std430) uniform Params {
vec3 bcs;
@@ -35,9 +39,9 @@ layout(push_constant, binding = 1, std430) uniform Params {
uint tonemapper;
uvec2 glow_texture_size;
-
float glow_intensity;
uint pad3;
+
uint glow_mode;
float glow_levels[7];
@@ -255,10 +259,18 @@ vec3 apply_bcs(vec3 color, vec3 bcs) {
return color;
}
-
-vec3 apply_color_correction(vec3 color, sampler3D correction_tex) {
- return texture(correction_tex, color).rgb;
+#ifdef USE_1D_LUT
+vec3 apply_color_correction(vec3 color) {
+ color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r;
+ color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g;
+ color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b;
+ return color;
+}
+#else
+vec3 apply_color_correction(vec3 color) {
+ return textureLod(source_color_correction, color, 0.0).rgb;
}
+#endif
vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
const float FXAA_REDUCE_MIN = (1.0 / 128.0);
@@ -367,7 +379,7 @@ void main() {
}
if (params.use_color_correction) {
- color = apply_color_correction(color, color_correction);
+ color = apply_color_correction(color);
}
frag_color = vec4(color, 1.0f);
diff --git a/servers/rendering/rendering_server_canvas.cpp b/servers/rendering/rendering_server_canvas.cpp
index ffc1ec391d..0e61d53866 100644
--- a/servers/rendering/rendering_server_canvas.cpp
+++ b/servers/rendering/rendering_server_canvas.cpp
@@ -540,59 +540,64 @@ void RenderingServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_fro
}
}
-void RenderingServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
+void RenderingServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
ERR_FAIL_COND(p_points.size() < 2);
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
+ Color color = Color(1, 1, 1, 1);
+
+ Vector<int> indices;
+ int pc = p_points.size();
+ int pc2 = pc * 2;
+
+ Vector2 prev_t;
+ int j2;
+
Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
ERR_FAIL_COND(!pline);
- if (true || p_width <= 1) {
-#define TODO make thick lines possible
- Vector<int> indices;
- int pc = p_points.size();
- indices.resize((pc - 1) * 2);
- {
- int *iptr = indices.ptrw();
- for (int i = 0; i < (pc - 1); i++) {
- iptr[i * 2 + 0] = i;
- iptr[i * 2 + 1] = i + 1;
- }
- }
+ PackedColorArray colors;
+ PackedVector2Array points;
- pline->primitive = RS::PRIMITIVE_LINES;
- pline->polygon.create(indices, p_points, p_colors);
- } else {
-#if 0
- //make a trianglestrip for drawing the line...
- Vector2 prev_t;
- pline->triangles.resize(p_points.size() * 2);
- if (p_antialiased) {
- pline->lines.resize(p_points.size() * 2);
- }
+ colors.resize(pc2);
+ points.resize(pc2);
- if (p_colors.size() == 0) {
- pline->triangle_colors.push_back(Color(1, 1, 1, 1));
- if (p_antialiased) {
- pline->line_colors.push_back(Color(1, 1, 1, 1));
- }
- } else if (p_colors.size() == 1) {
- pline->triangle_colors = p_colors;
- pline->line_colors = p_colors;
- } else {
- if (p_colors.size() != p_points.size()) {
- pline->triangle_colors.push_back(p_colors[0]);
- pline->line_colors.push_back(p_colors[0]);
- } else {
- pline->triangle_colors.resize(pline->triangles.size());
- pline->line_colors.resize(pline->lines.size());
- }
- }
+ Vector2 *points_ptr = points.ptrw();
+ Color *colors_ptr = colors.ptrw();
+
+ if (p_antialiased) {
+ Color color2 = Color(1, 1, 1, 0);
+
+ PackedColorArray colors_top;
+ PackedVector2Array points_top;
+
+ colors_top.resize(pc2);
+ points_top.resize(pc2);
+
+ PackedColorArray colors_bottom;
+ PackedVector2Array points_bottom;
- for (int i = 0; i < p_points.size(); i++) {
+ colors_bottom.resize(pc2);
+ points_bottom.resize(pc2);
+
+ Item::CommandPolygon *pline_top = canvas_item->alloc_command<Item::CommandPolygon>();
+ ERR_FAIL_COND(!pline_top);
+
+ Item::CommandPolygon *pline_bottom = canvas_item->alloc_command<Item::CommandPolygon>();
+ ERR_FAIL_COND(!pline_bottom);
+
+ //make three trianglestrip's for drawing the antialiased line...
+
+ Vector2 *points_top_ptr = points_top.ptrw();
+ Vector2 *points_bottom_ptr = points_bottom.ptrw();
+
+ Color *colors_top_ptr = colors_top.ptrw();
+ Color *colors_bottom_ptr = colors_bottom.ptrw();
+
+ for (int i = 0, j = 0; i < pc; i++, j += 2) {
Vector2 t;
- if (i == p_points.size() - 1) {
+ if (i == pc - 1) {
t = prev_t;
} else {
t = (p_points[i + 1] - p_points[i]).normalized().tangent();
@@ -601,29 +606,77 @@ void RenderingServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Po
}
}
+ j2 = j + 1;
+
Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5;
+ Vector2 pos = p_points[i];
- if (p_antialiased) {
- pline->lines.write[i] = p_points[i] + tangent;
- pline->lines.write[p_points.size() * 2 - i - 1] = p_points[i] - tangent;
- if (pline->line_colors.size() > 1) {
- pline->line_colors.write[i] = p_colors[i];
- pline->line_colors.write[p_points.size() * 2 - i - 1] = p_colors[i];
+ points_ptr[j] = pos + tangent;
+ points_ptr[j2] = pos - tangent;
+
+ points_top_ptr[j] = pos + tangent + tangent;
+ points_top_ptr[j2] = pos + tangent;
+
+ points_bottom_ptr[j] = pos - tangent;
+ points_bottom_ptr[j2] = pos - tangent - tangent;
+
+ if (i < p_colors.size()) {
+ color = p_colors[i];
+ color2 = Color(color.r, color.g, color.b, 0);
+ }
+
+ colors_ptr[j] = color;
+ colors_ptr[j2] = color;
+
+ colors_top_ptr[j] = color2;
+ colors_top_ptr[j2] = color;
+
+ colors_bottom_ptr[j] = color;
+ colors_bottom_ptr[j2] = color2;
+
+ prev_t = t;
+ }
+
+ pline_top->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
+ pline_top->polygon.create(indices, points_top, colors_top);
+
+ pline_bottom->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
+ pline_bottom->polygon.create(indices, points_bottom, colors_bottom);
+ } else {
+ //make a trianglestrip for drawing the line...
+
+ for (int i = 0, j = 0; i < pc; i++, j += 2) {
+ Vector2 t;
+ if (i == pc - 1) {
+ t = prev_t;
+ } else {
+ t = (p_points[i + 1] - p_points[i]).normalized().tangent();
+ if (i == 0) {
+ prev_t = t;
}
}
- pline->triangles.write[i * 2 + 0] = p_points[i] + tangent;
- pline->triangles.write[i * 2 + 1] = p_points[i] - tangent;
+ j2 = j + 1;
- if (pline->triangle_colors.size() > 1) {
- pline->triangle_colors.write[i * 2 + 0] = p_colors[i];
- pline->triangle_colors.write[i * 2 + 1] = p_colors[i];
+ Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5;
+ Vector2 pos = p_points[i];
+
+ points_ptr[j] = pos + tangent;
+ points_ptr[j2] = pos - tangent;
+
+ if (i < p_colors.size()) {
+ color = p_colors[i];
}
+ colors_ptr[j] = color;
+ colors_ptr[j2] = color;
+
prev_t = t;
}
-#endif
}
+
+ pline->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
+ pline->polygon.create(indices, points, colors);
}
void RenderingServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
diff --git a/servers/rendering/rendering_server_canvas.h b/servers/rendering/rendering_server_canvas.h
index 83b76539c4..89f511a8fb 100644
--- a/servers/rendering/rendering_server_canvas.h
+++ b/servers/rendering/rendering_server_canvas.h
@@ -192,7 +192,7 @@ public:
void canvas_item_set_update_when_visible(RID p_item, bool p_update);
void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0);
- void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
+ void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color);
void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color);
diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h
index 413fcda581..76ceccb3c5 100644
--- a/servers/rendering/rendering_server_raster.h
+++ b/servers/rendering/rendering_server_raster.h
@@ -336,6 +336,7 @@ public:
BIND2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
BIND2(light_directional_set_blend_splits, RID, bool)
+ BIND2(light_directional_set_sky_only, RID, bool)
BIND2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode)
/* PROBE API */
@@ -593,7 +594,7 @@ public:
BIND9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
- BIND6(environment_set_adjustment, RID, bool, float, float, float, RID)
+ BIND7(environment_set_adjustment, RID, bool, float, float, float, bool, RID)
BIND9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
BIND9(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, EnvVolumetricFogShadowFilter)
@@ -717,7 +718,7 @@ public:
BIND2(canvas_item_set_draw_behind_parent, RID, bool)
BIND5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
- BIND4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float)
+ BIND5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
BIND4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float)
BIND3(canvas_item_add_rect, RID, const Rect2 &, const Color &)
BIND4(canvas_item_add_circle, RID, const Point2 &, float, const Color &)
diff --git a/servers/rendering/rendering_server_scene.cpp b/servers/rendering/rendering_server_scene.cpp
index ae6786090a..b933a550e2 100644
--- a/servers/rendering/rendering_server_scene.cpp
+++ b/servers/rendering/rendering_server_scene.cpp
@@ -2169,7 +2169,7 @@ void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const
//check shadow..
if (light) {
- if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base)) {
+ if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base) && !(RSG::storage->light_get_type(E->get()->base) == RS::LIGHT_DIRECTIONAL && RSG::storage->light_directional_is_sky_only(E->get()->base))) {
lights_with_shadow[directional_shadow_count++] = E->get();
}
//add to list
@@ -2595,7 +2595,8 @@ void RenderingServerScene::render_probes() {
cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) ||
cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) ||
cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) ||
- cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION)) {
+ cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION) ||
+ cache->sky_only != RSG::storage->light_directional_is_sky_only(instance->base)) {
cache_dirty = true;
}
}
@@ -2664,6 +2665,7 @@ void RenderingServerScene::render_probes() {
cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION);
cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE);
cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+ cache->sky_only = RSG::storage->light_directional_is_sky_only(instance->base);
idx++;
}
diff --git a/servers/rendering/rendering_server_scene.h b/servers/rendering/rendering_server_scene.h
index 646b2a666f..eb438be273 100644
--- a/servers/rendering/rendering_server_scene.h
+++ b/servers/rendering/rendering_server_scene.h
@@ -350,6 +350,7 @@ public:
float spot_angle;
float spot_attenuation;
bool has_shadow;
+ bool sky_only;
};
Vector<LightCache> light_cache;
diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h
index d33bdb043a..2c230aaee4 100644
--- a/servers/rendering/rendering_server_wrap_mt.h
+++ b/servers/rendering/rendering_server_wrap_mt.h
@@ -244,6 +244,7 @@ public:
FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
FUNC2(light_directional_set_blend_splits, RID, bool)
+ FUNC2(light_directional_set_sky_only, RID, bool)
FUNC2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode)
/* PROBE API */
@@ -506,7 +507,7 @@ public:
FUNC9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
- FUNC6(environment_set_adjustment, RID, bool, float, float, float, RID)
+ FUNC7(environment_set_adjustment, RID, bool, float, float, float, bool, RID)
FUNC9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
@@ -618,7 +619,7 @@ public:
FUNC2(canvas_item_set_draw_behind_parent, RID, bool)
FUNC5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
- FUNC4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float)
+ FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
FUNC4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float)
FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &)
FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &)
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index bd61f2a549..0c9b2ddf2f 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -67,6 +67,12 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_ID"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_INDICES"] = ShaderLanguage::TYPE_UVEC4;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_WEIGHTS"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM0"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM1"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM2"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM3"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].can_discard = false;
//builtins
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index ea37e0c143..599b9e09f2 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -315,8 +315,10 @@ RID RenderingServer::get_white_texture() {
#define SMALL_VEC2 Vector2(0.00001, 0.00001)
#define SMALL_VEC3 Vector3(0.00001, 0.00001, 0.00001)
-Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, Vector<uint8_t> &r_vertex_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) {
+Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) {
uint8_t *vw = r_vertex_array.ptrw();
+ uint8_t *aw = r_attrib_array.ptrw();
+ uint8_t *sw = r_skin_array.ptrw();
uint8_t *iw = nullptr;
if (r_index_array.size()) {
@@ -345,7 +347,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < p_vertex_array_len; i++) {
float vector[2] = { src[i].x, src[i].y };
- copymem(&vw[p_offsets[ai] + i * p_stride], vector, sizeof(float) * 2);
+ copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 2);
if (i == 0) {
aabb = Rect2(src[i], SMALL_VEC2); //must have a bit of size
@@ -370,7 +372,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < p_vertex_array_len; i++) {
float vector[3] = { src[i].x, src[i].y, src[i].z };
- copymem(&vw[p_offsets[ai] + i * p_stride], vector, sizeof(float) * 3);
+ copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3);
if (i == 0) {
aabb = AABB(src[i], SMALL_VEC3);
@@ -391,26 +393,15 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
const Vector3 *src = array.ptr();
+ for (int i = 0; i < p_vertex_array_len; i++) {
+ Vector3 n = src[i] * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
- // setting vertices means regenerating the AABB
+ uint32_t value = 0;
+ value |= CLAMP(int(n.x * 1023.0), 0, 1023);
+ value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
+ value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
- if (p_format & ARRAY_COMPRESS_NORMAL) {
- for (int i = 0; i < p_vertex_array_len; i++) {
- int8_t vector[4] = {
- (int8_t)CLAMP(src[i].x * 127, -128, 127),
- (int8_t)CLAMP(src[i].y * 127, -128, 127),
- (int8_t)CLAMP(src[i].z * 127, -128, 127),
- 0,
- };
-
- copymem(&vw[p_offsets[ai] + i * p_stride], vector, 4);
- }
-
- } else {
- for (int i = 0; i < p_vertex_array_len; i++) {
- float vector[3] = { src[i].x, src[i].y, src[i].z };
- copymem(&vw[p_offsets[ai] + i * p_stride], vector, 3 * 4);
- }
+ copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
}
} break;
@@ -424,29 +415,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const real_t *src = array.ptr();
- if (p_format & ARRAY_COMPRESS_TANGENT) {
- for (int i = 0; i < p_vertex_array_len; i++) {
- int8_t xyzw[4] = {
- (int8_t)CLAMP(src[i * 4 + 0] * 127, -128, 127),
- (int8_t)CLAMP(src[i * 4 + 1] * 127, -128, 127),
- (int8_t)CLAMP(src[i * 4 + 2] * 127, -128, 127),
- (int8_t)CLAMP(src[i * 4 + 3] * 127, -128, 127)
- };
-
- copymem(&vw[p_offsets[ai] + i * p_stride], xyzw, 4);
- }
+ for (int i = 0; i < p_vertex_array_len; i++) {
+ uint32_t value = 0;
+ value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023);
+ value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
+ value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
+ value |= CLAMP(int((src[i * 4 + 3] * 0.5 + 0.5) * 3.0), 0, 3) << 30;
- } else {
- for (int i = 0; i < p_vertex_array_len; i++) {
- float xyzw[4] = {
- src[i * 4 + 0],
- src[i * 4 + 1],
- src[i * 4 + 2],
- src[i * 4 + 3]
- };
-
- copymem(&vw[p_offsets[ai] + i * p_stride], xyzw, 4 * 4);
- }
+ copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
}
} break;
@@ -458,23 +434,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
const Color *src = array.ptr();
-
- if (p_format & ARRAY_COMPRESS_COLOR) {
- for (int i = 0; i < p_vertex_array_len; i++) {
- uint8_t colors[4];
-
- for (int j = 0; j < 4; j++) {
- colors[j] = CLAMP(int((src[i][j]) * 255.0), 0, 255);
- }
-
- copymem(&vw[p_offsets[ai] + i * p_stride], colors, 4);
- }
- } else {
- for (int i = 0; i < p_vertex_array_len; i++) {
- copymem(&vw[p_offsets[ai] + i * p_stride], &src[i], 4 * 4);
- }
+ uint16_t color16[4];
+ for (int i = 0; i < p_vertex_array_len; i++) {
+ color16[0] = Math::make_half_float(src[i].r);
+ color16[1] = Math::make_half_float(src[i].g);
+ color16[2] = Math::make_half_float(src[i].b);
+ color16[3] = Math::make_half_float(src[i].a);
+ copymem(&aw[p_offsets[ai] + i * p_attrib_stride], color16, 8);
}
-
} break;
case RS::ARRAY_TEX_UV: {
ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::PACKED_VECTOR2_ARRAY, ERR_INVALID_PARAMETER);
@@ -485,18 +452,10 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const Vector2 *src = array.ptr();
- if (p_format & ARRAY_COMPRESS_TEX_UV) {
- for (int i = 0; i < p_vertex_array_len; i++) {
- uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) };
- copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 2);
- }
-
- } else {
- for (int i = 0; i < p_vertex_array_len; i++) {
- float uv[2] = { src[i].x, src[i].y };
+ for (int i = 0; i < p_vertex_array_len; i++) {
+ float uv[2] = { src[i].x, src[i].y };
- copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 4);
- }
+ copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4);
}
} break;
@@ -510,37 +469,90 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const Vector2 *src = array.ptr();
- if (p_format & ARRAY_COMPRESS_TEX_UV2) {
- for (int i = 0; i < p_vertex_array_len; i++) {
- uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) };
- copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 2);
- }
+ for (int i = 0; i < p_vertex_array_len; i++) {
+ uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) };
+ copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 2);
+ }
+ } break;
+ case RS::ARRAY_CUSTOM0:
+ case RS::ARRAY_CUSTOM1:
+ case RS::ARRAY_CUSTOM2:
+ case RS::ARRAY_CUSTOM3: {
+ uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - ai))) & ARRAY_FORMAT_CUSTOM_MASK;
+ switch (type) {
+ case ARRAY_CUSTOM_RGBA8_UNORM:
+ case ARRAY_CUSTOM_RGBA8_SNORM:
+ case ARRAY_CUSTOM_RG_HALF: {
+ //size 4
+ ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_BYTE_ARRAY, ERR_INVALID_PARAMETER);
- } else {
- for (int i = 0; i < p_vertex_array_len; i++) {
- float uv[2] = { src[i].x, src[i].y };
+ Vector<uint8_t> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER);
+
+ const uint8_t *src = array.ptr();
+
+ for (int i = 0; i < p_vertex_array_len; i++) {
+ copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 4], 4);
+ }
+
+ } break;
+ case ARRAY_CUSTOM_RGBA_HALF: {
+ //size 8
+ ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_BYTE_ARRAY, ERR_INVALID_PARAMETER);
+
+ Vector<uint8_t> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 8, ERR_INVALID_PARAMETER);
+
+ const uint8_t *src = array.ptr();
- copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 4);
+ for (int i = 0; i < p_vertex_array_len; i++) {
+ copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 8], 8);
+ }
+ } break;
+ case ARRAY_CUSTOM_R_FLOAT:
+ case ARRAY_CUSTOM_RG_FLOAT:
+ case ARRAY_CUSTOM_RGB_FLOAT:
+ case ARRAY_CUSTOM_RGBA_FLOAT: {
+ //RF
+ ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER);
+
+ Vector<float> array = p_arrays[ai];
+ int32_t s = ARRAY_CUSTOM_R_FLOAT - ai + 1;
+
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len * s, ERR_INVALID_PARAMETER);
+
+ const float *src = array.ptr();
+
+ for (int i = 0; i < p_vertex_array_len; i++) {
+ copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s);
+ }
+ } break;
+ default: {
}
}
+
} break;
case RS::ARRAY_WEIGHTS: {
ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER);
+ uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4;
+
Vector<real_t> array = p_arrays[ai];
- ERR_FAIL_COND_V(array.size() != p_vertex_array_len * RS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(array.size() != (int32_t)(p_vertex_array_len * bone_count), ERR_INVALID_PARAMETER);
const real_t *src = array.ptr();
{
+ uint16_t data[8];
for (int i = 0; i < p_vertex_array_len; i++) {
- uint16_t data[RS::ARRAY_WEIGHTS_SIZE];
- for (int j = 0; j < RS::ARRAY_WEIGHTS_SIZE; j++) {
- data[j] = CLAMP(src[i * RS::ARRAY_WEIGHTS_SIZE + j] * 65535, 0, 65535);
+ for (uint32_t j = 0; j < bone_count; j++) {
+ data[j] = CLAMP(src[i * bone_count + j] * 65535, 0, 65535);
}
- copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4);
+ copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count);
}
}
@@ -550,21 +562,25 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
Vector<int> array = p_arrays[ai];
- ERR_FAIL_COND_V(array.size() != p_vertex_array_len * RS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER);
+ uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4;
+
+ ERR_FAIL_COND_V(array.size() != (int32_t)(p_vertex_array_len * bone_count), ERR_INVALID_PARAMETER);
const int *src = array.ptr();
+ uint16_t data[8];
+
for (int i = 0; i < p_vertex_array_len; i++) {
- uint16_t data[RS::ARRAY_WEIGHTS_SIZE];
- for (int j = 0; j < RS::ARRAY_WEIGHTS_SIZE; j++) {
- data[j] = src[i * RS::ARRAY_WEIGHTS_SIZE + j];
+ for (uint32_t j = 0; j < bone_count; j++) {
+ data[j] = src[i * bone_count + j];
max_bone = MAX(data[j], max_bone);
}
- copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4);
+ copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count);
}
} break;
+
case RS::ARRAY_INDEX: {
ERR_FAIL_NULL_V(iw, ERR_INVALID_DATA);
ERR_FAIL_COND_V(p_index_array_len <= 0, ERR_INVALID_DATA);
@@ -652,23 +668,62 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
return OK;
}
-uint32_t RenderingServer::mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const {
+uint32_t RenderingServer::mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_array_index) const {
+ p_format &= ~ARRAY_FORMAT_INDEX;
uint32_t offsets[ARRAY_MAX];
- mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets);
+ uint32_t vstr;
+ uint32_t astr;
+ uint32_t sstr;
+ mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr);
return offsets[p_array_index];
}
-uint32_t RenderingServer::mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const {
+uint32_t RenderingServer::mesh_surface_get_format_vertex_stride(uint32_t p_format, int p_vertex_len) const {
+ p_format &= ~ARRAY_FORMAT_INDEX;
uint32_t offsets[ARRAY_MAX];
- return mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets);
+ uint32_t vstr;
+ uint32_t astr;
+ uint32_t sstr;
+ mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr);
+ return vstr;
}
+uint32_t RenderingServer::mesh_surface_get_format_attribute_stride(uint32_t p_format, int p_vertex_len) const {
+ p_format &= ~ARRAY_FORMAT_INDEX;
+ uint32_t offsets[ARRAY_MAX];
+ uint32_t vstr;
+ uint32_t astr;
+ uint32_t sstr;
+ mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr);
+ return astr;
+}
+uint32_t RenderingServer::mesh_surface_get_format_skin_stride(uint32_t p_format, int p_vertex_len) const {
+ p_format &= ~ARRAY_FORMAT_INDEX;
+ uint32_t offsets[ARRAY_MAX];
+ uint32_t vstr;
+ uint32_t astr;
+ uint32_t sstr;
+ mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr);
+ return sstr;
+}
+
+void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const {
+ r_vertex_element_size = 0;
+ r_attrib_element_size = 0;
+ r_skin_element_size = 0;
-uint32_t RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const {
- int total_elem_size = 0;
+ uint32_t *size_accum;
for (int i = 0; i < RS::ARRAY_MAX; i++) {
r_offsets[i] = 0; //reset
+ if (i == RS::ARRAY_VERTEX) {
+ size_accum = &r_vertex_element_size;
+ } else if (i == RS::ARRAY_COLOR) {
+ size_accum = &r_attrib_element_size;
+ } else if (i == RS::ARRAY_BONES) {
+ size_accum = &r_skin_element_size;
+ }
+
if (!(p_format & (1 << i))) { // no array
continue;
}
@@ -693,53 +748,64 @@ uint32_t RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_forma
} break;
case RS::ARRAY_NORMAL: {
- if (p_format & ARRAY_COMPRESS_NORMAL) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 3;
- }
-
+ elem_size = 4;
} break;
case RS::ARRAY_TANGENT: {
- if (p_format & ARRAY_COMPRESS_TANGENT) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
-
+ elem_size = 4;
} break;
case RS::ARRAY_COLOR: {
- if (p_format & ARRAY_COMPRESS_COLOR) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
+ elem_size = 8;
} break;
case RS::ARRAY_TEX_UV: {
- if (p_format & ARRAY_COMPRESS_TEX_UV) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
+ elem_size = 8;
} break;
case RS::ARRAY_TEX_UV2: {
- if (p_format & ARRAY_COMPRESS_TEX_UV2) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
+ elem_size = 8;
} break;
+ case RS::ARRAY_CUSTOM0:
+ case RS::ARRAY_CUSTOM1:
+ case RS::ARRAY_CUSTOM2:
+ case RS::ARRAY_CUSTOM3: {
+ uint32_t format = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + (ARRAY_FORMAT_CUSTOM_BITS * (i - ARRAY_CUSTOM0)))) & ARRAY_FORMAT_CUSTOM_MASK;
+ switch (format) {
+ case ARRAY_CUSTOM_RGBA8_UNORM: {
+ elem_size = 4;
+ } break;
+ case ARRAY_CUSTOM_RGBA8_SNORM: {
+ elem_size = 4;
+ } break;
+ case ARRAY_CUSTOM_RG_HALF: {
+ elem_size = 4;
+ } break;
+ case ARRAY_CUSTOM_RGBA_HALF: {
+ elem_size = 8;
+ } break;
+ case ARRAY_CUSTOM_R_FLOAT: {
+ elem_size = 4;
+ } break;
+ case ARRAY_CUSTOM_RG_FLOAT: {
+ elem_size = 8;
+ } break;
+ case ARRAY_CUSTOM_RGB_FLOAT: {
+ elem_size = 12;
+ } break;
+ case ARRAY_CUSTOM_RGBA_FLOAT: {
+ elem_size = 16;
+ } break;
+ }
+ } break;
case RS::ARRAY_WEIGHTS: {
- elem_size = sizeof(uint16_t) * 4;
+ uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4;
+ elem_size = sizeof(uint16_t) * bone_count;
} break;
case RS::ARRAY_BONES: {
- elem_size = sizeof(uint16_t) * 4;
-
+ uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4;
+ elem_size = sizeof(uint16_t) * bone_count;
} break;
case RS::ARRAY_INDEX: {
if (p_index_len <= 0) {
@@ -757,14 +823,13 @@ uint32_t RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_forma
continue;
}
default: {
- ERR_FAIL_V(0);
+ ERR_FAIL();
}
}
- r_offsets[i] = total_elem_size;
- total_elem_size += elem_size;
+ r_offsets[i] = (*size_accum);
+ (*size_accum) += elem_size;
}
- return total_elem_size;
}
Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_compress_format) {
@@ -785,20 +850,20 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
format |= (1 << i);
if (i == RS::ARRAY_VERTEX) {
- Variant var = p_arrays[i];
- switch (var.get_type()) {
+ switch (p_arrays[i].get_type()) {
case Variant::PACKED_VECTOR2_ARRAY: {
- Vector<Vector2> v2 = var;
+ Vector<Vector2> v2 = p_arrays[i];
+ array_len = v2.size();
} break;
case Variant::PACKED_VECTOR3_ARRAY: {
- Vector<Vector3> v3 = var;
+ Vector<Vector3> v3 = p_arrays[i];
+ array_len = v3.size();
} break;
default: {
- Array v = var;
+ ERR_FAIL_V(ERR_INVALID_DATA);
} break;
}
- array_len = PackedVector3Array(p_arrays[i]).size();
ERR_FAIL_COND_V(array_len == 0, ERR_INVALID_DATA);
} else if (i == RS::ARRAY_INDEX) {
index_array_len = PackedInt32Array(p_arrays[i]).size();
@@ -824,117 +889,28 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
uint32_t offsets[RS::ARRAY_MAX];
- int total_elem_size = 0;
+ uint32_t vertex_element_size;
+ uint32_t attrib_element_size;
+ uint32_t skin_element_size;
- for (int i = 0; i < RS::ARRAY_MAX; i++) {
- offsets[i] = 0; //reset
-
- if (!(format & (1 << i))) { // no array
- continue;
- }
-
- int elem_size = 0;
-
- switch (i) {
- case RS::ARRAY_VERTEX: {
- Variant arr = p_arrays[0];
- if (arr.get_type() == Variant::PACKED_VECTOR2_ARRAY) {
- elem_size = 2;
- p_compress_format |= ARRAY_FLAG_USE_2D_VERTICES;
- } else if (arr.get_type() == Variant::PACKED_VECTOR3_ARRAY) {
- p_compress_format &= ~ARRAY_FLAG_USE_2D_VERTICES;
- elem_size = 3;
- } else {
- elem_size = (p_compress_format & ARRAY_FLAG_USE_2D_VERTICES) ? 2 : 3;
- }
-
- {
- elem_size *= sizeof(float);
- }
-
- } break;
- case RS::ARRAY_NORMAL: {
- if (p_compress_format & ARRAY_COMPRESS_NORMAL) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 3;
- }
-
- } break;
-
- case RS::ARRAY_TANGENT: {
- if (p_compress_format & ARRAY_COMPRESS_TANGENT) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
-
- } break;
- case RS::ARRAY_COLOR: {
- if (p_compress_format & ARRAY_COMPRESS_COLOR) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
- } break;
- case RS::ARRAY_TEX_UV: {
- if (p_compress_format & ARRAY_COMPRESS_TEX_UV) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
-
- } break;
-
- case RS::ARRAY_TEX_UV2: {
- if (p_compress_format & ARRAY_COMPRESS_TEX_UV2) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
-
- } break;
- case RS::ARRAY_WEIGHTS: {
- elem_size = sizeof(uint16_t) * 4;
-
- } break;
- case RS::ARRAY_BONES: {
- elem_size = sizeof(uint16_t) * 4;
-
- } break;
- case RS::ARRAY_INDEX: {
- if (index_array_len <= 0) {
- ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
- break;
- }
- /* determine whether using 16 or 32 bits indices */
- if (array_len >= (1 << 16)) {
- elem_size = 4;
-
- } else {
- elem_size = 2;
- }
- offsets[i] = elem_size;
- continue;
- }
- default: {
- ERR_FAIL_V(ERR_BUG);
- }
- }
-
- offsets[i] = total_elem_size;
- total_elem_size += elem_size;
- }
+ mesh_surface_make_offsets_from_format(format, array_len, index_array_len, offsets, vertex_element_size, attrib_element_size, skin_element_size);
uint32_t mask = (1 << ARRAY_MAX) - 1;
format |= (~mask) & p_compress_format; //make the full format
- int array_size = total_elem_size * array_len;
+ int vertex_array_size = vertex_element_size * array_len;
+ int attrib_array_size = attrib_element_size * array_len;
+ int skin_array_size = skin_element_size * array_len;
+ int index_array_size = offsets[RS::ARRAY_INDEX] * index_array_len;
Vector<uint8_t> vertex_array;
- vertex_array.resize(array_size);
+ vertex_array.resize(vertex_array_size);
- int index_array_size = offsets[RS::ARRAY_INDEX] * index_array_len;
+ Vector<uint8_t> attrib_array;
+ attrib_array.resize(attrib_array_size);
+
+ Vector<uint8_t> skin_array;
+ skin_array.resize(skin_array_size);
Vector<uint8_t> index_array;
index_array.resize(index_array_size);
@@ -942,22 +918,29 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
AABB aabb;
Vector<AABB> bone_aabb;
- Error err = _surface_set_data(p_arrays, format, offsets, total_elem_size, vertex_array, array_len, index_array, index_array_len, aabb, bone_aabb);
+ Error err = _surface_set_data(p_arrays, format, offsets, vertex_element_size, attrib_element_size, skin_element_size, vertex_array, attrib_array, skin_array, array_len, index_array, index_array_len, aabb, bone_aabb);
ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Invalid array format for surface.");
- Vector<Vector<uint8_t>> blend_shape_data;
-
- for (int i = 0; i < p_blend_shapes.size(); i++) {
- Vector<uint8_t> vertex_array_shape;
- vertex_array_shape.resize(array_size);
- Vector<uint8_t> noindex;
+ Vector<uint8_t> blend_shape_data;
+ uint32_t blend_shape_count = 0;
- AABB laabb;
- Error err2 = _surface_set_data(p_blend_shapes[i], format & ~ARRAY_FORMAT_INDEX, offsets, total_elem_size, vertex_array_shape, array_len, noindex, 0, laabb, bone_aabb);
- aabb.merge_with(laabb);
- ERR_FAIL_COND_V_MSG(err2 != OK, ERR_INVALID_DATA, "Invalid blend shape array format for surface.");
-
- blend_shape_data.push_back(vertex_array_shape);
+ if (p_blend_shapes.size()) {
+ uint32_t bs_format = format & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK;
+ for (int i = 0; i < p_blend_shapes.size(); i++) {
+ Vector<uint8_t> vertex_array_shape;
+ vertex_array_shape.resize(vertex_array_size);
+ Vector<uint8_t> noindex;
+ Vector<uint8_t> noattrib;
+ Vector<uint8_t> noskin;
+
+ AABB laabb;
+ Error err2 = _surface_set_data(p_blend_shapes[i], bs_format, offsets, vertex_element_size, 0, 0, vertex_array_shape, noattrib, noskin, array_len, noindex, 0, laabb, bone_aabb);
+ aabb.merge_with(laabb);
+ ERR_FAIL_COND_V_MSG(err2 != OK, ERR_INVALID_DATA, "Invalid blend shape array format for surface.");
+
+ blend_shape_data.append_array(vertex_array_shape);
+ blend_shape_count++;
+ }
}
Vector<SurfaceData::LOD> lods;
if (index_array_len) {
@@ -1004,10 +987,13 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
surface_data.primitive = p_primitive;
surface_data.aabb = aabb;
surface_data.vertex_data = vertex_array;
+ surface_data.attribute_data = attrib_array;
+ surface_data.skin_data = skin_array;
surface_data.vertex_count = array_len;
surface_data.index_data = index_array;
surface_data.index_count = index_array_len;
- surface_data.blend_shapes = blend_shape_data;
+ surface_data.blend_shape_count = blend_shape_count;
+ surface_data.blend_shape_data = blend_shape_data;
surface_data.bone_aabbs = bone_aabb;
surface_data.lods = lods;
@@ -1023,110 +1009,20 @@ void RenderingServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_p
mesh_add_surface(p_mesh, sd);
}
-Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const {
- uint32_t offsets[ARRAY_MAX];
-
- int total_elem_size = 0;
-
- for (int i = 0; i < RS::ARRAY_MAX; i++) {
- offsets[i] = 0; //reset
-
- if (!(p_format & (1 << i))) { // no array
- continue;
- }
-
- int elem_size = 0;
-
- switch (i) {
- case RS::ARRAY_VERTEX: {
- if (p_format & ARRAY_FLAG_USE_2D_VERTICES) {
- elem_size = 2;
- } else {
- elem_size = 3;
- }
-
- {
- elem_size *= sizeof(float);
- }
-
- } break;
- case RS::ARRAY_NORMAL: {
- if (p_format & ARRAY_COMPRESS_NORMAL) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 3;
- }
-
- } break;
-
- case RS::ARRAY_TANGENT: {
- if (p_format & ARRAY_COMPRESS_TANGENT) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
-
- } break;
- case RS::ARRAY_COLOR: {
- if (p_format & ARRAY_COMPRESS_COLOR) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
- } break;
- case RS::ARRAY_TEX_UV: {
- if (p_format & ARRAY_COMPRESS_TEX_UV) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
-
- } break;
-
- case RS::ARRAY_TEX_UV2: {
- if (p_format & ARRAY_COMPRESS_TEX_UV2) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
-
- } break;
- case RS::ARRAY_WEIGHTS: {
- elem_size = sizeof(uint16_t) * 4;
-
- } break;
- case RS::ARRAY_BONES: {
- elem_size = sizeof(uint16_t) * 4;
-
- } break;
- case RS::ARRAY_INDEX: {
- if (p_index_len <= 0) {
- ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
- break;
- }
- /* determine whether using 16 or 32 bits indices */
- if (p_vertex_len >= (1 << 16)) {
- elem_size = 4;
-
- } else {
- elem_size = 2;
- }
- offsets[i] = elem_size;
- continue;
- }
- default: {
- ERR_FAIL_V(Array());
- }
- }
+Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const {
+ uint32_t offsets[RS::ARRAY_MAX];
- offsets[i] = total_elem_size;
- total_elem_size += elem_size;
- }
+ uint32_t vertex_elem_size;
+ uint32_t attrib_elem_size;
+ uint32_t skin_elem_size;
+ mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets, vertex_elem_size, attrib_elem_size, skin_elem_size);
Array ret;
ret.resize(RS::ARRAY_MAX);
const uint8_t *r = p_vertex_data.ptr();
+ const uint8_t *ar = p_attrib_data.ptr();
+ const uint8_t *sr = p_skin_data.ptr();
for (int i = 0; i < RS::ARRAY_MAX; i++) {
if (!(p_format & (1 << i))) {
@@ -1143,7 +1039,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
Vector2 *w = arr_2d.ptrw();
for (int j = 0; j < p_vertex_len; j++) {
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
+ const float *v = (const float *)&r[j * vertex_elem_size + offsets[i]];
w[j] = Vector2(v[0], v[1]);
}
}
@@ -1157,7 +1053,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
Vector3 *w = arr_3d.ptrw();
for (int j = 0; j < p_vertex_len; j++) {
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
+ const float *v = (const float *)&r[j * vertex_elem_size + offsets[i]];
w[j] = Vector3(v[0], v[1], v[2]);
}
}
@@ -1170,21 +1066,11 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
Vector<Vector3> arr;
arr.resize(p_vertex_len);
- if (p_format & ARRAY_COMPRESS_NORMAL) {
- Vector3 *w = arr.ptrw();
- const float multiplier = 1.f / 127.f;
+ Vector3 *w = arr.ptrw();
- for (int j = 0; j < p_vertex_len; j++) {
- const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector3(float(v[0]) * multiplier, float(v[1]) * multiplier, float(v[2]) * multiplier);
- }
- } else {
- Vector3 *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector3(v[0], v[1], v[2]);
- }
+ for (int j = 0; j < p_vertex_len; j++) {
+ const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]];
+ w[j] = Vector3((v & 0x3FF) / 1023.0, ((v >> 10) & 0x3FF) / 1023.0, ((v >> 20) & 0x3FF) / 1023.0) * Vector3(2, 2, 2) - Vector3(1, 1, 1);
}
ret[i] = arr;
@@ -1194,24 +1080,16 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
case RS::ARRAY_TANGENT: {
Vector<float> arr;
arr.resize(p_vertex_len * 4);
- if (p_format & ARRAY_COMPRESS_TANGENT) {
- float *w = arr.ptrw();
- for (int j = 0; j < p_vertex_len; j++) {
- const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
- for (int k = 0; k < 4; k++) {
- w[j * 4 + k] = float(v[k] / 127.0);
- }
- }
- } else {
- float *w = arr.ptrw();
+ float *w = arr.ptrw();
- for (int j = 0; j < p_vertex_len; j++) {
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- for (int k = 0; k < 4; k++) {
- w[j * 4 + k] = v[k];
- }
- }
+ for (int j = 0; j < p_vertex_len; j++) {
+ const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]];
+
+ w[j * 4 + 0] = ((v & 0x3FF) / 1023.0) * 2.0 - 1.0;
+ w[j * 4 + 1] = (((v >> 10) & 0x3FF) / 1023.0) * 2.0 - 1.0;
+ w[j * 4 + 2] = (((v >> 20) & 0x3FF) / 1023.0) * 2.0 - 1.0;
+ w[j * 4 + 3] = ((v >> 30) / 3.0) * 2.0 - 1.0;
}
ret[i] = arr;
@@ -1221,20 +1099,11 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
Vector<Color> arr;
arr.resize(p_vertex_len);
- if (p_format & ARRAY_COMPRESS_COLOR) {
- Color *w = arr.ptrw();
+ Color *w = arr.ptrw();
- for (int j = 0; j < p_vertex_len; j++) {
- const uint8_t *v = (const uint8_t *)&r[j * total_elem_size + offsets[i]];
- w[j] = Color(float(v[0] / 255.0), float(v[1] / 255.0), float(v[2] / 255.0), float(v[3] / 255.0));
- }
- } else {
- Color *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- w[j] = Color(v[0], v[1], v[2], v[3]);
- }
+ for (int32_t j = 0; j < p_vertex_len; j++) {
+ const uint16_t *v = (const uint16_t *)&ar[j * attrib_elem_size + offsets[i]];
+ w[j] = Color(Math::half_to_float(v[0]), Math::half_to_float(v[1]), Math::half_to_float(v[2]), Math::half_to_float(v[3]));
}
ret[i] = arr;
@@ -1243,20 +1112,11 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
Vector<Vector2> arr;
arr.resize(p_vertex_len);
- if (p_format & ARRAY_COMPRESS_TEX_UV) {
- Vector2 *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
- const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector2(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1]));
- }
- } else {
- Vector2 *w = arr.ptrw();
+ Vector2 *w = arr.ptrw();
- for (int j = 0; j < p_vertex_len; j++) {
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector2(v[0], v[1]);
- }
+ for (int j = 0; j < p_vertex_len; j++) {
+ const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]];
+ w[j] = Vector2(v[0], v[1]);
}
ret[i] = arr;
@@ -1266,35 +1126,74 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
Vector<Vector2> arr;
arr.resize(p_vertex_len);
- if (p_format & ARRAY_COMPRESS_TEX_UV2) {
- Vector2 *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
- const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector2(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1]));
- }
- } else {
- Vector2 *w = arr.ptrw();
+ Vector2 *w = arr.ptrw();
- for (int j = 0; j < p_vertex_len; j++) {
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector2(v[0], v[1]);
- }
+ for (int j = 0; j < p_vertex_len; j++) {
+ const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]];
+ w[j] = Vector2(v[0], v[1]);
}
ret[i] = arr;
} break;
+ case RS::ARRAY_CUSTOM0:
+ case RS::ARRAY_CUSTOM1:
+ case RS::ARRAY_CUSTOM2:
+ case RS::ARRAY_CUSTOM3: {
+ uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - i))) & ARRAY_FORMAT_CUSTOM_MASK;
+ switch (type) {
+ case ARRAY_CUSTOM_RGBA8_UNORM:
+ case ARRAY_CUSTOM_RGBA8_SNORM:
+ case ARRAY_CUSTOM_RG_HALF:
+ case ARRAY_CUSTOM_RGBA_HALF: {
+ //size 4
+ int s = type == ARRAY_CUSTOM_RGBA_HALF ? 8 : 4;
+ Vector<uint8_t> arr;
+ arr.resize(p_vertex_len * s);
+
+ uint8_t *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+ const uint8_t *v = (const uint8_t *)&ar[j * attrib_elem_size + offsets[i]];
+ copymem(&w[j * s], v, s);
+ }
+
+ ret[i] = arr;
+
+ } break;
+ case ARRAY_CUSTOM_R_FLOAT:
+ case ARRAY_CUSTOM_RG_FLOAT:
+ case ARRAY_CUSTOM_RGB_FLOAT:
+ case ARRAY_CUSTOM_RGBA_FLOAT: {
+ uint32_t s = type - ARRAY_CUSTOM_R_FLOAT + 1;
+
+ Vector<float> arr;
+ float *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+ const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]];
+ copymem(&w[j * s], v, s * sizeof(float));
+ }
+ ret[i] = arr;
+
+ } break;
+ default: {
+ }
+ }
+
+ } break;
case RS::ARRAY_WEIGHTS: {
+ uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4;
+
Vector<float> arr;
- arr.resize(p_vertex_len * 4);
+ arr.resize(p_vertex_len * bone_count);
{
float *w = arr.ptrw();
for (int j = 0; j < p_vertex_len; j++) {
- const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
- for (int k = 0; k < 4; k++) {
- w[j * 4 + k] = float(v[k] / 65535.0);
+ const uint16_t *v = (const uint16_t *)&sr[j * skin_elem_size + offsets[i]];
+ for (uint32_t k = 0; k < bone_count; k++) {
+ w[j * bone_count + k] = float(v[k] / 65535.0);
}
}
}
@@ -1303,15 +1202,17 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
} break;
case RS::ARRAY_BONES: {
+ uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4;
+
Vector<int> arr;
- arr.resize(p_vertex_len * 4);
+ arr.resize(p_vertex_len * bone_count);
int *w = arr.ptrw();
for (int j = 0; j < p_vertex_len; j++) {
- const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
- for (int k = 0; k < 4; k++) {
- w[j * 4 + k] = v[k];
+ const uint16_t *v = (const uint16_t *)&sr[j * skin_elem_size + offsets[i]];
+ for (uint32_t k = 0; k < bone_count; k++) {
+ w[j * bone_count + k] = v[k];
}
}
@@ -1394,20 +1295,30 @@ Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_sur
SurfaceData sd = mesh_get_surface(p_mesh, p_surface);
ERR_FAIL_COND_V(sd.vertex_count == 0, Array());
- Vector<Vector<uint8_t>> blend_shape_data = sd.blend_shapes;
+ Vector<uint8_t> blend_shape_data = sd.blend_shape_data;
if (blend_shape_data.size() > 0) {
- int vertex_len = sd.vertex_count;
+ uint32_t bs_offsets[RS::ARRAY_MAX];
+ uint32_t bs_format = (sd.format & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK);
+ uint32_t vertex_elem_size;
+ uint32_t attrib_elem_size;
+ uint32_t skin_elem_size;
+
+ mesh_surface_make_offsets_from_format(bs_format, sd.vertex_count, 0, bs_offsets, vertex_elem_size, attrib_elem_size, skin_elem_size);
- Vector<uint8_t> index_data = sd.index_data;
- int index_len = sd.index_count;
+ int divisor = vertex_elem_size * sd.vertex_count;
+ ERR_FAIL_COND_V((blend_shape_data.size() % divisor) != 0, Array());
- uint32_t format = sd.format;
+ uint32_t blend_shape_count = blend_shape_data.size() / divisor;
+
+ ERR_FAIL_COND_V(blend_shape_count != sd.blend_shape_count, Array());
Array blend_shape_array;
- blend_shape_array.resize(blend_shape_data.size());
- for (int i = 0; i < blend_shape_data.size(); i++) {
- blend_shape_array.set(i, _get_array_from_surface(format, blend_shape_data[i], vertex_len, index_data, index_len));
+ blend_shape_array.resize(blend_shape_count);
+ for (uint32_t i = 0; i < blend_shape_count; i++) {
+ Vector<uint8_t> bs_data = blend_shape_data.subarray(i * divisor, (i + 1) * divisor - 1);
+ Vector<uint8_t> unused;
+ blend_shape_array.set(i, _get_array_from_surface(bs_format, bs_data, unused, unused, sd.vertex_count, unused, 0));
}
return blend_shape_array;
@@ -1418,6 +1329,8 @@ Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_sur
Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const {
Vector<uint8_t> vertex_data = p_data.vertex_data;
+ Vector<uint8_t> attrib_data = p_data.attribute_data;
+ Vector<uint8_t> skin_data = p_data.skin_data;
ERR_FAIL_COND_V(vertex_data.size() == 0, Array());
int vertex_len = p_data.vertex_count;
@@ -1427,7 +1340,7 @@ Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p
uint32_t format = p_data.format;
- return _get_array_from_surface(format, vertex_data, vertex_len, index_data, index_len);
+ return _get_array_from_surface(format, vertex_data, attrib_data, skin_data, vertex_len, index_data, index_len);
}
#if 0
Array RenderingServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surface) const {
@@ -1540,9 +1453,11 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("material_set_next_pass", "material", "next_material"), &RenderingServer::material_set_next_pass);
ClassDB::bind_method(D_METHOD("mesh_create"), &RenderingServer::mesh_create);
- ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_len", "index_len", "array_index"), &RenderingServer::mesh_surface_get_format_offset);
- ClassDB::bind_method(D_METHOD("mesh_surface_get_format_stride", "format", "vertex_len", "index_len"), &RenderingServer::mesh_surface_get_format_stride);
- ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primitive", "arrays", "blend_shapes", "lods", "compress_format"), &RenderingServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT));
+ ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_count", "array_index"), &RenderingServer::mesh_surface_get_format_offset);
+ ClassDB::bind_method(D_METHOD("mesh_surface_get_format_vertex_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_vertex_stride);
+ ClassDB::bind_method(D_METHOD("mesh_surface_get_format_attribute_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_attribute_stride);
+ ClassDB::bind_method(D_METHOD("mesh_surface_get_format_skin_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_skin_stride);
+ //ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primitive", "arrays", "blend_shapes", "lods", "compress_format"), &RenderingServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT));
ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_count", "mesh"), &RenderingServer::mesh_get_blend_shape_count);
ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_mode", "mesh", "mode"), &RenderingServer::mesh_set_blend_shape_mode);
ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_mode", "mesh"), &RenderingServer::mesh_get_blend_shape_mode);
@@ -1617,6 +1532,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("light_directional_set_shadow_mode", "light", "mode"), &RenderingServer::light_directional_set_shadow_mode);
ClassDB::bind_method(D_METHOD("light_directional_set_blend_splits", "light", "enable"), &RenderingServer::light_directional_set_blend_splits);
+ ClassDB::bind_method(D_METHOD("light_directional_set_sky_only", "light", "enable"), &RenderingServer::light_directional_set_sky_only);
ClassDB::bind_method(D_METHOD("light_directional_set_shadow_depth_range_mode", "light", "range_mode"), &RenderingServer::light_directional_set_shadow_depth_range_mode);
ClassDB::bind_method(D_METHOD("reflection_probe_create"), &RenderingServer::reflection_probe_create);
@@ -1749,7 +1665,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source", "ao_color"), &RenderingServer::environment_set_ambient_light, DEFVAL(RS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(RS::ENV_REFLECTION_SOURCE_BG), DEFVAL(Color()));
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_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", "ramp"), &RenderingServer::environment_set_adjustment);
+ 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);
ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "bias", "light_affect", "ao_channel_affect", "blur", "bilateral_sharpness"), &RenderingServer::environment_set_ssao);
ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective"), &RenderingServer::environment_set_fog);
@@ -1946,14 +1862,6 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS);
BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_NORMAL);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TANGENT);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_COLOR);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV2);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT);
-
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 236112c3fb..c22cf3ace4 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -52,7 +52,7 @@ class RenderingServer : public Object {
void _camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far);
void _canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate = Color(1, 1, 1));
- Array _get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const;
+ Array _get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const;
protected:
RID _make_test_cube();
@@ -61,7 +61,7 @@ protected:
RID white_texture;
RID test_material;
- Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, Vector<uint8_t> &r_vertex_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb);
+ Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb);
static RenderingServer *(*create_func)();
static void _bind_methods();
@@ -199,16 +199,36 @@ public:
/* MESH API */
enum ArrayType {
- ARRAY_VERTEX = 0,
- ARRAY_NORMAL = 1,
- ARRAY_TANGENT = 2,
- ARRAY_COLOR = 3,
- ARRAY_TEX_UV = 4,
- ARRAY_TEX_UV2 = 5,
- ARRAY_BONES = 6,
- ARRAY_WEIGHTS = 7,
- ARRAY_INDEX = 8,
- ARRAY_MAX = 9
+ ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit)
+ ARRAY_NORMAL = 1, // A2B10G10R10
+ ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal
+ ARRAY_COLOR = 3, // RGBA16F
+ ARRAY_TEX_UV = 4, // RG32F
+ ARRAY_TEX_UV2 = 5, // RG32F
+ ARRAY_CUSTOM0 = 6, // depends on ArrayCustomFormat
+ ARRAY_CUSTOM1 = 7,
+ ARRAY_CUSTOM2 = 8,
+ ARRAY_CUSTOM3 = 9,
+ ARRAY_BONES = 10, // RGBA16UI (x2 if 8 weights)
+ ARRAY_WEIGHTS = 11, // RGBA16UNORM (x2 if 8 weights)
+ ARRAY_INDEX = 12, // 16 or 32 bits depending on length > 0xFFFF
+ ARRAY_MAX = 13
+ };
+
+ enum {
+ ARRAY_CUSTOM_COUNT = ARRAY_BONES - ARRAY_CUSTOM0
+ };
+
+ enum ArrayCustomFormat {
+ ARRAY_CUSTOM_RGBA8_UNORM,
+ ARRAY_CUSTOM_RGBA8_SNORM,
+ ARRAY_CUSTOM_RG_HALF,
+ ARRAY_CUSTOM_RGBA_HALF,
+ ARRAY_CUSTOM_R_FLOAT,
+ ARRAY_CUSTOM_RG_FLOAT,
+ ARRAY_CUSTOM_RGB_FLOAT,
+ ARRAY_CUSTOM_RGBA_FLOAT,
+ ARRAY_CUSTOM_MAX
};
enum ArrayFormat {
@@ -219,21 +239,29 @@ public:
ARRAY_FORMAT_COLOR = 1 << ARRAY_COLOR,
ARRAY_FORMAT_TEX_UV = 1 << ARRAY_TEX_UV,
ARRAY_FORMAT_TEX_UV2 = 1 << ARRAY_TEX_UV2,
+ ARRAY_FORMAT_CUSTOM0 = 1 << ARRAY_CUSTOM0,
+ ARRAY_FORMAT_CUSTOM1 = 1 << ARRAY_CUSTOM1,
+ ARRAY_FORMAT_CUSTOM2 = 1 << ARRAY_CUSTOM2,
+ ARRAY_FORMAT_CUSTOM3 = 1 << ARRAY_CUSTOM3,
ARRAY_FORMAT_BONES = 1 << ARRAY_BONES,
ARRAY_FORMAT_WEIGHTS = 1 << ARRAY_WEIGHTS,
ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX,
- ARRAY_COMPRESS_BASE = (ARRAY_INDEX + 1),
- ARRAY_COMPRESS_NORMAL = 1 << (ARRAY_NORMAL + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_TANGENT = 1 << (ARRAY_TANGENT + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_COLOR = 1 << (ARRAY_COLOR + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_TEX_UV = 1 << (ARRAY_TEX_UV + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_TEX_UV2 = 1 << (ARRAY_TEX_UV2 + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_INDEX = 1 << (ARRAY_INDEX + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2,
+ ARRAY_FORMAT_BLEND_SHAPE_MASK = ~(ARRAY_FORMAT_COLOR | ARRAY_FORMAT_TEX_UV | ARRAY_FORMAT_TEX_UV2 | ARRAY_FORMAT_BONES | ARRAY_FORMAT_WEIGHTS | ARRAY_FORMAT_CUSTOM0 | ARRAY_FORMAT_CUSTOM1 | ARRAY_FORMAT_CUSTOM2 | ARRAY_FORMAT_CUSTOM3 | ARRAY_FORMAT_INDEX),
- ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1,
- ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3,
+ ARRAY_FORMAT_CUSTOM_BASE = (ARRAY_INDEX + 1),
+ ARRAY_FORMAT_CUSTOM_BITS = 3,
+ ARRAY_FORMAT_CUSTOM0_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + 0),
+ ARRAY_FORMAT_CUSTOM1_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS),
+ ARRAY_FORMAT_CUSTOM2_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * 2),
+ ARRAY_FORMAT_CUSTOM3_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * 3),
+
+ ARRAY_FORMAT_CUSTOM_MASK = 0x7,
+ ARRAY_COMPRESS_FLAGS_BASE = (ARRAY_INDEX + 1 + 12),
+
+ ARRAY_FLAG_USE_2D_VERTICES = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 0),
+ ARRAY_FLAG_USE_DYNAMIC_UPDATE = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 1),
+ ARRAY_FLAG_USE_8_BONE_WEIGHTS = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 2),
};
enum PrimitiveType {
@@ -249,11 +277,15 @@ public:
PrimitiveType primitive = PRIMITIVE_MAX;
uint32_t format = 0;
- Vector<uint8_t> vertex_data;
+ Vector<uint8_t> vertex_data; // vertex, normal, tangent (change with skinning, blendshape)
+ Vector<uint8_t> attribute_data; // color,uv, uv2, custom0-3
+ Vector<uint8_t> skin_data; // bone index, bone weight
uint32_t vertex_count = 0;
Vector<uint8_t> index_data;
uint32_t index_count = 0;
+ uint32_t blend_shape_count = 0;
+
AABB aabb;
struct LOD {
float edge_length;
@@ -262,7 +294,7 @@ public:
Vector<LOD> lods;
Vector<AABB> bone_aabbs;
- Vector<Vector<uint8_t>> blend_shapes;
+ Vector<uint8_t> blend_shape_data;
RID material;
};
@@ -270,17 +302,20 @@ public:
virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) = 0;
virtual RID mesh_create() = 0;
- virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const;
- virtual uint32_t mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const;
+ virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_array_index) const;
+ virtual uint32_t mesh_surface_get_format_vertex_stride(uint32_t p_format, int p_vertex_len) const;
+ virtual uint32_t mesh_surface_get_format_attribute_stride(uint32_t p_format, int p_vertex_len) const;
+ virtual uint32_t mesh_surface_get_format_skin_stride(uint32_t p_format, int p_vertex_len) const;
+
/// Returns stride
- virtual uint32_t mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const;
- virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT);
+ virtual void mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const;
+ virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0);
Array mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const;
Array mesh_surface_get_arrays(RID p_mesh, int p_surface) const;
Array mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const;
Dictionary mesh_surface_get_lods(RID p_mesh, int p_surface) const;
- virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT);
+ virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0);
virtual void mesh_add_surface(RID p_mesh, const SurfaceData &p_surface) = 0;
virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0;
@@ -436,6 +471,7 @@ public:
virtual void light_directional_set_shadow_mode(RID p_light, LightDirectionalShadowMode p_mode) = 0;
virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0;
+ virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0;
enum LightDirectionalShadowDepthRangeMode {
LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE,
@@ -889,7 +925,7 @@ public:
};
virtual void environment_set_tonemap(RID p_env, 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_grey) = 0;
- virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0;
+ virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) = 0;
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance) = 0;
@@ -1175,7 +1211,7 @@ public:
};
virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0) = 0;
- virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0;
+ virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0;
virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0;
virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0;
virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0;
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
new file mode 100644
index 0000000000..74bf437a25
--- /dev/null
+++ b/servers/text_server.cpp
@@ -0,0 +1,1246 @@
+/*************************************************************************/
+/* text_server.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "servers/text_server.h"
+#include "scene/main/canvas_item.h"
+
+TextServerManager *TextServerManager::singleton = nullptr;
+TextServer *TextServerManager::server = nullptr;
+TextServerManager::TextServerCreate TextServerManager::server_create_functions[TextServerManager::MAX_SERVERS];
+int TextServerManager::server_create_count = 0;
+
+void TextServerManager::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_interface_count"), &TextServerManager::_get_interface_count);
+ ClassDB::bind_method(D_METHOD("get_interface_name", "index"), &TextServerManager::_get_interface_name);
+ ClassDB::bind_method(D_METHOD("get_interface_features", "index"), &TextServerManager::_get_interface_features);
+ ClassDB::bind_method(D_METHOD("get_interface", "index"), &TextServerManager::_get_interface);
+ ClassDB::bind_method(D_METHOD("get_interfaces"), &TextServerManager::_get_interfaces);
+ ClassDB::bind_method(D_METHOD("find_interface", "name"), &TextServerManager::_find_interface);
+
+ ClassDB::bind_method(D_METHOD("set_primary_interface", "index"), &TextServerManager::_set_primary_interface);
+ ClassDB::bind_method(D_METHOD("get_primary_interface"), &TextServerManager::_get_primary_interface);
+}
+
+void TextServerManager::register_create_function(const String &p_name, uint32_t p_features, TextServerManager::CreateFunction p_function, void *p_user_data) {
+ ERR_FAIL_COND(server_create_count == MAX_SERVERS);
+ server_create_functions[server_create_count].name = p_name;
+ server_create_functions[server_create_count].create_function = p_function;
+ server_create_functions[server_create_count].user_data = p_user_data;
+ server_create_functions[server_create_count].features = p_features;
+ server_create_count++;
+}
+
+int TextServerManager::get_interface_count() {
+ return server_create_count;
+}
+
+String TextServerManager::get_interface_name(int p_index) {
+ ERR_FAIL_INDEX_V(p_index, server_create_count, String());
+ return server_create_functions[p_index].name;
+}
+
+uint32_t TextServerManager::get_interface_features(int p_index) {
+ ERR_FAIL_INDEX_V(p_index, server_create_count, 0);
+ return server_create_functions[p_index].features;
+}
+
+TextServer *TextServerManager::initialize(int p_index, Error &r_error) {
+ ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr);
+ if (server_create_functions[p_index].instance == nullptr) {
+ server_create_functions[p_index].instance = server_create_functions[p_index].create_function(r_error, server_create_functions[p_index].user_data);
+ if (server_create_functions[p_index].instance != nullptr) {
+ server_create_functions[p_index].instance->load_support_data(""); // Try loading default data.
+ }
+ }
+ if (server_create_functions[p_index].instance != nullptr) {
+ server = server_create_functions[p_index].instance;
+ if (OS::get_singleton()->get_main_loop()) {
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TEXT_SERVER_CHANGED);
+ }
+ }
+ return server_create_functions[p_index].instance;
+}
+
+TextServer *TextServerManager::get_primary_interface() {
+ return server;
+}
+
+int TextServerManager::_get_interface_count() const {
+ return server_create_count;
+}
+
+String TextServerManager::_get_interface_name(int p_index) const {
+ return get_interface_name(p_index);
+}
+
+uint32_t TextServerManager::_get_interface_features(int p_index) const {
+ return get_interface_features(p_index);
+}
+
+TextServer *TextServerManager::_get_interface(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr);
+ if (server_create_functions[p_index].instance == nullptr) {
+ Error error;
+ server_create_functions[p_index].instance = server_create_functions[p_index].create_function(error, server_create_functions[p_index].user_data);
+ if (server_create_functions[p_index].instance != nullptr) {
+ server_create_functions[p_index].instance->load_support_data(""); // Try loading default data.
+ }
+ }
+ return server_create_functions[p_index].instance;
+}
+
+TextServer *TextServerManager::_find_interface(const String &p_name) const {
+ for (int i = 0; i < server_create_count; i++) {
+ if (server_create_functions[i].name == p_name) {
+ return _get_interface(i);
+ }
+ }
+ return nullptr;
+}
+
+Array TextServerManager::_get_interfaces() const {
+ Array ret;
+
+ for (int i = 0; i < server_create_count; i++) {
+ Dictionary iface_info;
+
+ iface_info["id"] = i;
+ iface_info["name"] = server_create_functions[i].name;
+
+ ret.push_back(iface_info);
+ };
+
+ return ret;
+};
+
+bool TextServerManager::_set_primary_interface(int p_index) {
+ Error error;
+ TextServerManager::initialize(p_index, error);
+ return (error == OK);
+}
+
+TextServer *TextServerManager::_get_primary_interface() const {
+ return server;
+}
+
+TextServerManager::TextServerManager() {
+ singleton = this;
+}
+
+TextServerManager::~TextServerManager() {
+ singleton = nullptr;
+ for (int i = 0; i < server_create_count; i++) {
+ if (server_create_functions[i].instance != nullptr) {
+ memdelete(server_create_functions[i].instance);
+ server_create_functions[i].instance = nullptr;
+ }
+ }
+}
+
+/*************************************************************************/
+
+bool TextServer::Glyph::operator==(const Glyph &p_a) const {
+ return (p_a.index == index) && (p_a.font_rid == font_rid) && (p_a.font_size == font_size) && (p_a.start == start);
+}
+
+bool TextServer::Glyph::operator!=(const Glyph &p_a) const {
+ return (p_a.index != index) || (p_a.font_rid != font_rid) || (p_a.font_size != font_size) || (p_a.start != start);
+}
+
+bool TextServer::Glyph::operator<(const Glyph &p_a) const {
+ if (p_a.start == start) {
+ if (p_a.count == count) {
+ if ((p_a.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return p_a.count > count;
+ }
+ return p_a.start < start;
+}
+
+bool TextServer::Glyph::operator>(const Glyph &p_a) const {
+ if (p_a.start == start) {
+ if (p_a.count == count) {
+ if ((p_a.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ return p_a.count < count;
+ }
+ return p_a.start > start;
+}
+
+void TextServer::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("has_feature", "feature"), &TextServer::has_feature);
+ ClassDB::bind_method(D_METHOD("get_name"), &TextServer::get_name);
+ ClassDB::bind_method(D_METHOD("load_support_data", "filename"), &TextServer::load_support_data);
+
+ ClassDB::bind_method(D_METHOD("is_locale_right_to_left", "locale"), &TextServer::is_locale_right_to_left);
+
+ ClassDB::bind_method(D_METHOD("name_to_tag", "name"), &TextServer::name_to_tag);
+ ClassDB::bind_method(D_METHOD("tag_to_name", "tag"), &TextServer::tag_to_name);
+
+ ClassDB::bind_method(D_METHOD("has", "rid"), &TextServer::has);
+ ClassDB::bind_method(D_METHOD("free_rid", "rid"), &TextServer::free); // shouldn't conflict with Object::free()
+
+ /* Font Interface */
+ ClassDB::bind_method(D_METHOD("create_font_system", "name", "base_size"), &TextServer::create_font_system, DEFVAL(16));
+ ClassDB::bind_method(D_METHOD("create_font_resource", "filename", "base_size"), &TextServer::create_font_resource, DEFVAL(16));
+ ClassDB::bind_method(D_METHOD("create_font_memory", "data", "type", "base_size"), &TextServer::_create_font_memory, DEFVAL(16));
+
+ ClassDB::bind_method(D_METHOD("font_get_height", "font", "size"), &TextServer::font_get_height);
+ ClassDB::bind_method(D_METHOD("font_get_ascent", "font", "size"), &TextServer::font_get_ascent);
+ ClassDB::bind_method(D_METHOD("font_get_descent", "font", "size"), &TextServer::font_get_descent);
+
+ ClassDB::bind_method(D_METHOD("font_get_underline_position", "font", "size"), &TextServer::font_get_underline_position);
+ ClassDB::bind_method(D_METHOD("font_get_underline_thickness", "font", "size"), &TextServer::font_get_underline_thickness);
+
+ ClassDB::bind_method(D_METHOD("font_set_antialiased", "font", "antialiased"), &TextServer::font_set_antialiased);
+ ClassDB::bind_method(D_METHOD("font_get_antialiased", "font"), &TextServer::font_get_antialiased);
+
+ ClassDB::bind_method(D_METHOD("font_get_feature_list", "font"), &TextServer::font_get_feature_list);
+
+ ClassDB::bind_method(D_METHOD("font_set_hinting", "font", "hinting"), &TextServer::font_set_hinting);
+ ClassDB::bind_method(D_METHOD("font_get_hinting", "font"), &TextServer::font_get_hinting);
+
+ ClassDB::bind_method(D_METHOD("font_set_distance_field_hint", "font", "distance_field"), &TextServer::font_set_distance_field_hint);
+ ClassDB::bind_method(D_METHOD("font_get_distance_field_hint", "font"), &TextServer::font_get_distance_field_hint);
+
+ ClassDB::bind_method(D_METHOD("font_set_force_autohinter", "font", "enabeld"), &TextServer::font_set_force_autohinter);
+ ClassDB::bind_method(D_METHOD("font_get_force_autohinter", "font"), &TextServer::font_get_force_autohinter);
+
+ ClassDB::bind_method(D_METHOD("font_has_char", "font", "char"), &TextServer::font_has_char);
+ ClassDB::bind_method(D_METHOD("font_get_supported_chars", "font"), &TextServer::font_get_supported_chars);
+
+ ClassDB::bind_method(D_METHOD("font_has_outline", "font"), &TextServer::font_has_outline);
+ ClassDB::bind_method(D_METHOD("font_get_base_size", "font"), &TextServer::font_get_base_size);
+
+ ClassDB::bind_method(D_METHOD("font_is_language_supported", "font", "language"), &TextServer::font_is_language_supported);
+ ClassDB::bind_method(D_METHOD("font_set_language_support_override", "font", "language", "supported"), &TextServer::font_set_language_support_override);
+
+ ClassDB::bind_method(D_METHOD("font_get_language_support_override", "font", "language"), &TextServer::font_get_language_support_override);
+ ClassDB::bind_method(D_METHOD("font_remove_language_support_override", "font", "language"), &TextServer::font_remove_language_support_override);
+ ClassDB::bind_method(D_METHOD("font_get_language_support_overrides", "font"), &TextServer::font_get_language_support_overrides);
+
+ ClassDB::bind_method(D_METHOD("font_is_script_supported", "font", "script"), &TextServer::font_is_script_supported);
+ ClassDB::bind_method(D_METHOD("font_set_script_support_override", "font", "script", "supported"), &TextServer::font_set_script_support_override);
+
+ ClassDB::bind_method(D_METHOD("font_get_script_support_override", "font", "script"), &TextServer::font_get_script_support_override);
+ ClassDB::bind_method(D_METHOD("font_remove_script_support_override", "font", "script"), &TextServer::font_remove_script_support_override);
+ ClassDB::bind_method(D_METHOD("font_get_script_support_overrides", "font"), &TextServer::font_get_script_support_overrides);
+
+ ClassDB::bind_method(D_METHOD("font_get_glyph_index", "font", "char", "variation_selector"), &TextServer::font_get_glyph_index, DEFVAL(0x0000));
+ ClassDB::bind_method(D_METHOD("font_get_glyph_advance", "font", "index", "size"), &TextServer::font_get_glyph_advance);
+ ClassDB::bind_method(D_METHOD("font_get_glyph_kerning", "font", "index_a", "index_b", "size"), &TextServer::font_get_glyph_kerning);
+
+ ClassDB::bind_method(D_METHOD("font_draw_glyph", "font", "canvas", "size", "pos", "index", "color"), &TextServer::font_draw_glyph, DEFVAL(Color(1, 1, 1)));
+ ClassDB::bind_method(D_METHOD("font_draw_glyph_outline", "font", "canvas", "size", "outline_size", "pos", "index", "color"), &TextServer::font_draw_glyph_outline, DEFVAL(Color(1, 1, 1)));
+
+ ClassDB::bind_method(D_METHOD("font_get_oversampling"), &TextServer::font_get_oversampling);
+ ClassDB::bind_method(D_METHOD("font_set_oversampling", "oversampling"), &TextServer::font_set_oversampling);
+
+ ClassDB::bind_method(D_METHOD("get_system_fonts"), &TextServer::get_system_fonts);
+
+ ClassDB::bind_method(D_METHOD("get_hex_code_box_size", "size", "index"), &TextServer::get_hex_code_box_size);
+ ClassDB::bind_method(D_METHOD("draw_hex_code_box", "canvas", "size", "pos", "index", "color"), &TextServer::draw_hex_code_box);
+
+ /* Shaped text buffer interface */
+
+ ClassDB::bind_method(D_METHOD("create_shaped_text", "direction", "orientation"), &TextServer::create_shaped_text, DEFVAL(DIRECTION_AUTO), DEFVAL(ORIENTATION_HORIZONTAL));
+
+ ClassDB::bind_method(D_METHOD("shaped_text_clear"), &TextServer::shaped_text_clear);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_set_direction", "shaped", "direction"), &TextServer::shaped_text_set_direction, DEFVAL(DIRECTION_AUTO));
+ ClassDB::bind_method(D_METHOD("shaped_text_get_direction", "shaped"), &TextServer::shaped_text_get_direction);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_set_bidi_override", "shaped", "override"), &TextServer::_shaped_text_set_bidi_override);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_set_orientation", "shaped", "orientation"), &TextServer::shaped_text_set_orientation, DEFVAL(ORIENTATION_HORIZONTAL));
+ ClassDB::bind_method(D_METHOD("shaped_text_get_orientation", "shaped"), &TextServer::shaped_text_get_orientation);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_set_preserve_invalid", "shaped", "enabled"), &TextServer::shaped_text_set_preserve_invalid);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_invalid", "shaped"), &TextServer::shaped_text_get_preserve_invalid);
+
+ 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_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(VALIGN_CENTER));
+
+ 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));
+ ClassDB::bind_method(D_METHOD("shaped_text_tab_align", "shaped", "tab_stops"), &TextServer::shaped_text_tab_align);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_shape", "shaped"), &TextServer::shaped_text_shape);
+ ClassDB::bind_method(D_METHOD("shaped_text_is_ready", "shaped"), &TextServer::shaped_text_is_ready);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_get_glyphs", "shaped"), &TextServer::_shaped_text_get_glyphs);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_get_range", "shaped"), &TextServer::shaped_text_get_range);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks_adv", "shaped", "width", "start", "once", "break_flags"), &TextServer::_shaped_text_get_line_breaks_adv, DEFVAL(0), DEFVAL(true), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND));
+ ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks", "shaped", "width", "start", "break_flags"), &TextServer::_shaped_text_get_line_breaks, DEFVAL(0), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND));
+ ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks", "shaped"), &TextServer::_shaped_text_get_word_breaks);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_objects", "shaped"), &TextServer::shaped_text_get_objects);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_object_rect", "shaped", "key"), &TextServer::shaped_text_get_object_rect);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_get_size", "shaped"), &TextServer::shaped_text_get_size);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_ascent", "shaped"), &TextServer::shaped_text_get_ascent);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_descent", "shaped"), &TextServer::shaped_text_get_descent);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_width", "shaped"), &TextServer::shaped_text_get_width);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_underline_position", "shaped"), &TextServer::shaped_text_get_underline_position);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_underline_thickness", "shaped"), &TextServer::shaped_text_get_underline_thickness);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_get_carets", "shaped", "position"), &TextServer::_shaped_text_get_carets);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_selection", "shaped", "start", "end"), &TextServer::_shaped_text_get_selection);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_hit_test_grapheme", "shaped", "coords"), &TextServer::shaped_text_hit_test_grapheme);
+ ClassDB::bind_method(D_METHOD("shaped_text_hit_test_position", "shaped", "coords"), &TextServer::shaped_text_hit_test_position);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_next_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_next_grapheme_pos);
+ ClassDB::bind_method(D_METHOD("shaped_text_prev_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_prev_grapheme_pos);
+
+ ClassDB::bind_method(D_METHOD("shaped_text_draw", "shaped", "canvas", "pos", "clip_l", "clip_r", "color"), &TextServer::shaped_text_draw, DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1)));
+ ClassDB::bind_method(D_METHOD("shaped_text_draw_outline", "shaped", "canvas", "pos", "clip_l", "clip_r", "outline_size", "color"), &TextServer::shaped_text_draw_outline, DEFVAL(-1), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1, 1, 1)));
+
+ ClassDB::bind_method(D_METHOD("shaped_text_get_dominant_direciton_in_range", "shaped", "start", "end"), &TextServer::shaped_text_get_dominant_direciton_in_range);
+
+ ClassDB::bind_method(D_METHOD("format_number", "number", "language"), &TextServer::format_number, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("parse_number", "number", "language"), &TextServer::parse_number, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("percent_sign", "language"), &TextServer::percent_sign, DEFVAL(""));
+
+ /* Direction */
+ BIND_ENUM_CONSTANT(DIRECTION_AUTO);
+ BIND_ENUM_CONSTANT(DIRECTION_LTR);
+ BIND_ENUM_CONSTANT(DIRECTION_RTL);
+
+ /* Orientation */
+ BIND_ENUM_CONSTANT(ORIENTATION_HORIZONTAL);
+ BIND_ENUM_CONSTANT(ORIENTATION_VERTICAL);
+
+ /* JustificationFlag */
+ BIND_ENUM_CONSTANT(JUSTIFICATION_NONE);
+ BIND_ENUM_CONSTANT(JUSTIFICATION_KASHIDA);
+ BIND_ENUM_CONSTANT(JUSTIFICATION_WORD_BOUND);
+ BIND_ENUM_CONSTANT(JUSTIFICATION_TRIM_EDGE_SPACES);
+ BIND_ENUM_CONSTANT(JUSTIFICATION_AFTER_LAST_TAB);
+
+ /* LineBreakFlag */
+ BIND_ENUM_CONSTANT(BREAK_NONE);
+ BIND_ENUM_CONSTANT(BREAK_MANDATORY);
+ BIND_ENUM_CONSTANT(BREAK_WORD_BOUND);
+ BIND_ENUM_CONSTANT(BREAK_GRAPHEME_BOUND);
+
+ /* GraphemeFlag */
+ BIND_ENUM_CONSTANT(GRAPHEME_IS_RTL);
+ BIND_ENUM_CONSTANT(GRAPHEME_IS_VIRTUAL);
+ BIND_ENUM_CONSTANT(GRAPHEME_IS_SPACE);
+ BIND_ENUM_CONSTANT(GRAPHEME_IS_BREAK_HARD);
+ BIND_ENUM_CONSTANT(GRAPHEME_IS_BREAK_SOFT);
+ BIND_ENUM_CONSTANT(GRAPHEME_IS_TAB);
+ BIND_ENUM_CONSTANT(GRAPHEME_IS_ELONGATION);
+
+ /* Hinting */
+ BIND_ENUM_CONSTANT(HINTING_NONE);
+ BIND_ENUM_CONSTANT(HINTING_LIGHT);
+ BIND_ENUM_CONSTANT(HINTING_NORMAL);
+
+ /* Feature */
+ BIND_ENUM_CONSTANT(FEATURE_BIDI_LAYOUT);
+ BIND_ENUM_CONSTANT(FEATURE_VERTICAL_LAYOUT);
+ BIND_ENUM_CONSTANT(FEATURE_SHAPING);
+ BIND_ENUM_CONSTANT(FEATURE_KASHIDA_JUSTIFICATION);
+ BIND_ENUM_CONSTANT(FEATURE_BREAK_ITERATORS);
+ BIND_ENUM_CONSTANT(FEATURE_FONT_SYSTEM);
+ BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA);
+}
+
+Vector3 TextServer::hex_code_box_font_size[2] = { Vector3(5, 5, 1), Vector3(10, 10, 2) };
+Ref<CanvasTexture> TextServer::hex_code_box_font_tex[2] = { nullptr, nullptr };
+
+void TextServer::initialize_hex_code_box_fonts() {
+ static unsigned int tamsyn5x9_png_len = 175;
+ static unsigned char tamsyn5x9_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
+ 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x05,
+ 0x04, 0x03, 0x00, 0x00, 0x00, 0x20, 0x7c, 0x76, 0xda, 0x00, 0x00, 0x00,
+ 0x0f, 0x50, 0x4c, 0x54, 0x45, 0xfd, 0x07, 0x00, 0x00, 0x00, 0x00, 0x06,
+ 0x7e, 0x74, 0x00, 0x40, 0xc6, 0xff, 0xff, 0xff, 0x47, 0x9a, 0xd4, 0xc7,
+ 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8,
+ 0x66, 0x00, 0x00, 0x00, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x08, 0x1d, 0x05,
+ 0xc1, 0x21, 0x01, 0x00, 0x00, 0x00, 0x83, 0x30, 0x04, 0xc1, 0x10, 0xef,
+ 0x9f, 0xe9, 0x1b, 0x86, 0x2c, 0x17, 0xb9, 0xcc, 0x65, 0x0c, 0x73, 0x38,
+ 0xc7, 0xe6, 0x22, 0x19, 0x88, 0x98, 0x10, 0x48, 0x4a, 0x29, 0x85, 0x14,
+ 0x02, 0x89, 0x10, 0xa3, 0x1c, 0x0b, 0x31, 0xd6, 0xe6, 0x08, 0x69, 0x39,
+ 0x48, 0x44, 0xa0, 0x0d, 0x4a, 0x22, 0xa1, 0x94, 0x42, 0x0a, 0x01, 0x63,
+ 0x6d, 0x0e, 0x72, 0x18, 0x61, 0x8c, 0x74, 0x38, 0xc7, 0x26, 0x1c, 0xf3,
+ 0x71, 0x16, 0x15, 0x27, 0x6a, 0xc2, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x49,
+ 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ };
+
+ static unsigned int tamsyn10x20_png_len = 270;
+ static unsigned char tamsyn10x20_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
+ 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x0a,
+ 0x04, 0x03, 0x00, 0x00, 0x00, 0xc1, 0x66, 0x48, 0x96, 0x00, 0x00, 0x00,
+ 0x0f, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0xf9, 0x07, 0x00, 0x5d,
+ 0x71, 0xa5, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x49, 0xdb, 0xcb, 0x7f,
+ 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8,
+ 0x66, 0x00, 0x00, 0x00, 0xad, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0xa5,
+ 0x92, 0x4b, 0x0e, 0x03, 0x31, 0x08, 0x43, 0xdf, 0x82, 0x83, 0x79, 0xe1,
+ 0xfb, 0x9f, 0xa9, 0x0b, 0x3e, 0x61, 0xa6, 0x1f, 0x55, 0xad, 0x14, 0x31,
+ 0x66, 0x42, 0x1c, 0x70, 0x0c, 0xb6, 0x00, 0x01, 0xb6, 0x08, 0xdb, 0x00,
+ 0x8d, 0xc2, 0x14, 0xb2, 0x55, 0xa1, 0xfe, 0x09, 0xc2, 0x26, 0xdc, 0x25,
+ 0x75, 0x22, 0x97, 0x1a, 0x25, 0x77, 0x28, 0x31, 0x02, 0x80, 0xc8, 0xdd,
+ 0x2c, 0x11, 0x1a, 0x54, 0x9f, 0xc8, 0xa2, 0x8a, 0x06, 0xa9, 0x93, 0x22,
+ 0xbd, 0xd4, 0xd0, 0x0c, 0xcf, 0x81, 0x2b, 0xca, 0xbb, 0x83, 0xe0, 0x10,
+ 0xe6, 0xad, 0xff, 0x10, 0x2a, 0x66, 0x34, 0x41, 0x58, 0x35, 0x54, 0x49,
+ 0x5a, 0x63, 0xa5, 0xc2, 0x87, 0xab, 0x52, 0x76, 0x9a, 0xba, 0xc6, 0xf4,
+ 0x75, 0x7a, 0x9e, 0x3c, 0x46, 0x86, 0x5c, 0xa3, 0xfd, 0x87, 0x0e, 0x75,
+ 0x08, 0x7b, 0xee, 0x7e, 0xea, 0x21, 0x5c, 0x4f, 0xf6, 0xc5, 0xc8, 0x4b,
+ 0xb9, 0x11, 0xf2, 0xd6, 0xe1, 0x8f, 0x84, 0x62, 0x7b, 0x67, 0xf9, 0x24,
+ 0xde, 0x6d, 0xbc, 0xb2, 0xcd, 0xb1, 0xf3, 0xf2, 0x2f, 0xe8, 0xe2, 0xe4,
+ 0xae, 0x4b, 0x4f, 0xcf, 0x2b, 0xdc, 0x8d, 0x0d, 0xf0, 0x00, 0x8f, 0x22,
+ 0x26, 0x65, 0x75, 0x8a, 0xe6, 0x84, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
+ 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ };
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ Vector<uint8_t> hex_box_data;
+
+ Ref<Image> image;
+ image.instance();
+
+ Ref<ImageTexture> hex_code_image_tex[2];
+
+ hex_box_data.resize(tamsyn5x9_png_len);
+ memcpy(hex_box_data.ptrw(), tamsyn5x9_png, tamsyn5x9_png_len);
+ image->load_png_from_buffer(hex_box_data);
+ hex_code_image_tex[0].instance();
+ hex_code_image_tex[0]->create_from_image(image);
+ hex_code_box_font_tex[0].instance();
+ hex_code_box_font_tex[0]->set_diffuse_texture(hex_code_image_tex[0]);
+ hex_code_box_font_tex[0]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
+ hex_box_data.clear();
+
+ hex_box_data.resize(tamsyn10x20_png_len);
+ memcpy(hex_box_data.ptrw(), tamsyn10x20_png, tamsyn10x20_png_len);
+ image->load_png_from_buffer(hex_box_data);
+ hex_code_image_tex[1].instance();
+ hex_code_image_tex[1]->create_from_image(image);
+ hex_code_box_font_tex[1].instance();
+ hex_code_box_font_tex[1]->set_diffuse_texture(hex_code_image_tex[1]);
+ hex_code_box_font_tex[1]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
+ hex_box_data.clear();
+ }
+}
+
+void TextServer::finish_hex_code_box_fonts() {
+ if (hex_code_box_font_tex[0].is_valid()) {
+ hex_code_box_font_tex[0].unref();
+ }
+ if (hex_code_box_font_tex[1].is_valid()) {
+ hex_code_box_font_tex[1].unref();
+ }
+}
+
+Vector2 TextServer::get_hex_code_box_size(int p_size, char32_t p_index) const {
+ int fnt = (p_size < 20) ? 0 : 1;
+
+ float w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)) * hex_code_box_font_size[fnt].x;
+ float h = 2 * hex_code_box_font_size[fnt].y;
+ return Vector2(w + 4, h + 3 + 2 * hex_code_box_font_size[fnt].z);
+}
+
+void TextServer::draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const {
+ int fnt = (p_size < 20) ? 0 : 1;
+
+ ERR_FAIL_COND(hex_code_box_font_tex[fnt].is_null());
+
+ uint8_t a = p_index & 0x0F;
+ uint8_t b = (p_index >> 4) & 0x0F;
+ uint8_t c = (p_index >> 8) & 0x0F;
+ uint8_t d = (p_index >> 12) & 0x0F;
+ uint8_t e = (p_index >> 16) & 0x0F;
+ uint8_t f = (p_index >> 20) & 0x0F;
+
+ Vector2 pos = p_pos;
+ Rect2 dest = Rect2(Vector2(), Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y));
+
+ float w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)) * hex_code_box_font_size[fnt].x;
+ float h = 2 * hex_code_box_font_size[fnt].y;
+
+ pos.y -= Math::floor((h + 3 + hex_code_box_font_size[fnt].z) * 0.75);
+
+ RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(1, h + 2 + 2 * hex_code_box_font_size[fnt].z)), p_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(w + 2, 0), Size2(1, h + 2 + 2 * hex_code_box_font_size[fnt].z)), p_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(w + 2, 1)), p_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, h + 2 + 2 * hex_code_box_font_size[fnt].z), Size2(w + 2, 1)), p_color);
+
+ pos += Point2(2, 2);
+ if (p_index <= 0xFF) {
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ } else if (p_index <= 0xFFFF) {
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(d * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 0);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(c * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 1) + Point2(0, hex_code_box_font_size[fnt].z);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ } else {
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(f * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 0);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(e * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(2, 0);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(d * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(c * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 1) + Point2(0, hex_code_box_font_size[fnt].z);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(2, 1) + Point2(0, hex_code_box_font_size[fnt].z);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false);
+ }
+}
+
+Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<float> &p_width, int p_start, bool p_once, uint8_t /*TextBreakFlag*/ p_break_flags) const {
+ Vector<Vector2i> lines;
+
+ ERR_FAIL_COND_V(p_width.empty(), lines);
+
+ const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped);
+ const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
+ const Vector2i &range = shaped_text_get_range(p_shaped);
+
+ float width = 0.f;
+ int line_start = MAX(p_start, range.x);
+ int last_safe_break = -1;
+ int chunk = 0;
+ for (int i = 0; i < logical.size(); i++) {
+ if (logical[i].start < p_start) {
+ continue;
+ }
+ if (logical[i].count > 0) {
+ if ((p_width[chunk] > 0) && (width + logical[i].advance > p_width[chunk]) && (last_safe_break >= 0)) {
+ lines.push_back(Vector2i(line_start, logical[last_safe_break].end));
+ line_start = logical[last_safe_break].end;
+ i = last_safe_break;
+ last_safe_break = -1;
+ width = 0;
+ chunk++;
+ if (chunk >= p_width.size()) {
+ chunk = 0;
+ if (p_once) {
+ return lines;
+ }
+ }
+ continue;
+ }
+ if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) {
+ if ((logical[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
+ lines.push_back(Vector2i(line_start, logical[i].end));
+ line_start = logical[i].end;
+ last_safe_break = -1;
+ width = 0;
+ chunk = 0;
+ if (p_once) {
+ return lines;
+ }
+ continue;
+ }
+ }
+ if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) {
+ if ((logical[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ last_safe_break = i;
+ }
+ }
+ if ((p_break_flags & BREAK_GRAPHEME_BOUND) == BREAK_GRAPHEME_BOUND) {
+ last_safe_break = i;
+ }
+ }
+ width += logical[i].advance;
+ }
+
+ if (logical.size() > 0) {
+ lines.push_back(Vector2i(line_start, range.y));
+ } else {
+ lines.push_back(Vector2i(0, 0));
+ }
+
+ return lines;
+}
+
+Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint8_t /*TextBreakFlag*/ p_break_flags) const {
+ Vector<Vector2i> lines;
+
+ const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped);
+ const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
+ const Vector2i &range = shaped_text_get_range(p_shaped);
+
+ float width = 0.f;
+ int line_start = MAX(p_start, range.x);
+ int last_safe_break = -1;
+ for (int i = 0; i < logical.size(); i++) {
+ if (logical[i].start < p_start) {
+ continue;
+ }
+ if (logical[i].count > 0) {
+ if ((p_width > 0) && (width + logical[i].advance > p_width) && (last_safe_break >= 0)) {
+ lines.push_back(Vector2i(line_start, logical[last_safe_break].end));
+ line_start = logical[last_safe_break].end;
+ i = last_safe_break;
+ last_safe_break = -1;
+ width = 0;
+ continue;
+ }
+ if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) {
+ if ((logical[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
+ lines.push_back(Vector2i(line_start, logical[i].end));
+ line_start = logical[i].end;
+ last_safe_break = -1;
+ width = 0;
+ continue;
+ }
+ }
+ if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) {
+ if ((logical[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ last_safe_break = i;
+ }
+ }
+ if ((p_break_flags & BREAK_GRAPHEME_BOUND) == BREAK_GRAPHEME_BOUND) {
+ last_safe_break = i;
+ }
+ }
+ width += logical[i].advance;
+ }
+
+ if (logical.size() > 0) {
+ if (lines.size() == 0 || lines[lines.size() - 1].y < range.y) {
+ lines.push_back(Vector2i(line_start, range.y));
+ }
+ } else {
+ lines.push_back(Vector2i(0, 0));
+ }
+
+ return lines;
+}
+
+Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const {
+ Vector<Vector2i> words;
+
+ const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped);
+ const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
+ const Vector2i &range = shaped_text_get_range(p_shaped);
+
+ int word_start = range.x;
+ for (int i = 0; i < logical.size(); i++) {
+ if (logical[i].count > 0) {
+ if ((logical[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
+ words.push_back(Vector2i(word_start, logical[i].end - 1));
+ word_start = logical[i].end;
+ }
+ }
+ }
+ if (logical.size() > 0) {
+ words.push_back(Vector2i(word_start, range.y));
+ }
+
+ return words;
+}
+
+void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const {
+ Vector<Rect2> carets;
+ const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
+ TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
+ const Vector2 &range = shaped_text_get_range(p_shaped);
+ float ascent = shaped_text_get_ascent(p_shaped);
+ float descent = shaped_text_get_descent(p_shaped);
+ float height = (ascent + descent) / 2;
+
+ float off = 0.0f;
+ p_leading_dir = DIRECTION_AUTO;
+ p_trailing_dir = DIRECTION_AUTO;
+ for (int i = 0; i < glyphs.size(); i++) {
+ if (glyphs[i].count > 0) {
+ // Caret before grapheme (top / left).
+ if (p_position == glyphs[i].start && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) {
+ Rect2 cr;
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ if (glyphs[i].start == range.x) {
+ cr.size.y = height * 2;
+ } else {
+ cr.size.y = height;
+ }
+ cr.position.y = -ascent;
+ cr.position.x = off;
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ p_trailing_dir = DIRECTION_RTL;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat;
+ cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat;
+ }
+ } else {
+ p_trailing_dir = DIRECTION_LTR;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat;
+ }
+ }
+ } else {
+ if (glyphs[i].start == range.x) {
+ cr.size.x = height * 2;
+ } else {
+ cr.size.x = height;
+ }
+ cr.position.x = -ascent;
+ cr.position.y = off;
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ p_trailing_dir = DIRECTION_RTL;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat;
+ cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat;
+ }
+ } else {
+ p_trailing_dir = DIRECTION_LTR;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat;
+ }
+ }
+ }
+ p_trailing_caret = cr;
+ }
+ // Caret after grapheme (bottom / right).
+ if (p_position == glyphs[i].end && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) {
+ Rect2 cr;
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ if (glyphs[i].end == range.y) {
+ cr.size.y = height * 2;
+ cr.position.y = -ascent;
+ } else {
+ cr.size.y = height;
+ cr.position.y = -ascent + height;
+ }
+ cr.position.x = off;
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) {
+ p_leading_dir = DIRECTION_LTR;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat;
+ cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat;
+ }
+ } else {
+ p_leading_dir = DIRECTION_RTL;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat;
+ }
+ }
+ } else {
+ cr.size.y = 1.0f;
+ if (glyphs[i].end == range.y) {
+ cr.size.x = height * 2;
+ cr.position.x = -ascent;
+ } else {
+ cr.size.x = height;
+ cr.position.x = -ascent + height;
+ }
+ cr.position.y = off;
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) {
+ p_leading_dir = DIRECTION_LTR;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat;
+ cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat;
+ }
+ } else {
+ p_leading_dir = DIRECTION_RTL;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat;
+ }
+ }
+ }
+ p_leading_caret = cr;
+ }
+ // Caret inside grapheme (middle).
+ if (p_position > glyphs[i].start && p_position < glyphs[i].end && (glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL) {
+ float advance = 0.f;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ advance += glyphs[i + j].advance * glyphs[i + j].repeat;
+ }
+ float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start);
+ Rect2 cr;
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ cr.size.x = 1.0f;
+ cr.size.y = height * 2;
+ cr.position.y = -ascent;
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ cr.position.x = off + char_adv * (glyphs[i].end - p_position);
+ } else {
+ cr.position.x = off + char_adv * (p_position - glyphs[i].start);
+ }
+ } else {
+ cr.size.y = 1.0f;
+ cr.size.x = height * 2;
+ cr.position.x = -ascent;
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ cr.position.y = off + char_adv * (glyphs[i].end - p_position);
+ } else {
+ cr.position.y = off + char_adv * (p_position - glyphs[i].start);
+ }
+ }
+ p_trailing_caret = cr;
+ p_leading_caret = cr;
+ }
+ }
+ off += glyphs[i].advance * glyphs[i].repeat;
+ }
+}
+
+TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const {
+ const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
+
+ if (p_start == p_end) {
+ return DIRECTION_AUTO;
+ }
+
+ int start = MIN(p_start, p_end);
+ int end = MAX(p_start, p_end);
+
+ int rtl = 0;
+ int ltr = 0;
+
+ for (int i = 0; i < glyphs.size(); i++) {
+ if ((glyphs[i].end > start) && (glyphs[i].start < end)) {
+ if (glyphs[i].count > 0) {
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ rtl++;
+ } else {
+ ltr++;
+ }
+ }
+ }
+ }
+ if (ltr == rtl) {
+ return DIRECTION_AUTO;
+ } else if (ltr > rtl) {
+ return DIRECTION_LTR;
+ } else {
+ return DIRECTION_RTL;
+ }
+}
+
+Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const {
+ Vector<Vector2> ranges;
+ const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
+
+ if (p_start == p_end) {
+ return ranges;
+ }
+
+ int start = MIN(p_start, p_end);
+ int end = MAX(p_start, p_end);
+
+ float off = 0.0f;
+ for (int i = 0; i < glyphs.size(); i++) {
+ for (int k = 0; k < glyphs[i].repeat; k++) {
+ if (glyphs[i].count > 0 && glyphs[i].index != 0) {
+ if (glyphs[i].start < end && glyphs[i].end > start) {
+ // Grapheme fully in selection range.
+ if (glyphs[i].start >= start && glyphs[i].end <= end) {
+ float advance = 0.f;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ advance += glyphs[i + j].advance;
+ }
+ ranges.push_back(Vector2(off, off + advance));
+ }
+ // Only start of grapheme is in selection range.
+ if (glyphs[i].start >= start && glyphs[i].end > end) {
+ float advance = 0.f;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ advance += glyphs[i + j].advance;
+ }
+ float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start);
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - end), off + advance));
+ } else {
+ ranges.push_back(Vector2(off, off + char_adv * (end - glyphs[i].start)));
+ }
+ }
+ // Only end of grapheme is in selection range.
+ if (glyphs[i].start < start && glyphs[i].end <= end) {
+ float advance = 0.f;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ advance += glyphs[i + j].advance;
+ }
+ float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start);
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ ranges.push_back(Vector2(off, off + char_adv * (start - glyphs[i].start)));
+ } else {
+ ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - start), off + advance));
+ }
+ }
+ // Selection range is within grapheme
+ if (glyphs[i].start < start && glyphs[i].end > end) {
+ float advance = 0.f;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ advance += glyphs[i + j].advance;
+ }
+ float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start);
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - end), off + char_adv * (glyphs[i].end - start)));
+ } else {
+ ranges.push_back(Vector2(off + char_adv * (start - glyphs[i].start), off + char_adv * (end - glyphs[i].start)));
+ }
+ }
+ }
+ }
+ off += glyphs[i].advance;
+ }
+ }
+
+ // Merge intersecting ranges.
+ int i = 0;
+ while (i < ranges.size()) {
+ int j = i + 1;
+ while (j < ranges.size()) {
+ if (Math::is_equal_approx(ranges[i].y, ranges[j].x, UNIT_EPSILON)) {
+ ranges.write[i].y = ranges[j].y;
+ ranges.remove(j);
+ continue;
+ }
+ j++;
+ }
+ i++;
+ }
+
+ return ranges;
+}
+
+int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const {
+ const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
+
+ // Exact grapheme hit test, return -1 if missed.
+ float off = 0.0f;
+ for (int i = 0; i < glyphs.size(); i++) {
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ if (p_coords >= off && p_coords < off + glyphs[i].advance) {
+ return i;
+ }
+ off += glyphs[i].advance;
+ }
+ }
+ return -1;
+}
+
+int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) const {
+ const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
+
+ // Cursor placement hit test.
+
+ // Place caret to the left of the leftmost grapheme, or to position 0 if string is empty.
+ if (p_coords <= 0) {
+ if (glyphs.size() > 0) {
+ if ((glyphs[0].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ return glyphs[0].end;
+ } else {
+ return glyphs[0].start;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ // Place caret to the right of the rightmost grapheme, or to position 0 if string is empty.
+ if (p_coords >= shaped_text_get_width(p_shaped)) {
+ if (glyphs.size() > 0) {
+ if ((glyphs[glyphs.size() - 1].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ return glyphs[glyphs.size() - 1].start;
+ } else {
+ return glyphs[glyphs.size() - 1].end;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ float off = 0.0f;
+ for (int i = 0; i < glyphs.size(); i++) {
+ for (int k = 0; k < glyphs[i].repeat; k++) {
+ if (glyphs[i].count > 0) {
+ float advance = 0.f;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ advance += glyphs[i + j].advance;
+ }
+ // Place caret to the left of clicked grapheme.
+ if (p_coords >= off && p_coords < off + advance / 2) {
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ return glyphs[i].end;
+ } else {
+ return glyphs[i].start;
+ }
+ }
+ // Place caret to the right of clicked grapheme.
+ if (p_coords >= off + advance / 2 && p_coords < off + advance) {
+ if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
+ return glyphs[i].start;
+ } else {
+ return glyphs[i].end;
+ }
+ }
+ }
+ off += glyphs[i].advance;
+ }
+ }
+ return 0;
+}
+
+int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) {
+ const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
+ for (int i = 0; i < glyphs.size(); i++) {
+ if (p_pos >= glyphs[i].start && p_pos < glyphs[i].end) {
+ return glyphs[i].end;
+ }
+ }
+ return p_pos;
+}
+
+int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) {
+ const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
+ for (int i = 0; i < glyphs.size(); i++) {
+ if (p_pos > glyphs[i].start && p_pos <= glyphs[i].end) {
+ return glyphs[i].start;
+ }
+ }
+
+ return p_pos;
+}
+
+void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, const Color &p_color) const {
+ const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
+ TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
+ bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped);
+
+ Vector2 ofs = p_pos;
+ // Draw at the baseline.
+ for (int i = 0; i < glyphs.size(); i++) {
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ if (p_clip_r > 0) {
+ // Clip right / bottom.
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ if (ofs.x - p_pos.x > p_clip_r) {
+ return;
+ }
+ } else {
+ if (ofs.y - p_pos.y > p_clip_r) {
+ return;
+ }
+ }
+ }
+ if (p_clip_l > 0) {
+ // Clip left / top.
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ if (ofs.x - p_pos.x < p_clip_l) {
+ ofs.x += glyphs[i].advance;
+ continue;
+ }
+ } else {
+ if (ofs.y - p_pos.y < p_clip_l) {
+ ofs.y += glyphs[i].advance;
+ continue;
+ }
+ }
+ }
+ if (glyphs[i].font_rid != RID()) {
+ font_draw_glyph(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color);
+ } else if (hex_codes && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) {
+ TextServer::draw_hex_code_box(p_canvas, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color);
+ }
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += glyphs[i].advance;
+ } else {
+ ofs.y += glyphs[i].advance;
+ }
+ }
+ }
+}
+
+void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, int p_outline_size, const Color &p_color) const {
+ const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
+ TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
+
+ Vector2 ofs = p_pos;
+ // Draw at the baseline.
+ for (int i = 0; i < glyphs.size(); i++) {
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ if (p_clip_r > 0) {
+ // Clip right / bottom.
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ if (ofs.x - p_pos.x > p_clip_r) {
+ return;
+ }
+ } else {
+ if (ofs.y - p_pos.y > p_clip_r) {
+ return;
+ }
+ }
+ }
+ if (p_clip_l > 0) {
+ // Clip left / top.
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ if (ofs.x - p_pos.x < p_clip_l) {
+ ofs.x += glyphs[i].advance;
+ continue;
+ }
+ } else {
+ if (ofs.y - p_pos.y < p_clip_l) {
+ ofs.y += glyphs[i].advance;
+ continue;
+ }
+ }
+ }
+ if (glyphs[i].font_rid != RID()) {
+ font_draw_glyph_outline(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, p_outline_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color);
+ }
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += glyphs[i].advance;
+ } else {
+ ofs.y += glyphs[i].advance;
+ }
+ }
+ }
+}
+
+RID TextServer::_create_font_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size) {
+ return create_font_memory(p_data.ptr(), p_data.size(), p_type, p_base_size);
+}
+
+void TextServer::_shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
+ Vector<Vector2i> overrides;
+ for (int i = 0; i < p_override.size(); i++) {
+ overrides.push_back(p_override[i]);
+ }
+ shaped_text_set_bidi_override(p_shaped, overrides);
+}
+
+Array TextServer::_shaped_text_get_glyphs(RID p_shaped) const {
+ Array ret;
+
+ Vector<Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
+ for (int i = 0; i < glyphs.size(); i++) {
+ Dictionary glyph;
+
+ glyph["start"] = glyphs[i].start;
+ glyph["end"] = glyphs[i].end;
+ glyph["repeat"] = glyphs[i].repeat;
+ glyph["count"] = glyphs[i].count;
+ glyph["flags"] = glyphs[i].flags;
+ glyph["offset"] = Vector2(glyphs[i].x_off, glyphs[i].y_off);
+ glyph["advance"] = glyphs[i].advance;
+ glyph["font_rid"] = glyphs[i].font_rid;
+ glyph["font_size"] = glyphs[i].font_size;
+ glyph["index"] = glyphs[i].index;
+
+ ret.push_back(glyph);
+ }
+
+ return ret;
+}
+
+Array TextServer::_shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint8_t p_break_flags) const {
+ Array ret;
+
+ Vector<Vector2i> lines = shaped_text_get_line_breaks_adv(p_shaped, p_width, p_start, p_once, p_break_flags);
+ for (int i = 0; i < lines.size(); i++) {
+ ret.push_back(lines[i]);
+ }
+
+ return ret;
+}
+
+Array TextServer::_shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint8_t p_break_flags) const {
+ Array ret;
+
+ Vector<Vector2i> lines = shaped_text_get_line_breaks(p_shaped, p_width, p_start, p_break_flags);
+ for (int i = 0; i < lines.size(); i++) {
+ ret.push_back(lines[i]);
+ }
+
+ return ret;
+}
+
+Array TextServer::_shaped_text_get_word_breaks(RID p_shaped) const {
+ Array ret;
+
+ Vector<Vector2i> words = shaped_text_get_word_breaks(p_shaped);
+ for (int i = 0; i < words.size(); i++) {
+ ret.push_back(words[i]);
+ }
+
+ return ret;
+}
+
+Dictionary TextServer::_shaped_text_get_carets(RID p_shaped, int p_position) const {
+ Dictionary ret;
+
+ Rect2 l_caret, t_caret;
+ Direction l_dir, t_dir;
+ shaped_text_get_carets(p_shaped, p_position, l_caret, l_dir, t_caret, t_dir);
+
+ ret["leading_rect"] = l_caret;
+ ret["leading_direction"] = l_dir;
+ ret["trailing_rect"] = t_caret;
+ ret["trailing_direction"] = t_dir;
+
+ return ret;
+}
+
+Array TextServer::_shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const {
+ Array ret;
+
+ Vector<Vector2> ranges = shaped_text_get_selection(p_shaped, p_start, p_end);
+ for (int i = 0; i < ranges.size(); i++) {
+ ret.push_back(ranges[i]);
+ }
+
+ return ret;
+}
+
+TextServer::TextServer() {
+}
+
+TextServer::~TextServer() {
+}
diff --git a/servers/text_server.h b/servers/text_server.h
index e69de29bb2..6796b7f1d6 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -0,0 +1,453 @@
+/*************************************************************************/
+/* text_server.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEXT_SERVER_H
+#define TEXT_SERVER_H
+
+#include "core/object/reference.h"
+#include "core/os/os.h"
+#include "core/templates/rid.h"
+#include "core/variant/variant.h"
+#include "scene/resources/texture.h"
+
+class CanvasTexture;
+
+class TextServer : public Object {
+ GDCLASS(TextServer, Object);
+
+public:
+ enum Direction {
+ DIRECTION_AUTO,
+ DIRECTION_LTR,
+ DIRECTION_RTL
+ };
+
+ enum Orientation {
+ ORIENTATION_HORIZONTAL,
+ ORIENTATION_VERTICAL
+ };
+
+ enum JustificationFlag {
+ JUSTIFICATION_NONE = 0,
+ JUSTIFICATION_KASHIDA = 1 << 0,
+ JUSTIFICATION_WORD_BOUND = 1 << 1,
+ JUSTIFICATION_TRIM_EDGE_SPACES = 1 << 2,
+ JUSTIFICATION_AFTER_LAST_TAB = 1 << 3
+ };
+
+ enum LineBreakFlag {
+ BREAK_NONE = 0,
+ BREAK_MANDATORY = 1 << 4,
+ BREAK_WORD_BOUND = 1 << 5,
+ BREAK_GRAPHEME_BOUND = 1 << 6
+ //RESERVED = 1 << 7
+ };
+
+ enum GraphemeFlag {
+ GRAPHEME_IS_VALID = 1 << 0, // Glyph is valid.
+ GRAPHEME_IS_RTL = 1 << 1, // Glyph is right-to-left.
+ GRAPHEME_IS_VIRTUAL = 1 << 2, // Glyph is not part of source string (added by fit_to_width function, do not affect caret movement).
+ GRAPHEME_IS_SPACE = 1 << 3, // Is whitespace (for justification).
+ GRAPHEME_IS_BREAK_HARD = 1 << 4, // Is line break (mandatory break, e.g "\n")
+ GRAPHEME_IS_BREAK_SOFT = 1 << 5, // Is line break (optional break, e.g space)
+ GRAPHEME_IS_TAB = 1 << 6, // Is tab or vertical tab
+ GRAPHEME_IS_ELONGATION = 1 << 7 // Elongation (e.g kashida), glyph can be duplicated or truncated to fit line to width.
+ };
+
+ enum Hinting {
+ HINTING_NONE,
+ HINTING_LIGHT,
+ HINTING_NORMAL
+ };
+
+ enum Feature {
+ FEATURE_BIDI_LAYOUT = 1 << 0,
+ FEATURE_VERTICAL_LAYOUT = 1 << 1,
+ FEATURE_SHAPING = 1 << 2,
+ FEATURE_KASHIDA_JUSTIFICATION = 1 << 3,
+ FEATURE_BREAK_ITERATORS = 1 << 4,
+ FEATURE_FONT_SYSTEM = 1 << 5,
+ FEATURE_USE_SUPPORT_DATA = 1 << 6
+ };
+
+ struct Glyph {
+ int start = -1; // Start offset in the source string.
+ int end = -1; // End offset in the source string.
+
+ uint8_t count = 0; // Number of glyphs in the grapheme, set in the first glyph only.
+ uint8_t repeat = 1; // Draw multiple times in the row.
+ uint8_t flags = 0; // Grapheme flags (valid, rtl, virtual), set in the first glyph only.
+
+ float x_off = 0.f; // Offset from the origin of the glyph on baseline.
+ float y_off = 0.f;
+ float advance = 0.f; // Advance to the next glyph along baseline(x for horizontal layout, y for vertical).
+
+ RID font_rid; // Font resource.
+ int font_size = 0; // Font size;
+ uint32_t index = 0; // Glyph index (font specific) or UTF-32 codepoint (for the invalid glyphs).
+
+ bool operator==(const Glyph &p_a) const;
+ bool operator!=(const Glyph &p_a) const;
+
+ bool operator<(const Glyph &p_a) const;
+ bool operator>(const Glyph &p_a) const;
+ };
+
+ struct GlyphCompare { // For line breaking reordering.
+ _FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const {
+ if (l.start == r.start) {
+ if (l.count == r.count) {
+ if ((l.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ return l.count > r.count; // Sort first glyoh with count & flags, order of the rest are irrelevant.
+ } else {
+ return l.start < r.start;
+ }
+ }
+ };
+
+ struct ShapedTextData {
+ /* Source data */
+ RID parent; // Substring parent ShapedTextData.
+
+ int start = 0; // Substring start offset in the parent string.
+ int end = 0; // Substring end offset in the parent string.
+
+ String text;
+ 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;
+ VAlign inline_align = VALIGN_TOP;
+ Rect2 rect;
+ };
+ Map<Variant, EmbeddedObject> objects;
+
+ /* Shaped data */
+ TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction.
+ bool valid = false; // String is shaped.
+ bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted).
+ bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string.
+ bool sort_valid = false;
+
+ bool preserve_invalid = true; // Draw hex code box instead of missing characters.
+ bool preserve_control = false; // Draw control characters.
+
+ float ascent = 0.f; // Ascent for horizontal layout, 1/2 of width for vertical.
+ float descent = 0.f; // Descent for horizontal layout, 1/2 of width for vertical.
+ float width = 0.f; // Width for horizontal layout, height for vertical.
+
+ float upos = 0.f;
+ float uthk = 0.f;
+
+ Vector<TextServer::Glyph> glyphs;
+ Vector<TextServer::Glyph> glyphs_logical;
+ };
+
+ struct BitmapFontData {
+ int height = 0;
+ int ascent = 0;
+ int charcount = 0;
+ const int *char_rects = nullptr;
+ int kerning_count = 0;
+ const int *kernings = nullptr;
+ int w = 0;
+ int h = 0;
+ const unsigned char *img = nullptr;
+ };
+
+protected:
+ static void _bind_methods();
+
+ static Vector3 hex_code_box_font_size[2];
+ static Ref<CanvasTexture> hex_code_box_font_tex[2];
+
+public:
+ static void initialize_hex_code_box_fonts();
+ static void finish_hex_code_box_fonts();
+
+ virtual bool has_feature(Feature p_feature) = 0;
+ virtual String get_name() const = 0;
+
+ virtual void free(RID p_rid) = 0;
+ virtual bool has(RID p_rid) = 0;
+ virtual bool load_support_data(const String &p_filename) = 0;
+
+#ifdef TOOLS_ENABLED
+ virtual String get_support_data_filename() = 0;
+ virtual String get_support_data_info() = 0;
+ virtual bool save_support_data(const String &p_filename) = 0;
+#endif
+
+ virtual bool is_locale_right_to_left(const String &p_locale) = 0;
+
+ virtual int32_t name_to_tag(const String &p_name) { return 0; };
+ virtual String tag_to_name(int32_t p_tag) { return ""; };
+
+ /* Font interface */
+ virtual RID create_font_system(const String &p_name, int p_base_size = 16) = 0;
+ virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) = 0;
+ virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) = 0;
+
+ virtual float font_get_height(RID p_font, int p_size) const = 0;
+ virtual float font_get_ascent(RID p_font, int p_size) const = 0;
+ virtual float font_get_descent(RID p_font, int p_size) const = 0;
+
+ virtual float font_get_underline_position(RID p_font, int p_size) const = 0;
+ virtual float font_get_underline_thickness(RID p_font, int p_size) const = 0;
+
+ virtual void font_set_antialiased(RID p_font, bool p_antialiased) = 0;
+ virtual bool font_get_antialiased(RID p_font) const = 0;
+
+ virtual Dictionary font_get_feature_list(RID p_font) const { return Dictionary(); };
+
+ virtual void font_set_distance_field_hint(RID p_font, bool p_distance_field) = 0;
+ virtual bool font_get_distance_field_hint(RID p_font) const = 0;
+
+ virtual void font_set_hinting(RID p_font, Hinting p_hinting) = 0;
+ virtual Hinting font_get_hinting(RID p_font) const = 0;
+
+ virtual void font_set_force_autohinter(RID p_font, bool p_enabeld) = 0;
+ virtual bool font_get_force_autohinter(RID p_font) const = 0;
+
+ virtual bool font_has_char(RID p_font, char32_t p_char) const = 0;
+ virtual String font_get_supported_chars(RID p_font) const = 0;
+
+ virtual bool font_has_outline(RID p_font) const = 0;
+ virtual float font_get_base_size(RID p_font) const = 0;
+
+ virtual bool font_is_language_supported(RID p_font, const String &p_language) const = 0;
+ virtual void font_set_language_support_override(RID p_font, const String &p_language, bool p_supported) = 0;
+ virtual bool font_get_language_support_override(RID p_font, const String &p_language) = 0;
+ virtual void font_remove_language_support_override(RID p_font, const String &p_language) = 0;
+ virtual Vector<String> font_get_language_support_overrides(RID p_font) = 0;
+
+ virtual bool font_is_script_supported(RID p_font, const String &p_script) const = 0;
+ virtual void font_set_script_support_override(RID p_font, const String &p_script, bool p_supported) = 0;
+ virtual bool font_get_script_support_override(RID p_font, const String &p_script) = 0;
+ virtual void font_remove_script_support_override(RID p_font, const String &p_script) = 0;
+ virtual Vector<String> font_get_script_support_overrides(RID p_font) = 0;
+
+ virtual uint32_t font_get_glyph_index(RID p_font, char32_t p_char, char32_t p_variation_selector = 0x0000) const = 0;
+ virtual Vector2 font_get_glyph_advance(RID p_font, uint32_t p_index, int p_size) const = 0;
+ virtual Vector2 font_get_glyph_kerning(RID p_font, uint32_t p_index_a, uint32_t p_index_b, int p_size) const = 0;
+
+ virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0;
+ virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0;
+
+ virtual float font_get_oversampling() const = 0;
+ virtual void font_set_oversampling(float p_oversampling) = 0;
+
+ Vector2 get_hex_code_box_size(int p_size, char32_t p_index) const;
+ void draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const;
+
+ virtual Vector<String> get_system_fonts() const = 0;
+
+ /* Shaped text buffer interface */
+
+ virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) = 0;
+
+ virtual void shaped_text_clear(RID p_shaped) = 0;
+
+ virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) = 0;
+ virtual Direction shaped_text_get_direction(RID p_shaped) const = 0;
+
+ virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) = 0;
+
+ virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) = 0;
+ virtual Orientation shaped_text_get_orientation(RID p_shaped) const = 0;
+
+ virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) = 0;
+ virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const = 0;
+
+ 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_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) = 0;
+ virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) = 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;
+
+ virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) = 0;
+ virtual float shaped_text_tab_align(RID p_shaped, const Vector<float> &p_tab_stops) = 0;
+
+ virtual bool shaped_text_shape(RID p_shaped) = 0;
+ virtual bool shaped_text_update_breaks(RID p_shaped) = 0;
+ virtual bool shaped_text_update_justification_ops(RID p_shaped) = 0;
+
+ virtual bool shaped_text_is_ready(RID p_shaped) const = 0;
+
+ virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const = 0;
+
+ virtual Vector2i shaped_text_get_range(RID p_shaped) const = 0;
+
+ virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) = 0;
+
+ virtual Vector<Vector2i> shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<float> &p_width, int p_start = 0, bool p_once = true, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const;
+ virtual Vector<Vector2i> shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start = 0, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const;
+ virtual Vector<Vector2i> shaped_text_get_word_breaks(RID p_shaped) const;
+ virtual Array shaped_text_get_objects(RID p_shaped) const = 0;
+ virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const = 0;
+
+ virtual Size2 shaped_text_get_size(RID p_shaped) const = 0;
+ virtual float shaped_text_get_ascent(RID p_shaped) const = 0;
+ virtual float shaped_text_get_descent(RID p_shaped) const = 0;
+ virtual float shaped_text_get_width(RID p_shaped) const = 0;
+ virtual float shaped_text_get_underline_position(RID p_shaped) const = 0;
+ virtual float shaped_text_get_underline_thickness(RID p_shaped) const = 0;
+
+ virtual Direction shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const;
+
+ virtual void shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const;
+ virtual Vector<Vector2> shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const;
+
+ virtual int shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const; // Return grapheme index.
+ virtual int shaped_text_hit_test_position(RID p_shaped, float p_coords) const; // Return caret/selection position.
+
+ virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos);
+ virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos);
+
+ // The pen position is always placed on the baseline and moveing left to right.
+ virtual void shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, const Color &p_color = Color(1, 1, 1)) const;
+ virtual void shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const;
+
+ // Number conversion.
+ virtual String format_number(const String &p_string, const String &p_language = "") const { return p_string; };
+ virtual String parse_number(const String &p_string, const String &p_language = "") const { return p_string; };
+ virtual String percent_sign(const String &p_language = "") const { return "%"; };
+
+ /* GDScript wrappers */
+ RID _create_font_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size = 16);
+
+ Array _shaped_text_get_glyphs(RID p_shaped) const;
+ Dictionary _shaped_text_get_carets(RID p_shaped, int p_position) const;
+
+ void _shaped_text_set_bidi_override(RID p_shaped, const Array &p_override);
+
+ Array _shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint8_t p_break_flags) const;
+ Array _shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint8_t p_break_flags) const;
+ Array _shaped_text_get_word_breaks(RID p_shaped) const;
+
+ Array _shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const;
+
+ TextServer();
+ ~TextServer();
+};
+
+/*************************************************************************/
+
+class TextServerManager : public Object {
+ GDCLASS(TextServerManager, Object);
+
+public:
+ typedef TextServer *(*CreateFunction)(Error &r_error, void *p_user_data);
+
+protected:
+ static void _bind_methods();
+
+private:
+ static TextServerManager *singleton;
+ static TextServer *server;
+ enum {
+ MAX_SERVERS = 64
+ };
+
+ struct TextServerCreate {
+ String name;
+ CreateFunction create_function = nullptr;
+ uint32_t features = 0;
+ TextServer *instance = nullptr;
+ void *user_data = nullptr;
+ };
+
+ static TextServerCreate server_create_functions[MAX_SERVERS];
+ static int server_create_count;
+
+public:
+ _FORCE_INLINE_ static TextServerManager *get_singleton() {
+ return singleton;
+ }
+
+ static void register_create_function(const String &p_name, uint32_t p_features, CreateFunction p_function, void *p_user_data);
+ static int get_interface_count();
+ static String get_interface_name(int p_index);
+ static uint32_t get_interface_features(int p_index);
+ static TextServer *initialize(int p_index, Error &r_error);
+ static TextServer *get_primary_interface();
+
+ /* GDScript wrappers */
+ int _get_interface_count() const;
+ String _get_interface_name(int p_index) const;
+ uint32_t _get_interface_features(int p_index) const;
+ TextServer *_get_interface(int p_index) const;
+ Array _get_interfaces() const;
+ TextServer *_find_interface(const String &p_name) const;
+
+ bool _set_primary_interface(int p_index);
+ TextServer *_get_primary_interface() const;
+
+ TextServerManager();
+ ~TextServerManager();
+};
+
+/*************************************************************************/
+
+#define TS TextServerManager::get_primary_interface()
+
+VARIANT_ENUM_CAST(TextServer::Direction);
+VARIANT_ENUM_CAST(TextServer::Orientation);
+VARIANT_ENUM_CAST(TextServer::JustificationFlag);
+VARIANT_ENUM_CAST(TextServer::LineBreakFlag);
+VARIANT_ENUM_CAST(TextServer::GraphemeFlag);
+VARIANT_ENUM_CAST(TextServer::Hinting);
+VARIANT_ENUM_CAST(TextServer::Feature);
+
+#endif // TEXT_SERVER_H