45 enabled_ = !res.is_selection() &&
state.show_attribute_viewer_text();
57 const Object &
object = *ob_ref.object;
58 const bool is_preview = ob_ref.preview_base_geometry() !=
nullptr;
64 const float4x4 &object_to_world =
object.object_to_world();
66 if (ob_ref.preview_instance_index() >= 0) {
67 const bke::Instances *instances = ob_ref.preview_base_geometry()->get_instances();
69 add_instance_attributes_to_text_cache(
70 dt, instances->
attributes(), object_to_world, ob_ref.preview_instance_index());
76 switch (
object.type) {
79 add_mesh_attributes_to_text_cache(
state, mesh, object_to_world);
84 add_attributes_to_text_cache(dt, pointcloud.
attributes(), object_to_world);
91 add_attributes_to_text_cache(dt, curves.
attributes(), object_to_world);
98 add_attributes_to_text_cache(dt, curves.
attributes(), object_to_world);
109 if (!attribute_accessor.
contains(
".viewer")) {
117 add_values_to_text_cache(dt, attribute.
varray, positions, object_to_world);
120 void add_mesh_attributes_to_text_cache(
const State &
state,
125 if (!attributes.
contains(
".viewer")) {
129 const bke::GAttributeReader attribute = attributes.
lookup(
".viewer");
131 const VArraySpan<float3> positions = *attributes.
lookup<
float3>(
"position", domain);
134 const CPPType &type = attribute.varray.type();
135 float offset_by_type = 1.0f;
139 offset_by_type = 1.5f;
142 offset_by_type = 3.0f;
145 Array<float3> corner_positions(positions.size());
146 const Span<float3> positions = mesh.vert_positions();
147 const OffsetIndices<int>
faces = mesh.faces();
148 const Span<int> corner_verts = mesh.corner_verts();
149 const Span<float3> face_normals = mesh.face_normals();
152 for (const int face_index : range) {
153 const float3 &face_normal = face_normals[face_index];
154 const IndexRange face = faces[face_index];
155 for (const int corner : face) {
156 const int corner_prev = bke::mesh::face_corner_prev(face, corner);
157 const int corner_next = bke::mesh::face_corner_next(face, corner);
158 corner_positions[corner] = calc_corner_text_position(
159 positions[corner_verts[corner]],
160 positions[corner_verts[corner_prev]],
161 positions[corner_verts[corner_next]],
169 add_values_to_text_cache(
170 state.dt, attribute.varray, corner_positions.as_span(), object_to_world);
173 add_values_to_text_cache(
state.dt, attribute.varray, positions, object_to_world);
177 void add_instance_attributes_to_text_cache(DRWTextStore *dt,
178 bke::AttributeAccessor attribute_accessor,
184 const GVArray attribute = attribute_accessor.lookup(
".viewer").varray.
slice(
187 add_values_to_text_cache(dt, attribute, {
float3(0, 0, 0)}, object_to_world);
190 static void add_text_to_cache(DRWTextStore *dt,
207 static void add_lines_to_cache(DRWTextStore *dt,
213 const float line_height = text_size * 1.1f *
UI_SCALE_FAC;
214 const float center_offset = (lines.
size() - 1) / 2.0f;
222 (center_offset -
i) * line_height,
230 void add_values_to_text_cache(DRWTextStore *dt,
239 using T = decltype(dummy);
240 const VArray<T> &values_typed = values.typed<T>();
241 for (const int i : values.index_range()) {
242 const float3 position = math::transform_point(object_to_world, positions[i]);
243 const T &value = values_typed[i];
245 if constexpr (std::is_same_v<T, bool>) {
247 const size_t numstr_len = STRNCPY_UTF8_RLEN(numstr, value ?
"True" :
"False");
248 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
250 else if constexpr (std::is_same_v<T, int8_t>) {
252 const size_t numstr_len = SNPRINTF_UTF8_RLEN(numstr,
"%d", int(value));
253 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
255 else if constexpr (std::is_same_v<T, int>) {
257 const size_t numstr_len = SNPRINTF_UTF8_RLEN(numstr,
"%d", value);
258 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
260 else if constexpr (std::is_same_v<T, int2>) {
261 char x_str[64], y_str[64];
262 const size_t x_str_len = SNPRINTF_UTF8_RLEN(x_str,
"X: %d", value.x);
263 const size_t y_str_len = SNPRINTF_UTF8_RLEN(y_str,
"Y: %d", value.y);
265 dt, position, {StringRef(x_str, x_str_len), StringRef(y_str, y_str_len)}, col);
267 else if constexpr (std::is_same_v<T, float>) {
269 const size_t numstr_len = SNPRINTF_UTF8_RLEN(numstr,
"%g", value);
270 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
272 else if constexpr (std::is_same_v<T, float2>) {
273 char x_str[64], y_str[64];
274 const size_t x_str_len = SNPRINTF_UTF8_RLEN(x_str,
"X: %g", value.x);
275 const size_t y_str_len = SNPRINTF_UTF8_RLEN(y_str,
"Y: %g", value.y);
277 dt, position, {StringRef(x_str, x_str_len), StringRef(y_str, y_str_len)}, col);
279 else if constexpr (std::is_same_v<T, float3>) {
280 char x_str[64], y_str[64], z_str[64];
281 const size_t x_str_len = SNPRINTF_UTF8_RLEN(x_str,
"X: %g", value.x);
282 const size_t y_str_len = SNPRINTF_UTF8_RLEN(y_str,
"Y: %g", value.y);
283 const size_t z_str_len = SNPRINTF_UTF8_RLEN(z_str,
"Z: %g", value.z);
284 add_lines_to_cache(dt,
286 {StringRef(x_str, x_str_len),
287 StringRef(y_str, y_str_len),
288 StringRef(z_str, z_str_len)},
291 else if constexpr (std::is_same_v<T, ColorGeometry4b>) {
292 const ColorGeometry4f color = color::decode(value);
293 char r_str[64], g_str[64], b_str[64], a_str[64];
294 const size_t r_str_len = SNPRINTF_UTF8_RLEN(r_str,
"R: %.3f", color.r);
295 const size_t g_str_len = SNPRINTF_UTF8_RLEN(g_str,
"G: %.3f", color.g);
296 const size_t b_str_len = SNPRINTF_UTF8_RLEN(b_str,
"B: %.3f", color.b);
297 const size_t a_str_len = SNPRINTF_UTF8_RLEN(a_str,
"A: %.3f", color.a);
298 add_lines_to_cache(dt,
300 {StringRef(r_str, r_str_len),
301 StringRef(g_str, g_str_len),
302 StringRef(b_str, b_str_len),
303 StringRef(a_str, a_str_len)},
306 else if constexpr (std::is_same_v<T, ColorGeometry4f>) {
307 char r_str[64], g_str[64], b_str[64], a_str[64];
308 const size_t r_str_len = SNPRINTF_UTF8_RLEN(r_str,
"R: %.3f", value.r);
309 const size_t g_str_len = SNPRINTF_UTF8_RLEN(g_str,
"G: %.3f", value.g);
310 const size_t b_str_len = SNPRINTF_UTF8_RLEN(b_str,
"B: %.3f", value.b);
311 const size_t a_str_len = SNPRINTF_UTF8_RLEN(a_str,
"A: %.3f", value.a);
312 add_lines_to_cache(dt,
314 {StringRef(r_str, r_str_len),
315 StringRef(g_str, g_str_len),
316 StringRef(b_str, b_str_len),
317 StringRef(a_str, a_str_len)},
320 else if constexpr (std::is_same_v<T, math::Quaternion>) {
321 char w_str[64], x_str[64], y_str[64], z_str[64];
322 const size_t w_str_len = SNPRINTF_UTF8_RLEN(w_str,
"W: %.3f", value.w);
323 const size_t x_str_len = SNPRINTF_UTF8_RLEN(x_str,
"X: %.3f", value.x);
324 const size_t y_str_len = SNPRINTF_UTF8_RLEN(y_str,
"Y: %.3f", value.y);
325 const size_t z_str_len = SNPRINTF_UTF8_RLEN(z_str,
"Z: %.3f", value.z);
326 add_lines_to_cache(dt,
328 {StringRef(w_str, w_str_len),
329 StringRef(x_str, x_str_len),
330 StringRef(y_str, y_str_len),
331 StringRef(z_str, z_str_len)},
334 else if constexpr (std::is_same_v<T, float4x4>) {
336 math::EulerXYZ rotation;
338 math::to_loc_rot_scale_safe<true>(value, location, rotation, scale);
340 char location_str[64];
341 const size_t location_str_len = SNPRINTF_UTF8_RLEN(
342 location_str,
"Location: %.3f, %.3f, %.3f", location.x, location.y, location.z);
343 char rotation_str[64];
344 const size_t rotation_str_len = SNPRINTF_UTF8_RLEN(rotation_str,
345 "Rotation: %.3f°, %.3f°, %.3f°",
346 rotation.x().degree(),
347 rotation.y().degree(),
348 rotation.z().degree());
350 const size_t scale_str_len = SNPRINTF_UTF8_RLEN(
351 scale_str,
"Scale: %.3f, %.3f, %.3f", scale.x, scale.y, scale.z);
352 add_lines_to_cache(dt,
354 {StringRef(location_str, location_str_len),
355 StringRef(rotation_str, rotation_str_len),
356 StringRef(scale_str, scale_str_len)},
360 BLI_assert_unreachable();
366 static float3 calc_corner_text_position(
const float3 &corner_pos,
367 const float3 &prev_corner_pos,
368 const float3 &next_corner_pos,
369 const float3 &face_normal,
372 const float offset_scale = 1.0f)
374 const float3 prev_edge_vec = prev_corner_pos - corner_pos;
375 const float3 next_edge_vec = next_corner_pos - corner_pos;
380 const float next_edge_len =
math::length(next_edge_vec);
381 const float max_offset =
math::min(pre_edge_len, next_edge_len) / 2;
384 const float concavity_check =
math::dot(corner_normal, face_normal);
385 const float direction_correct = concavity_check > 0.0f ? 1.0f : -1.0f;
386 const float3 bisector_dir = (prev_edge_dir + next_edge_dir) / 2 * direction_correct;
388 const float sharp_factor = std::clamp(
math::dot(prev_edge_dir, next_edge_dir), 0.0f, 1.0f);
389 const float sharp_multiplier =
math::pow(sharp_factor, 4.0f) * 2 + 1;
394 const float screen_space_offset = pixel_size * pixel_offset;
396 const float offset_distance = std::clamp(
397 screen_space_offset * sharp_multiplier * offset_scale, 0.0f, max_offset);
399 return corner_pos + bisector_dir * offset_distance;