diff --git a/source/blender/draw/engines/overlay/overlay_attribute_text.hh b/source/blender/draw/engines/overlay/overlay_attribute_text.hh index 15c7ee685d9..f3425c7c984 100644 --- a/source/blender/draw/engines/overlay/overlay_attribute_text.hh +++ b/source/blender/draw/engines/overlay/overlay_attribute_text.hh @@ -19,9 +19,13 @@ #include "BKE_curves.hh" #include "BKE_geometry_set.hh" #include "BKE_instances.hh" +#include "BKE_mesh.hh" #include "DRW_render.hh" +#include "ED_view3d.hh" + +#include "UI_interface_c.hh" #include "UI_resources.hh" #include "draw_manager_text.hh" @@ -72,7 +76,7 @@ class AttributeTexts : Overlay { switch (object.type) { case OB_MESH: { const Mesh &mesh = DRW_object_get_data_for_drawing(object); - add_attributes_to_text_cache(dt, mesh.attributes(), object_to_world); + add_mesh_attributes_to_text_cache(state, mesh, object_to_world); break; } case OB_POINTCLOUD: { @@ -113,6 +117,63 @@ class AttributeTexts : Overlay { add_values_to_text_cache(dt, attribute.varray, positions, object_to_world); } + void add_mesh_attributes_to_text_cache(const State &state, + const Mesh &mesh, + const float4x4 &object_to_world) + { + const bke::AttributeAccessor attributes = mesh.attributes(); + if (!attributes.contains(".viewer")) { + return; + } + + const bke::GAttributeReader attribute = attributes.lookup(".viewer"); + const bke::AttrDomain domain = attribute.domain; + const VArraySpan positions = *attributes.lookup("position", domain); + + if (domain == bke::AttrDomain::Corner) { + const CPPType &type = attribute.varray.type(); + float offset_by_type = 1.0f; + if (type.is() || type.is() || type.is() || + type.is() || type.is() || type.is()) + { + offset_by_type = 1.5f; + } + else if (type.is()) { + offset_by_type = 3.0f; + } + + Array corner_positions(positions.size()); + const Span positions = mesh.vert_positions(); + const OffsetIndices faces = mesh.faces(); + const Span corner_verts = mesh.corner_verts(); + const Span face_normals = mesh.face_normals(); + + threading::parallel_for(faces.index_range(), 512, [&](const IndexRange range) { + for (const int face_index : range) { + const float3 &face_normal = face_normals[face_index]; + const IndexRange face = faces[face_index]; + for (const int corner : face) { + const int corner_prev = bke::mesh::face_corner_prev(face, corner); + const int corner_next = bke::mesh::face_corner_next(face, corner); + corner_positions[corner] = calc_corner_text_position( + positions[corner_verts[corner]], + positions[corner_verts[corner_prev]], + positions[corner_verts[corner_next]], + face_normal, + state.rv3d, + object_to_world, + offset_by_type); + } + } + }); + add_values_to_text_cache( + state.dt, attribute.varray, corner_positions.as_span(), object_to_world); + } + else { + add_values_to_text_cache(state.dt, attribute.varray, positions, object_to_world); + } + } + void add_instance_attributes_to_text_cache(DRWTextStore *dt, bke::AttributeAccessor attribute_accessor, const float4x4 &object_to_world, @@ -148,6 +209,9 @@ class AttributeTexts : Overlay { const Span lines, const uchar4 &color) { + const float text_size = UI_style_get()->widget.points; + const float line_height = text_size * 1.1f * UI_SCALE_FAC; + const float center_offset = (lines.size() - 1) / 2.0f; for (const int i : lines.index_range()) { const StringRef line = lines[i]; DRW_text_cache_add(dt, @@ -155,7 +219,7 @@ class AttributeTexts : Overlay { line.data(), line.size(), 0, - -i * 12.0f * UI_SCALE_FAC, + (center_offset - i) * line_height, DRW_TEXT_CACHE_GLOBALSPACE, color, true, @@ -194,9 +258,11 @@ class AttributeTexts : Overlay { add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col); } else if constexpr (std::is_same_v) { - char numstr[64]; - const size_t numstr_len = SNPRINTF_UTF8_RLEN(numstr, "(%d, %d)", value.x, value.y); - add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col); + char x_str[64], y_str[64]; + const size_t x_str_len = SNPRINTF_UTF8_RLEN(x_str, "X: %d", value.x); + const size_t y_str_len = SNPRINTF_UTF8_RLEN(y_str, "Y: %d", value.y); + add_lines_to_cache( + dt, position, {StringRef(x_str, x_str_len), StringRef(y_str, y_str_len)}, col); } else if constexpr (std::is_same_v) { char numstr[64]; @@ -204,34 +270,66 @@ class AttributeTexts : Overlay { add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col); } else if constexpr (std::is_same_v) { - char numstr[64]; - const size_t numstr_len = SNPRINTF_UTF8_RLEN(numstr, "(%g, %g)", value.x, value.y); - add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col); + char x_str[64], y_str[64]; + const size_t x_str_len = SNPRINTF_UTF8_RLEN(x_str, "X: %g", value.x); + const size_t y_str_len = SNPRINTF_UTF8_RLEN(y_str, "Y: %g", value.y); + add_lines_to_cache( + dt, position, {StringRef(x_str, x_str_len), StringRef(y_str, y_str_len)}, col); } else if constexpr (std::is_same_v) { - char numstr[64]; - const size_t numstr_len = SNPRINTF_UTF8_RLEN( - numstr, "(%g, %g, %g)", value.x, value.y, value.z); - add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col); + char x_str[64], y_str[64], z_str[64]; + const size_t x_str_len = SNPRINTF_UTF8_RLEN(x_str, "X: %g", value.x); + const size_t y_str_len = SNPRINTF_UTF8_RLEN(y_str, "Y: %g", value.y); + const size_t z_str_len = SNPRINTF_UTF8_RLEN(z_str, "Z: %g", value.z); + add_lines_to_cache(dt, + position, + {StringRef(x_str, x_str_len), + StringRef(y_str, y_str_len), + StringRef(z_str, z_str_len)}, + col); } else if constexpr (std::is_same_v) { const ColorGeometry4f color = color::decode(value); - char numstr[64]; - const size_t numstr_len = SNPRINTF_UTF8_RLEN( - numstr, "(%.3f, %.3f, %.3f, %.3f)", color.r, color.g, color.b, color.a); - add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col); + char r_str[64], g_str[64], b_str[64], a_str[64]; + const size_t r_str_len = SNPRINTF_UTF8_RLEN(r_str, "R: %.3f", color.r); + const size_t g_str_len = SNPRINTF_UTF8_RLEN(g_str, "G: %.3f", color.g); + const size_t b_str_len = SNPRINTF_UTF8_RLEN(b_str, "B: %.3f", color.b); + const size_t a_str_len = SNPRINTF_UTF8_RLEN(a_str, "A: %.3f", color.a); + add_lines_to_cache(dt, + position, + {StringRef(r_str, r_str_len), + StringRef(g_str, g_str_len), + StringRef(b_str, b_str_len), + StringRef(a_str, a_str_len)}, + col); } else if constexpr (std::is_same_v) { - char numstr[64]; - const size_t numstr_len = SNPRINTF_UTF8_RLEN( - numstr, "(%.3f, %.3f, %.3f, %.3f)", value.r, value.g, value.b, value.a); - add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col); + char r_str[64], g_str[64], b_str[64], a_str[64]; + const size_t r_str_len = SNPRINTF_UTF8_RLEN(r_str, "R: %.3f", value.r); + const size_t g_str_len = SNPRINTF_UTF8_RLEN(g_str, "G: %.3f", value.g); + const size_t b_str_len = SNPRINTF_UTF8_RLEN(b_str, "B: %.3f", value.b); + const size_t a_str_len = SNPRINTF_UTF8_RLEN(a_str, "A: %.3f", value.a); + add_lines_to_cache(dt, + position, + {StringRef(r_str, r_str_len), + StringRef(g_str, g_str_len), + StringRef(b_str, b_str_len), + StringRef(a_str, a_str_len)}, + col); } else if constexpr (std::is_same_v) { - char numstr[64]; - const size_t numstr_len = SNPRINTF_UTF8_RLEN( - numstr, "(%.3f, %.3f, %.3f, %.3f)", value.w, value.x, value.y, value.z); - add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col); + char w_str[64], x_str[64], y_str[64], z_str[64]; + const size_t w_str_len = SNPRINTF_UTF8_RLEN(w_str, "W: %.3f", value.w); + const size_t x_str_len = SNPRINTF_UTF8_RLEN(x_str, "X: %.3f", value.x); + const size_t y_str_len = SNPRINTF_UTF8_RLEN(y_str, "Y: %.3f", value.y); + const size_t z_str_len = SNPRINTF_UTF8_RLEN(z_str, "Z: %.3f", value.z); + add_lines_to_cache(dt, + position, + {StringRef(w_str, w_str_len), + StringRef(x_str, x_str_len), + StringRef(y_str, y_str_len), + StringRef(z_str, z_str_len)}, + col); } else if constexpr (std::is_same_v) { float3 location; @@ -264,6 +362,42 @@ class AttributeTexts : Overlay { } }); } + + static float3 calc_corner_text_position(const float3 &corner_pos, + const float3 &prev_corner_pos, + const float3 &next_corner_pos, + const float3 &face_normal, + const RegionView3D *rv3d, + const float4x4 &object_to_world, + const float offset_scale = 1.0f) + { + const float3 prev_edge_vec = prev_corner_pos - corner_pos; + const float3 next_edge_vec = next_corner_pos - corner_pos; + const float3 prev_edge_dir = math::normalize(prev_edge_vec); + const float3 next_edge_dir = math::normalize(next_edge_vec); + + const float pre_edge_len = math::length(prev_edge_vec); + const float next_edge_len = math::length(next_edge_vec); + const float max_offset = math::min(pre_edge_len, next_edge_len) / 2; + + const float3 corner_normal = math::cross(next_edge_dir, prev_edge_dir); + const float concavity_check = math::dot(corner_normal, face_normal); + const float direction_correct = concavity_check > 0.0f ? 1.0f : -1.0f; + const float3 bisector_dir = (prev_edge_dir + next_edge_dir) / 2 * direction_correct; + + const float sharp_factor = std::clamp(math::dot(prev_edge_dir, next_edge_dir), 0.0f, 1.0f); + const float sharp_multiplier = math::pow(sharp_factor, 4.0f) * 2 + 1; + + const float3 pos_o_world = math::transform_point(object_to_world, corner_pos); + const float pixel_size = ED_view3d_pixel_size(rv3d, pos_o_world); + const float pixel_offset = UI_style_get()->widget.points * 7.0f * UI_SCALE_FAC; + const float screen_space_offset = pixel_size * pixel_offset; + + const float offset_distance = std::clamp( + screen_space_offset * sharp_multiplier * offset_scale, 0.0f, max_offset); + + return corner_pos + bisector_dir * offset_distance; + } }; } // namespace blender::draw::overlay