Panda3D

transformBlend.cxx
Go to the documentation of this file.
1 /**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file transformBlend.cxx
10 * @author drose
11 * @date 2005-03-24
12 */
13
14 #include "transformBlend.h"
15 #include "indent.h"
16 #include "bamReader.h"
17 #include "bamWriter.h"
18
19 TypeHandle TransformBlend::_type_handle;
20
21 /**
22 * Defines an arbitrary ordering for TransformBlend objects.
23 */
24 int TransformBlend::
25 compare_to(const TransformBlend &other) const {
26 if (_entries.size() != other._entries.size()) {
27 return (int)_entries.size() - (int)other._entries.size();
28 }
29
30 Entries::const_iterator ai, bi;
31 ai = _entries.begin();
32 bi = other._entries.begin();
33 while (ai != _entries.end() && bi != other._entries.end()) {
34 if ((*ai)._transform != (*bi)._transform) {
35 return (*ai)._transform < (*bi)._transform ? -1 : 1;
36 }
37 if (!IS_NEARLY_EQUAL((*ai)._weight, (*bi)._weight)) {
38 return (*ai)._weight < (*bi)._weight ? -1 : 1;
39 }
40 ++ai;
41 ++bi;
42 }
43
44 return 0;
45 }
46
47 /**
48 * Adds a new transform to the blend. If the transform already existed,
49 * increases its weight factor.
50 */
51 void TransformBlend::
52 add_transform(const VertexTransform *transform, PN_stdfloat weight) {
53 if (!IS_NEARLY_ZERO(weight)) {
54 TransformEntry entry;
55 entry._transform = transform;
56 entry._weight = weight;
57 std::pair<Entries::iterator, bool> result = _entries.insert(entry);
58 if (!result.second) {
59 // If the new value was not inserted, it was already there; increment
60 // the existing weight factor.
61 Entries::iterator ei = result.first;
62 (*ei)._weight += weight;
63 if (IS_NEARLY_ZERO((*ei)._weight)) {
64 // If we have just zeroed out the weight, remove it.
65 _entries.erase(ei);
66 }
67 }
68 Thread *current_thread = Thread::get_current_thread();
69 clear_result(current_thread);
70 }
71 }
72
73 /**
74 * Removes the indicated transform from the blend.
75 */
76 void TransformBlend::
77 remove_transform(const VertexTransform *transform) {
78 TransformEntry entry;
79 entry._transform = transform;
80 entry._weight = 0.0f;
81 Entries::iterator ei = _entries.find(entry);
82 if (ei != _entries.end()) {
83 _entries.erase(ei);
84 }
85 Thread *current_thread = Thread::get_current_thread();
86 clear_result(current_thread);
87 }
88
89 /**
90 * If the total number of transforms in the blend exceeds max_transforms,
91 * removes the n least-important transforms as needed to reduce the number of
92 * transforms to max_transforms.
93 */
94 void TransformBlend::
95 limit_transforms(int max_transforms) {
96 if (max_transforms <= 0) {
97 _entries.clear();
98 return;
99 }
100
101 while ((int)_entries.size() > max_transforms) {
102 // Repeatedly find and remove the least-important transform.
103 nassertv(!_entries.empty());
104 Entries::iterator ei_least = _entries.begin();
105 Entries::iterator ei = ei_least;
106 ++ei;
107 while (ei != _entries.end()) {
108 if ((*ei)._weight < (*ei_least)._weight) {
109 ei_least = ei;
110 }
111 ++ei;
112 }
113
114 _entries.erase(ei_least);
115 }
116 }
117
118 /**
119 * Rescales all of the weights on the various transforms so that they sum to
120 * 1.0. It is generally a good idea to call this after adding or removing
121 * transforms from the blend.
122 */
123 void TransformBlend::
124 normalize_weights() {
125 PN_stdfloat net_weight = 0.0f;
126 Entries::iterator ei;
127 for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
128 net_weight += (*ei)._weight;
129 }
130 if (net_weight != 0.0f) {
131 for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
132 (*ei)._weight /= net_weight;
133 }
134 }
135 Thread *current_thread = Thread::get_current_thread();
136 clear_result(current_thread);
137 }
138
139 /**
140 * Returns true if the blend has the indicated transform, false otherwise.
141 */
142 bool TransformBlend::
143 has_transform(const VertexTransform *transform) const {
144 TransformEntry entry;
145 entry._transform = transform;
146 entry._weight = 0.0f;
147 Entries::const_iterator ei = _entries.find(entry);
148 return (ei != _entries.end());
149 }
150
151 /**
152 * Returns the weight associated with the indicated transform, or 0 if there
153 * is no entry for the transform.
154 */
155 PN_stdfloat TransformBlend::
156 get_weight(const VertexTransform *transform) const {
157 TransformEntry entry;
158 entry._transform = transform;
159 entry._weight = 0.0f;
160 Entries::const_iterator ei = _entries.find(entry);
161 if (ei != _entries.end()) {
162 return (*ei)._weight;
163 }
164 return 0.0f;
165 }
166
167 /**
168 *
169 */
170 void TransformBlend::
171 output(std::ostream &out) const {
172 if (_entries.empty()) {
173 out << "empty";
174 } else {
175 Entries::const_iterator ei = _entries.begin();
176 out << *(*ei)._transform << ":" << (*ei)._weight;
177 ++ei;
178 while (ei != _entries.end()) {
179 out << " " << *(*ei)._transform << ":" << (*ei)._weight;
180 ++ei;
181 }
182 }
183 }
184
185 /**
186 *
187 */
188 void TransformBlend::
189 write(std::ostream &out, int indent_level) const {
190 Thread *current_thread = Thread::get_current_thread();
191 Entries::const_iterator ei;
192 for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
193 indent(out, indent_level)
194 << *(*ei)._transform << ":" << (*ei)._weight << "\n";
195 LMatrix4 mat;
196 (*ei)._transform->get_matrix(mat);
197 mat.write(out, indent_level + 4);
198 }
199 LMatrix4 blend;
200 update_blend(current_thread);
201 get_blend(blend, current_thread);
202 indent(out, indent_level)
203 << "Blended result =\n";
204 blend.write(out, indent_level + 2);
205 }
206
207 /**
208 * Recomputes the blend result from the various VertexTransform objects, if
209 * necessary.
210 */
211 void TransformBlend::
212 recompute_result(CData *cdata, Thread *current_thread) {
213 // Update the global_modified sequence number first, to prevent race
214 // conditions.
215 cdata->_global_modified = VertexTransform::get_global_modified(current_thread);
216
217 // Now see if we really need to recompute.
218 UpdateSeq seq;
219 Entries::const_iterator ei;
220 for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
221 seq = std::max(seq, (*ei)._transform->get_modified(current_thread));
222 }
223
224 if (cdata->_modified != seq) {
225 // We do need to recompute.
226 cdata->_modified = seq;
227
228 cdata->_result = LMatrix4::zeros_mat();
229 for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
230 (*ei)._transform->accumulate_matrix(cdata->_result, (*ei)._weight);
231 }
232 }
233 }
234
235 /**
236 * Removes the computed result to force it to be recomputed.
237 */
238 void TransformBlend::
239 clear_result(Thread *current_thread) {
240 CDWriter cdata(_cycler, true, current_thread);
241 cdata->_global_modified = UpdateSeq();
242 if (cdata->_modified != UpdateSeq()) {
243 cdata->_modified = UpdateSeq();
244 cdata->_result = LMatrix4::ident_mat();
245 }
246 }
247
248 /**
249 * Writes the contents of this object to the datagram for shipping out to a
250 * Bam file.
251 */
252 void TransformBlend::
253 write_datagram(BamWriter *manager, Datagram &dg) const {
254 dg.add_uint16(_entries.size());
255
256 Entries::const_iterator ei;
257 for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
258 manager->write_pointer(dg, (*ei)._transform);
259 dg.add_stdfloat((*ei)._weight);
260 }
261 }
262
263 /**
264 * Receives an array of pointers, one for each time manager->read_pointer()
265 * was called in fillin(). Returns the number of pointers processed.
266 */
267 int TransformBlend::
268 complete_pointers(TypedWritable **p_list, BamReader *manager) {
269 int pi = 0;
270
271 Entries::iterator ei;
272 for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
273 (*ei)._transform = DCAST(VertexTransform, p_list[pi++]);
274 }
275
276 // Now that we have actual pointers, we can sort the list of entries.
277 _entries.sort();
278
279 return pi;
280 }
281
282 /**
283 * This internal function is called by make_from_bam to read in all of the
284 * relevant data from the BamFile for the new PandaNode.
285 */
286 void TransformBlend::
287 fillin(DatagramIterator &scan, BamReader *manager) {
288 size_t num_entries = scan.get_uint16();
289 _entries.reserve(num_entries);
290 for (size_t i = 0; i < num_entries; ++i) {
291 TransformEntry entry;
292 manager->read_pointer(scan);
293 entry._weight = scan.get_stdfloat();
294 _entries.push_back(entry);
295 }
296 }
297
298 /**
299 *
300 */
301 CycleData *TransformBlend::CData::
302 make_copy() const {
303 return new CData(*this);
304 }
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
BamReader::read_pointer
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
BamWriter::write_pointer
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
CycleData
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
DatagramIterator::get_stdfloat
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
Definition: datagramIterator.I:242
DatagramIterator::get_uint16
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
Definition: datagramIterator.I:145
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Datagram::add_stdfloat
void add_stdfloat(PN_stdfloat value)
Adds either a 32-bit or a 64-bit floating-point number, according to set_stdfloat_double().
Definition: datagram.I:133
Datagram::add_uint16
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
Thread::get_current_thread
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
TransformBlend
This defines a single entry in a TransformBlendTable.
Definition: transformBlend.h:32
TransformBlend::limit_transforms
void limit_transforms(int max_transforms)
If the total number of transforms in the blend exceeds max_transforms, removes the n least-important ...
Definition: transformBlend.cxx:95
TransformBlend::update_blend
void update_blend(Thread *current_thread) const
Recomputes the internal representation of the blend value, if necessary.
Definition: transformBlend.I:180
TransformBlend::has_transform
has_transform
Returns true if the blend has the indicated transform, false otherwise.
Definition: transformBlend.h:71
TransformBlend::get_weight
get_weight
Returns the weight associated with the indicated transform, or 0 if there is no entry for the transfo...
Definition: transformBlend.h:71
TransformBlend::fillin
void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is called by make_from_bam to read in all of the relevant data from the BamFil...
Definition: transformBlend.cxx:287
TransformBlend::complete_pointers
int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: transformBlend.cxx:268
TransformBlend::compare_to
int compare_to(const TransformBlend &other) const
Defines an arbitrary ordering for TransformBlend objects.
Definition: transformBlend.cxx:25
TransformBlend::get_blend
void get_blend(LMatrix4 &result, Thread *current_thread) const
Returns the current value of the blend, based on the current value of all of the nested transform obj...
Definition: transformBlend.I:196
TransformBlend::remove_transform
remove_transform
Removes the indicated transform from the blend.
Definition: transformBlend.h:70
TransformBlend::write_datagram
void write_datagram(BamWriter *manager, Datagram &dg) const
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: transformBlend.cxx:253
TransformBlend::normalize_weights
void normalize_weights()
Rescales all of the weights on the various transforms so that they sum to 1.0.
Definition: transformBlend.cxx:124
TransformBlend::add_transform
void add_transform(const VertexTransform *transform, PN_stdfloat weight)
Adds a new transform to the blend.
Definition: transformBlend.cxx:52
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
UpdateSeq
This is a sequence number that increments monotonically.
Definition: updateSeq.h:37
VertexTransform
This is an abstract base class that holds a pointer to some transform, computed in some arbitrary way...
Definition: vertexTransform.h:35
VertexTransform::get_global_modified
static UpdateSeq get_global_modified(Thread *current_thread)
Returns the currently highest VertexTransform::get_modified() value in the world.
Definition: vertexTransform.I:30
ordered_vector::reserve
void reserve(size_type_0 n)
Informs the vector of a planned change in size; ensures that the capacity of the vector is greater th...
Definition: ordered_vector.I:572
ordered_vector::begin
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
Definition: ordered_vector.I:41
ordered_vector::push_back
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
Definition: ordered_vector.I:614
ordered_vector::size
size_type_0 size() const
Returns the number of elements in the ordered vector.
Definition: ordered_vector.I:221
ordered_vector::empty
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
Definition: ordered_vector.I:240
ordered_vector::end
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
Definition: ordered_vector.I:50
ordered_vector::clear
void clear()
Removes all elements from the ordered vector.
Definition: ordered_vector.I:412
ov_set::sort
void sort()
Maps to sort_unique().
Definition: ordered_vector.I:731
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
transformBlend.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.