Blender V4.5
overlay_attribute_text.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
12#include "BLI_string.h"
13
14#include "DNA_curve_types.h"
16
17#include "BKE_attribute.hh"
18#include "BKE_curves.hh"
19#include "BKE_duplilist.hh"
20#include "BKE_geometry_set.hh"
21#include "BKE_instances.hh"
22
23#include "DRW_render.hh"
24
25#include "UI_resources.hh"
26
27#include "draw_manager_text.hh"
28
29#include "overlay_base.hh"
30
31namespace blender::draw::overlay {
32
38 public:
39 void begin_sync(Resources &res, const State &state) final
40 {
41 enabled_ = !res.is_selection() && state.show_attribute_viewer_text();
42 }
43
44 void object_sync(Manager & /*manager*/,
45 const ObjectRef &ob_ref,
46 Resources & /*res*/,
47 const State &state) final
48 {
49 if (!enabled_) {
50 return;
51 }
52
53 const Object &object = *ob_ref.object;
54 const DupliObject *dupli_object = ob_ref.dupli_object;
55 const bool is_preview = dupli_object != nullptr &&
56 dupli_object->preview_base_geometry != nullptr;
57 if (!is_preview) {
58 return;
59 }
60
61 DRWTextStore *dt = state.dt;
62 const float4x4 &object_to_world = object.object_to_world();
63
64 if (dupli_object->preview_instance_index >= 0) {
65 const bke::Instances *instances = dupli_object->preview_base_geometry->get_instances();
66 if (instances->attributes().contains(".viewer")) {
67 add_instance_attributes_to_text_cache(
68 dt, instances->attributes(), object_to_world, dupli_object->preview_instance_index);
69
70 return;
71 }
72 }
73
74 switch (object.type) {
75 case OB_MESH: {
76 const Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(object);
77 add_attributes_to_text_cache(dt, mesh.attributes(), object_to_world);
78 break;
79 }
80 case OB_POINTCLOUD: {
82 add_attributes_to_text_cache(dt, pointcloud.attributes(), object_to_world);
83 break;
84 }
85 case OB_CURVES_LEGACY: {
86 const Curve &curve = DRW_object_get_data_for_drawing<Curve>(object);
87 if (curve.curve_eval) {
88 const bke::CurvesGeometry &curves = curve.curve_eval->geometry.wrap();
89 add_attributes_to_text_cache(dt, curves.attributes(), object_to_world);
90 }
91 break;
92 }
93 case OB_CURVES: {
94 const Curves &curves_id = DRW_object_get_data_for_drawing<Curves>(object);
95 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
96 add_attributes_to_text_cache(dt, curves.attributes(), object_to_world);
97 break;
98 }
99 }
100 }
101
102 private:
103 void add_attributes_to_text_cache(DRWTextStore *dt,
104 bke::AttributeAccessor attribute_accessor,
105 const float4x4 &object_to_world)
106 {
107 if (!attribute_accessor.contains(".viewer")) {
108 return;
109 }
110
111 const bke::GAttributeReader attribute = attribute_accessor.lookup(".viewer");
112 const VArraySpan<float3> positions = *attribute_accessor.lookup<float3>("position",
113 attribute.domain);
114
115 add_values_to_text_cache(dt, attribute.varray, positions, object_to_world);
116 }
117
118 void add_instance_attributes_to_text_cache(DRWTextStore *dt,
119 bke::AttributeAccessor attribute_accessor,
120 const float4x4 &object_to_world,
121 int instance_index)
122 {
123 /* Data from instances are read as a single value from a given index. The data is converted
124 * back to an array so one function can handle both instance and object data. */
125 const GVArray attribute = attribute_accessor.lookup(".viewer").varray.slice(
126 IndexRange(instance_index, 1));
127
128 add_values_to_text_cache(dt, attribute, {float3(0, 0, 0)}, object_to_world);
129 }
130
131 static void add_text_to_cache(DRWTextStore *dt,
132 const float3 &position,
133 const StringRef text,
134 const uchar4 &color)
135 {
137 position,
138 text.data(),
139 text.size(),
140 0,
141 0,
143 color,
144 true,
145 true);
146 }
147
148 static void add_lines_to_cache(DRWTextStore *dt,
149 const float3 &position,
150 const Span<StringRef> lines,
151 const uchar4 &color)
152 {
153 for (const int i : lines.index_range()) {
154 const StringRef line = lines[i];
156 position,
157 line.data(),
158 line.size(),
159 0,
160 -i * 12.0f * UI_SCALE_FAC,
162 color,
163 true,
164 true);
165 }
166 }
167
168 void add_values_to_text_cache(DRWTextStore *dt,
169 const GVArray &values,
170 const Span<float3> positions,
171 const float4x4 &object_to_world)
172 {
173 uchar col[4];
175
176 bke::attribute_math::convert_to_static_type(values.type(), [&](auto dummy) {
177 using T = decltype(dummy);
178 const VArray<T> &values_typed = values.typed<T>();
179 for (const int i : values.index_range()) {
180 const float3 position = math::transform_point(object_to_world, positions[i]);
181 const T &value = values_typed[i];
182
183 if constexpr (std::is_same_v<T, bool>) {
184 char numstr[64];
185 const size_t numstr_len = SNPRINTF_RLEN(numstr, "%s", value ? "True" : "False");
186 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
187 }
188 else if constexpr (std::is_same_v<T, int8_t>) {
189 char numstr[64];
190 const size_t numstr_len = SNPRINTF_RLEN(numstr, "%d", int(value));
191 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
192 }
193 else if constexpr (std::is_same_v<T, int>) {
194 char numstr[64];
195 const size_t numstr_len = SNPRINTF_RLEN(numstr, "%d", value);
196 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
197 }
198 else if constexpr (std::is_same_v<T, int2>) {
199 char numstr[64];
200 const size_t numstr_len = SNPRINTF_RLEN(numstr, "(%d, %d)", value.x, value.y);
201 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
202 }
203 else if constexpr (std::is_same_v<T, float>) {
204 char numstr[64];
205 const size_t numstr_len = SNPRINTF_RLEN(numstr, "%g", value);
206 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
207 }
208 else if constexpr (std::is_same_v<T, float2>) {
209 char numstr[64];
210 const size_t numstr_len = SNPRINTF_RLEN(numstr, "(%g, %g)", value.x, value.y);
211 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
212 }
213 else if constexpr (std::is_same_v<T, float3>) {
214 char numstr[64];
215 const size_t numstr_len = SNPRINTF_RLEN(
216 numstr, "(%g, %g, %g)", value.x, value.y, value.z);
217 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
218 }
219 else if constexpr (std::is_same_v<T, ColorGeometry4b>) {
220 const ColorGeometry4f color = value.decode();
221 char numstr[64];
222 const size_t numstr_len = SNPRINTF_RLEN(
223 numstr, "(%.3f, %.3f, %.3f, %.3f)", color.r, color.g, color.b, color.a);
224 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
225 }
226 else if constexpr (std::is_same_v<T, ColorGeometry4f>) {
227 char numstr[64];
228 const size_t numstr_len = SNPRINTF_RLEN(
229 numstr, "(%.3f, %.3f, %.3f, %.3f)", value.r, value.g, value.b, value.a);
230 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
231 }
232 else if constexpr (std::is_same_v<T, math::Quaternion>) {
233 char numstr[64];
234 const size_t numstr_len = SNPRINTF_RLEN(
235 numstr, "(%.3f, %.3f, %.3f, %.3f)", value.w, value.x, value.y, value.z);
236 add_text_to_cache(dt, position, StringRef(numstr, numstr_len), col);
237 }
238 else if constexpr (std::is_same_v<T, float4x4>) {
239 float3 location;
240 math::EulerXYZ rotation;
241 float3 scale;
242 math::to_loc_rot_scale_safe<true>(value, location, rotation, scale);
243
244 char location_str[64];
245 const size_t location_str_len = SNPRINTF_RLEN(
246 location_str, "Location: %.3f, %.3f, %.3f", location.x, location.y, location.z);
247 char rotation_str[64];
248 const size_t rotation_str_len = SNPRINTF_RLEN(rotation_str,
249 "Rotation: %.3f°, %.3f°, %.3f°",
250 rotation.x().degree(),
251 rotation.y().degree(),
252 rotation.z().degree());
253 char scale_str[64];
254 const size_t scale_str_len = SNPRINTF_RLEN(
255 scale_str, "Scale: %.3f, %.3f, %.3f", scale.x, scale.y, scale.z);
256 add_lines_to_cache(dt,
257 position,
258 {StringRef(location_str, location_str_len),
259 StringRef(rotation_str, rotation_str_len),
260 StringRef(scale_str, scale_str_len)},
261 col);
262 }
263 else {
264 BLI_assert_unreachable();
265 }
266 }
267 });
268 }
269};
270
271} // namespace blender::draw::overlay
Low-level operations for curves.
unsigned char uchar
@ OB_MESH
@ OB_POINTCLOUD
@ OB_CURVES_LEGACY
@ OB_CURVES
#define UI_SCALE_FAC
@ TH_TEXT_HI
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
AttributeSet attributes
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
GVArray slice(IndexRange slice) const
constexpr int64_t size() const
constexpr const char * data() const
bool contains(StringRef attribute_id) const
GAttributeReader lookup(const StringRef attribute_id) const
AttributeAccessor attributes() const
bke::AttributeAccessor attributes() const
Definition instances.cc:63
void object_sync(Manager &, const ObjectRef &ob_ref, Resources &, const State &state) final
void begin_sync(Resources &res, const State &state) final
Mesh & DRW_object_get_data_for_drawing(const Object &object)
void DRW_text_cache_add(DRWTextStore *dt, const float co[3], const char *str, const int str_len, short xoffs, short yoffs, short flag, const uchar col[4], const bool shadow, const bool align_center)
@ DRW_TEXT_CACHE_GLOBALSPACE
uint col
static ulong state[N]
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
MatBase< float, 4, 4 > float4x4
blender::VecBase< uint8_t, 4 > uchar4
VecBase< float, 3 > float3
const struct Curves * curve_eval
CurvesGeometry geometry
const blender::bke::GeometrySet * preview_base_geometry
int preview_instance_index
const Instances * get_instances() const
i
Definition text_draw.cc:230