Blender  V2.93
geometry_component_instances.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include "BLI_float4x4.hh"
18 #include "BLI_map.hh"
19 #include "BLI_rand.hh"
20 #include "BLI_set.hh"
21 #include "BLI_span.hh"
22 #include "BLI_vector.hh"
23 
24 #include "DNA_collection_types.h"
25 
26 #include "BKE_geometry_set.hh"
27 
28 using blender::float4x4;
29 using blender::Map;
31 using blender::Set;
32 using blender::Span;
33 
34 /* -------------------------------------------------------------------- */
39 {
40 }
41 
43 {
44  InstancesComponent *new_component = new InstancesComponent();
45  new_component->transforms_ = transforms_;
46  new_component->instanced_data_ = instanced_data_;
47  new_component->ids_ = ids_;
48  return new_component;
49 }
50 
52 {
53  instanced_data_.clear();
54  transforms_.clear();
55  ids_.clear();
56 }
57 
59 {
62  data.data.object = object;
63  this->add_instance(data, transform, id);
64 }
65 
67 {
70  data.data.collection = collection;
71  this->add_instance(data, transform, id);
72 }
73 
75 {
76  instanced_data_.append(data);
77  transforms_.append(transform);
78  ids_.append(id);
79 }
80 
82 {
83  return instanced_data_;
84 }
85 
87 {
88  return transforms_;
89 }
90 
92 {
93  return ids_;
94 }
95 
97 {
98  return transforms_;
99 }
100 
102 {
103  const int size = instanced_data_.size();
104  BLI_assert(transforms_.size() == size);
105  return size;
106 }
107 
109 {
110  return transforms_.size() == 0;
111 }
112 
114 {
115  /* The object and collection instances are not direct data. Instance transforms are direct data
116  * and are always owned. Therefore, instance components always own all their direct data. */
117  return true;
118 }
119 
121 {
122  BLI_assert(this->is_mutable());
123 }
124 
126 {
127  using namespace blender;
128  Array<int> unique_ids(original_ids.size());
129 
130  Set<int> used_unique_ids;
131  used_unique_ids.reserve(original_ids.size());
132  Vector<int> instances_with_id_collision;
133  for (const int instance_index : original_ids.index_range()) {
134  const int original_id = original_ids[instance_index];
135  if (used_unique_ids.add(original_id)) {
136  /* The original id has not been used by another instance yet. */
137  unique_ids[instance_index] = original_id;
138  }
139  else {
140  /* The original id of this instance collided with a previous instance, it needs to be looked
141  * at again in a second pass. Don't generate a new random id here, because this might collide
142  * with other existing ids. */
143  instances_with_id_collision.append(instance_index);
144  }
145  }
146 
147  Map<int, RandomNumberGenerator> generator_by_original_id;
148  for (const int instance_index : instances_with_id_collision) {
149  const int original_id = original_ids[instance_index];
150  RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
152  rng.seed_random(original_id);
153  return rng;
154  });
155 
156  const int max_iteration = 100;
157  for (int iteration = 0;; iteration++) {
158  /* Try generating random numbers until an unused one has been found. */
159  const int random_id = rng.get_int32();
160  if (used_unique_ids.add(random_id)) {
161  /* This random id is not used by another instance. */
162  unique_ids[instance_index] = random_id;
163  break;
164  }
165  if (iteration == max_iteration) {
166  /* It seems to be very unlikely that we ever run into this case (assuming there are less
167  * than 2^30 instances). However, if that happens, it's better to use an id that is not
168  * unique than to be stuck in an infinite loop. */
169  unique_ids[instance_index] = original_id;
170  break;
171  }
172  }
173  }
174 
175  return unique_ids;
176 }
177 
179 {
180  std::lock_guard lock(almost_unique_ids_mutex_);
181  if (almost_unique_ids_.size() != ids_.size()) {
182  almost_unique_ids_ = generate_unique_instance_ids(ids_);
183  }
184  return almost_unique_ids_;
185 }
186 
@ GEO_COMPONENT_TYPE_INSTANCES
@ INSTANCE_DATA_TYPE_OBJECT
@ INSTANCE_DATA_TYPE_COLLECTION
#define BLI_assert(a)
Definition: BLI_assert.h:58
Object groups, one object can be in many groups at once.
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
bool is_mutable() const
Definition: geometry_set.cc:81
void add_instance(Object *object, blender::float4x4 transform, const int id=-1)
blender::Span< int > almost_unique_ids() const
blender::Span< blender::float4x4 > transforms() const
blender::Span< InstancedData > instanced_data() const
blender::Span< int > ids() const
GeometryComponent * copy() const override
bool owns_direct_data() const override
int64_t size() const
Definition: BLI_array.hh:258
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition: BLI_map.hh:575
void seed_random(uint32_t seed)
Definition: rand.cc:383
void reserve(const int64_t n)
Definition: BLI_set.hh:576
bool add(const Key &key)
Definition: BLI_set.hh:267
constexpr int64_t size() const
Definition: BLI_span.hh:254
constexpr IndexRange index_range() const
Definition: BLI_span.hh:414
int64_t size() const
Definition: BLI_vector.hh:662
void append(const T &value)
Definition: BLI_vector.hh:438
static blender::Array< int > generate_unique_instance_ids(Span< int > original_ids)