Blender V5.0
draw_handle.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
21
22#include "BKE_duplilist.hh"
23#include "draw_shader_shared.hh"
24
25/* random */
26#include "BLI_hash.h"
27
28/* find_rgba_attribute */
29#include "GPU_material.hh"
30
31/* particles_matrix */
32#include "BLI_math_matrix.hh"
34
35/* parent_is_in_edit_paint_mode */
36#include "BKE_context.hh"
37#include "BKE_paint.hh"
38#include "DNA_layer_types.h"
39#include "DRW_render.hh"
40
41/* ObjectKey */
43
45
46namespace blender::draw {
47
57 uint32_t raw;
58
59 ResourceIndex() = default;
60 ResourceIndex(uint raw_) : raw(raw_) {};
61 ResourceIndex(uint index, bool inverted_handedness)
62 {
63 raw = index;
64 SET_FLAG_FROM_TEST(raw, inverted_handedness, 0x80000000u);
65 }
66
68 {
69 return (raw & 0x80000000u) != 0;
70 }
71
73 {
74 return (raw & 0x7FFFFFFFu);
75 }
76};
77
84 /* First handle in the range. */
86 /* Number of handles in the range. */
87 uint32_t count = 1;
88
89 ResourceIndexRange() = default;
92
94 {
95 return first.has_inverted_handedness();
96 }
97
99 {
100 BLI_assert(count > 0);
101 BLI_assert(first.raw != 0 || count == 1);
102 return {first.raw, count};
103 }
104};
105
114class ResourceHandle {
115 friend class Manager;
117
118 ResourceIndex index_ = {};
119
120 ResourceHandle(uint raw) : index_(raw) {}
121 ResourceHandle(uint index, bool inverted_handedness) : index_(index, inverted_handedness) {}
122
123 public:
124 ResourceHandle() = default;
125
126 bool is_valid() const
127 {
128 return index_.raw != 0;
129 }
130
132 {
133 return index_.has_inverted_handedness();
134 }
135
137 {
138 return index_.resource_index();
139 }
140
141 operator ResourceIndex() const
142 {
144 return index_;
145 }
146};
147
152class ResourceHandleRange {
153 friend class Manager;
154
155 ResourceIndexRange index_ = {};
156
157 ResourceHandleRange(ResourceHandle handle, uint len) : index_(handle.index_, len) {}
158
159 public:
161 ResourceHandleRange(ResourceHandle handle) : index_(handle.index_) {}
162
163 bool is_valid() const
164 {
165 return index_.first.raw != 0;
166 }
167
169 {
170 return index_.has_inverted_handedness();
171 }
172
174 {
175 return index_.index_range();
176 }
177
178 operator ResourceIndexRange() const
179 {
181 return index_;
182 }
183
184 /* These functions are to keep existing engine code to work.
185 * Should be used only for objects and code paths that don't support ranged synchronization. */
186
187 operator ResourceHandle() const
188 {
189 BLI_assert(index_.count == 1);
190 return ResourceHandle(index_.first.raw);
191 }
192
193 uint32_t raw() const
194 {
195 BLI_assert(index_.count == 1);
196 return index_.first.raw;
197 }
198
200 {
201 BLI_assert(index_.count == 1);
202 return index_.first.resource_index();
203 }
204};
205
206/* TODO(fclem): Move to somewhere more appropriated after cleaning up the header dependencies. */
208 friend class Manager;
209 friend class ObjectKey;
210 friend DupliCacheManager;
211
212 private:
214 DupliObject *const dupli_object_ = nullptr;
216 Object *const dupli_parent_ = nullptr;
217
219 const VectorList<DupliObject *> *duplis_ = nullptr;
220
222 ResourceHandleRange handle_ = {};
223 ResourceHandleRange sculpt_handle_ = {};
224
225 public:
227
228 explicit ObjectRef(Object *ob,
229 Object *dupli_parent = nullptr,
230 DupliObject *dupli_object = nullptr);
231 explicit ObjectRef(Object &ob, Object *dupli_parent, const VectorList<DupliObject *> &duplis);
232
233 /* Is the object coming from a Dupli system. */
234 bool is_dupli() const
235 {
236 return dupli_parent_ != nullptr;
237 }
238
239 bool is_active(const Object *active_object) const
240 {
241 return (dupli_parent_ ? dupli_parent_ : object) == active_object;
242 }
243
244 float random() const
245 {
246 if (duplis_) {
247 /* NOTE: The random property is only used by EEVEE, which currently doesn't support
248 instancing optimizations. However, ObjectInfos always call this function so the code is still
249 reachable even if its result won't be used. */
250 // BLI_assert_unreachable();
251 /* TODO: This should fill a span instead. */
252 return 0.0;
253 }
254
255 if (dupli_parent_ == nullptr) {
256 /* TODO(fclem): this is rather costly to do at draw time. Maybe we can
257 * put it in ob->runtime and make depsgraph ensure it is up to date. */
258 return BLI_hash_int_2d(BLI_hash_string(object->id.name + 2), 0) * (1.0f / (float)0xFFFFFFFF);
259 }
260 return dupli_object_->random_id * (1.0f / (float)0xFFFFFFFF);
261 }
262
263 bool find_rgba_attribute(const GPUUniformAttr &attr, float r_value[4]) const
264 {
265 if (duplis_) {
266 /* NOTE: This function is only called for EEVEE, which currently doesn't support instancing
267 * optimizations, so this code should be unreachable. */
269 /* TODO: r_value should be a Span. */
270 return false;
271 }
272
273 /* If requesting instance data, check the parent particle system and object. */
274 if (attr.use_dupli) {
276 object, dupli_object_, dupli_parent_, attr.name, r_value);
277 }
278 return BKE_object_dupli_find_rgba_attribute(object, nullptr, nullptr, attr.name, r_value);
279 }
280
282 {
283 return dupli_parent_ ? dupli_parent_->light_linking : object->light_linking;
284 }
285
286 int recalc_flags(uint64_t last_update) const
287 {
288 /* TODO: There should also be a way to get the min last_update for all objects in the range. */
289 auto get_flags = [&](const ObjectRuntimeHandle &runtime) {
290 int flags = 0;
291 SET_FLAG_FROM_TEST(flags, runtime.last_update_transform > last_update, ID_RECALC_TRANSFORM);
292 SET_FLAG_FROM_TEST(flags, runtime.last_update_geometry > last_update, ID_RECALC_GEOMETRY);
293 SET_FLAG_FROM_TEST(flags, runtime.last_update_shading > last_update, ID_RECALC_SHADING);
294 return flags;
295 };
296
297 int flags = get_flags(*object->runtime);
298 if (dupli_parent_) {
299 flags |= get_flags(*dupli_parent_->runtime);
300 }
301
302 return flags;
303 }
304
305 /* Particle data are stored in world space. If an object is instanced, the associated particle
306 * systems need to be offset appropriately. */
308 {
309 if (duplis_) {
310 /* NOTE: Objects with particles don't support instancing optimizations yet, so this code
311 * should be unreachable. */
313 /* TODO: This should fill a span instead. */
314 return float4x4::identity();
315 }
316
317 /* TODO: Pass particle systems as a separate ObRef? */
318 float4x4 dupli_mat = float4x4::identity();
319 if (dupli_parent_ && dupli_object_) {
320 if (dupli_object_->type & OB_DUPLICOLLECTION) {
321 Collection *collection = dupli_parent_->instance_collection;
322 if (collection != nullptr) {
323 dupli_mat[3] -= float4(float3(collection->instance_offset), 0.0f);
324 }
325 dupli_mat = dupli_parent_->object_to_world() * dupli_mat;
326 }
327 else {
328 dupli_mat = object->object_to_world() * math::invert(dupli_object_->ob->object_to_world());
329 }
330 }
331 return dupli_mat;
332 }
333
335 {
336 if (dupli_object_) {
337 return dupli_object_->preview_instance_index;
338 }
339 return -1;
340 }
341
343 {
344 if (dupli_object_) {
345 return dupli_object_->preview_base_geometry;
346 }
347 return nullptr;
348 }
349
350 bool parent_is_in_edit_paint_mode(const Object *active_object,
351 eObjectMode ob_mode,
352 eContextObjectMode ctx_mode) const
353 {
354 /* TODO: Deduplicate code with Overlay engine.
355 * Move to BKE ? Or check if T72490 is still relevant. */
356
357 if (!dupli_parent_ || active_object != dupli_parent_) {
358 return false;
359 }
360
361 if (object->base_flag & BASE_FROM_DUPLI) {
362 /* TODO: Is this code reachable? */
363 return false;
364 }
365
366 if (dupli_parent_->sculpt && (dupli_parent_->sculpt->mode_type == OB_MODE_SCULPT)) {
367 return true;
368 }
369
371 return true;
372 }
373
374 if (DRW_object_is_in_edit_mode(dupli_parent_)) {
375 /* Also check for context mode as the object mode is not 100% reliable. (see T72490) */
376 switch (dupli_parent_->type) {
377 case OB_MESH:
378 return ctx_mode == CTX_MODE_EDIT_MESH;
379 case OB_ARMATURE:
380 return ctx_mode == CTX_MODE_EDIT_ARMATURE;
381 case OB_CURVES_LEGACY:
382 return ctx_mode == CTX_MODE_EDIT_CURVE;
383 case OB_SURF:
384 return ctx_mode == CTX_MODE_EDIT_SURFACE;
385 case OB_LATTICE:
386 return ctx_mode == CTX_MODE_EDIT_LATTICE;
387 case OB_MBALL:
388 return ctx_mode == CTX_MODE_EDIT_METABALL;
389 case OB_FONT:
390 return ctx_mode == CTX_MODE_EDIT_TEXT;
391 case OB_CURVES:
392 return ctx_mode == CTX_MODE_EDIT_CURVES;
393 case OB_POINTCLOUD:
394 return ctx_mode == CTX_MODE_EDIT_POINTCLOUD;
395 case OB_GREASE_PENCIL:
396 return ctx_mode == CTX_MODE_EDIT_GREASE_PENCIL;
397 case OB_VOLUME:
398 /* No edit mode yet. */
399 return false;
400 }
401 }
402 return false;
403 }
404};
405
406/* -------------------------------------------------------------------- */
412
415 uint64_t hash_value_ = 0;
417 Object *ob_ = nullptr;
419 Object *parent_ = nullptr;
421 int id_[MAX_DUPLI_RECUR];
423 int sub_key_ = 0;
424
425 public:
426 ObjectKey() = default;
427
428 ObjectKey(const ObjectRef &ob_ref, int sub_key = 0)
429 {
430 ob_ = DEG_get_original(ob_ref.object);
431 hash_value_ = get_default_hash(ob_);
432
433 if (DupliObject *dupli = ob_ref.dupli_object_) {
434 parent_ = ob_ref.dupli_parent_;
435 hash_value_ = get_default_hash(hash_value_, get_default_hash(parent_));
436 for (int i : IndexRange(MAX_DUPLI_RECUR)) {
437 id_[i] = dupli->persistent_id[i];
438 if (id_[i] == std::numeric_limits<int>::max()) {
439 break;
440 }
441 hash_value_ = get_default_hash(hash_value_, get_default_hash(id_[i]));
442 }
443 }
444
445 if (sub_key != 0) {
446 sub_key_ = sub_key;
447 hash_value_ = get_default_hash(hash_value_, get_default_hash(sub_key_));
448 }
449 }
450
452 {
453 return hash_value_;
454 }
455
456 bool operator==(const ObjectKey &k) const
457 {
458 if (hash_value_ != k.hash_value_) {
459 return false;
460 }
461 if (ob_ != k.ob_) {
462 return false;
463 }
464 if (parent_ != k.parent_) {
465 return false;
466 }
467 if (sub_key_ != k.sub_key_) {
468 return false;
469 }
470 if (parent_) {
471 for (int i : IndexRange(MAX_DUPLI_RECUR)) {
472 if (id_[i] != k.id_[i]) {
473 return false;
474 }
475 if (id_[i] == std::numeric_limits<int>::max()) {
476 break;
477 }
478 }
479 }
480 return true;
481 }
482};
483
485
486}; // namespace blender::draw
eContextObjectMode
@ CTX_MODE_EDIT_CURVE
@ CTX_MODE_EDIT_SURFACE
@ CTX_MODE_EDIT_MESH
@ CTX_MODE_EDIT_POINTCLOUD
@ CTX_MODE_EDIT_GREASE_PENCIL
@ CTX_MODE_EDIT_TEXT
@ CTX_MODE_EDIT_CURVES
@ CTX_MODE_EDIT_ARMATURE
@ CTX_MODE_EDIT_LATTICE
@ CTX_MODE_EDIT_METABALL
bool BKE_object_dupli_find_rgba_attribute(const Object *ob, const DupliObject *dupli, const Object *dupli_parent, const char *name, float r_value[4])
constexpr int MAX_DUPLI_RECUR
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
BLI_INLINE unsigned int BLI_hash_string(const char *str)
Definition BLI_hash.h:67
BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
Definition BLI_hash.h:51
unsigned int uint
#define SET_FLAG_FROM_TEST(value, test, flag)
T * DEG_get_original(T *id)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1054
@ ID_RECALC_SHADING
Definition DNA_ID.h:1094
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
Object groups, one object can be in many groups at once.
@ BASE_FROM_DUPLI
#define OB_MODE_ALL_PAINT
#define OB_MODE_ALL_PAINT_GPENCIL
eObjectMode
@ OB_MODE_SCULPT
@ OB_LATTICE
@ OB_MBALL
@ OB_SURF
@ OB_FONT
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ OB_MESH
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES_LEGACY
@ OB_CURVES
struct ObjectRuntimeHandle ObjectRuntimeHandle
@ OB_DUPLICOLLECTION
unsigned long long int uint64_t
constexpr IndexRange index_range() const
bool operator==(const ObjectKey &k) const
ObjectKey(const ObjectRef &ob_ref, int sub_key=0)
uint64_t hash() const
bool parent_is_in_edit_paint_mode(const Object *active_object, eObjectMode ob_mode, eContextObjectMode ctx_mode) const
bool find_rgba_attribute(const GPUUniformAttr &attr, float r_value[4]) const
LightLinking * light_linking() const
bool is_active(const Object *active_object) const
int recalc_flags(uint64_t last_update) const
ObjectRef(Object *ob, Object *dupli_parent=nullptr, DupliObject *dupli_object=nullptr)
int preview_instance_index() const
float4x4 particles_matrix() const
const blender::bke::GeometrySet * preview_base_geometry() const
ResourceHandleRange(ResourceHandle handle)
nullptr float
bool DRW_object_is_in_edit_mode(const Object *ob)
CartesianBasis invert(const CartesianBasis &basis)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
VecBase< float, 3 > float3
ResourceIndexRange(ResourceIndex index)
ResourceIndexRange(ResourceIndex index, uint len)
ResourceIndex(uint index, bool inverted_handedness)
bool has_inverted_handedness() const
i
Definition text_draw.cc:230
uint len