Panda3D
transformBlendTable.cxx
1 // Filename: transformBlendTable.cxx
2 // Created by: drose (24Mar05)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "transformBlendTable.h"
16 #include "indent.h"
17 #include "bamReader.h"
18 #include "bamWriter.h"
19 
20 TypeHandle TransformBlendTable::_type_handle;
21 
22 ////////////////////////////////////////////////////////////////////
23 // Function: TransformBlendTable::make_cow_copy
24 // Access: Protected, Virtual
25 // Description: Required to implement CopyOnWriteObject.
26 ////////////////////////////////////////////////////////////////////
27 PT(CopyOnWriteObject) TransformBlendTable::
28 make_cow_copy() {
29  return new TransformBlendTable(*this);
30 }
31 
32 ////////////////////////////////////////////////////////////////////
33 // Function: TransformBlendTable::Constructor
34 // Access: Published
35 // Description:
36 ////////////////////////////////////////////////////////////////////
37 TransformBlendTable::
38 TransformBlendTable() {
39 }
40 
41 ////////////////////////////////////////////////////////////////////
42 // Function: TransformBlendTable::Copy Constructor
43 // Access: Published
44 // Description:
45 ////////////////////////////////////////////////////////////////////
46 TransformBlendTable::
47 TransformBlendTable(const TransformBlendTable &copy) :
48  _blends(copy._blends),
49  _rows(copy._rows)
50 {
51 }
52 
53 ////////////////////////////////////////////////////////////////////
54 // Function: TransformBlendTable::Copy Assignment Operator
55 // Access: Published
56 // Description:
57 ////////////////////////////////////////////////////////////////////
58 void TransformBlendTable::
59 operator = (const TransformBlendTable &copy) {
60  _blends = copy._blends;
61  _rows = copy._rows;
62  clear_index();
63 }
64 
65 ////////////////////////////////////////////////////////////////////
66 // Function: TransformBlendTable::Destructor
67 // Access: Published, Virtual
68 // Description:
69 ////////////////////////////////////////////////////////////////////
70 TransformBlendTable::
71 ~TransformBlendTable() {
72 }
73 
74 ////////////////////////////////////////////////////////////////////
75 // Function: TransformBlendTable::set_blend
76 // Access: Published
77 // Description: Replaces the blend at the nth position with the
78 // indicated value.
79 ////////////////////////////////////////////////////////////////////
81 set_blend(int n, const TransformBlend &blend) {
82  nassertv(n >= 0 && n < (int)_blends.size());
83  _blends[n] = blend;
84 }
85 
86 ////////////////////////////////////////////////////////////////////
87 // Function: TransformBlendTable::remove_blend
88 // Access: Published
89 // Description: Removes the blend at the nth position.
90 ////////////////////////////////////////////////////////////////////
92 remove_blend(int n) {
93  nassertv(n >= 0 && n < (int)_blends.size());
94  _blends.erase(_blends.begin() + n);
95 }
96 
97 ////////////////////////////////////////////////////////////////////
98 // Function: TransformBlendTable::add_blend
99 // Access: Published
100 // Description: Adds a new blend to the table, and returns its
101 // index number. If there is already an identical blend
102 // in the table, simply returns that number instead.
103 ////////////////////////////////////////////////////////////////////
105 add_blend(const TransformBlend &blend) {
106  consider_rebuild_index();
107 
108  BlendIndex::iterator bi;
109  bi = _blend_index.find(&blend);
110  if (bi != _blend_index.end()) {
111  // Already had it.
112  return (*bi).second;
113  }
114 
115  bool needs_realloc = (_blends.size() >= _blends.capacity());
116  int new_position = (int)_blends.size();
117  _blends.push_back(blend);
118 
119  if (needs_realloc) {
120  // We just reallocated the blends vector, so we must rebuild the
121  // index.
122  clear_index();
123 
124  } else {
125  // Since we didn't realloc the blends vector, just update it with
126  // the latest.
127  const TransformBlend &added_blend = _blends[new_position];
128  _blend_index[&added_blend] = new_position;
129  _max_simultaneous_transforms = max(_max_simultaneous_transforms,
130  blend.get_num_transforms());
131 
132  // We can't compute this one as we go, so set it to a special
133  // value to indicate it needs to be recomputed.
134  _num_transforms = -1;
135  }
136 
137  return new_position;
138 }
139 
140 ////////////////////////////////////////////////////////////////////
141 // Function: TransformBlendTable::write
142 // Access: Published
143 // Description:
144 ////////////////////////////////////////////////////////////////////
145 void TransformBlendTable::
146 write(ostream &out, int indent_level) const {
147  for (int i = 0; i < (int)_blends.size(); i++) {
148  indent(out, indent_level)
149  << i << ". " << _blends[i] << "\n";
150  }
151 }
152 
153 ////////////////////////////////////////////////////////////////////
154 // Function: TransformBlendTable::clear_index
155 // Access: Private
156 // Description: Resets the index so that it will be rebuilt next time
157 // it is needed.
158 ////////////////////////////////////////////////////////////////////
159 void TransformBlendTable::
160 clear_index() {
161  _blend_index.clear();
162 }
163 
164 ////////////////////////////////////////////////////////////////////
165 // Function: TransformBlendTable::rebuild_index
166 // Access: Private
167 // Description: Rebuilds the index so that we can easily determine
168 // what blend combinations are already present in the
169 // table.
170 ////////////////////////////////////////////////////////////////////
171 void TransformBlendTable::
172 rebuild_index() {
173  _blend_index.clear();
174 
175  // We'll also count up these two statistics while we rebuild the
176  // index.
177  _num_transforms = 0;
178  _max_simultaneous_transforms = 0;
179 
181 
182  for (int i = 0; i < (int)_blends.size(); ++i) {
183  const TransformBlend &blend = _blends[i];
184  _blend_index[&blend] = i;
185 
186  for (int ti = 0; ti < blend.get_num_transforms(); ++ti) {
187  transforms.insert(blend.get_transform(ti));
188  }
189  _max_simultaneous_transforms = max(_max_simultaneous_transforms,
190  blend.get_num_transforms());
191  }
192 
193  _num_transforms = transforms.size();
194 }
195 
196 ////////////////////////////////////////////////////////////////////
197 // Function: TransformBlendTable::recompute_modified
198 // Access: Private
199 // Description: Recomputes the modified stamp from the various
200 // TransformBlend objects, if necessary.
201 ////////////////////////////////////////////////////////////////////
202 void TransformBlendTable::
203 recompute_modified(TransformBlendTable::CData *cdata, Thread *current_thread) {
204  // Update the global_modified sequence number first, to prevent race
205  // conditions.
206  cdata->_global_modified = VertexTransform::get_global_modified(current_thread);
207 
208  // Now get the local modified number.
209  UpdateSeq seq;
210  Blends::const_iterator bi;
211  for (bi = _blends.begin(); bi != _blends.end(); ++bi) {
212  seq = max(seq, (*bi).get_modified(current_thread));
213  }
214 
215  cdata->_modified = seq;
216 }
217 
218 ////////////////////////////////////////////////////////////////////
219 // Function: TransformBlendTable::clear_modified
220 // Access: Private
221 // Description: Clears the modified stamp to force it to be
222 // recomputed.
223 ////////////////////////////////////////////////////////////////////
224 void TransformBlendTable::
225 clear_modified(Thread *current_thread) {
226  CDWriter cdata(_cycler, true, current_thread);
227  cdata->_global_modified = UpdateSeq();
228  cdata->_modified = UpdateSeq();
229 }
230 
231 ////////////////////////////////////////////////////////////////////
232 // Function: TransformBlendTable::register_with_read_factory
233 // Access: Public, Static
234 // Description: Tells the BamReader how to create objects of type
235 // TransformBlendTable.
236 ////////////////////////////////////////////////////////////////////
239  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
240 }
241 
242 ////////////////////////////////////////////////////////////////////
243 // Function: TransformBlendTable::write_datagram
244 // Access: Public, Virtual
245 // Description: Writes the contents of this object to the datagram
246 // for shipping out to a Bam file.
247 ////////////////////////////////////////////////////////////////////
250  TypedWritable::write_datagram(manager, dg);
251 
252  dg.add_uint16(_blends.size());
253  Blends::const_iterator bi;
254  for (bi = _blends.begin(); bi != _blends.end(); ++bi) {
255  (*bi).write_datagram(manager, dg);
256  }
257 
258  _rows.write_datagram(manager, dg);
259 
260  manager->write_cdata(dg, _cycler);
261 }
262 
263 ////////////////////////////////////////////////////////////////////
264 // Function: TransformBlendTable::complete_pointers
265 // Access: Public, Virtual
266 // Description: Receives an array of pointers, one for each time
267 // manager->read_pointer() was called in fillin().
268 // Returns the number of pointers processed.
269 ////////////////////////////////////////////////////////////////////
272  int pi = TypedWritable::complete_pointers(p_list, manager);
273 
274  Blends::iterator bi;
275  for (bi = _blends.begin(); bi != _blends.end(); ++bi) {
276  pi += (*bi).complete_pointers(p_list + pi, manager);
277  }
278 
279  return pi;
280 }
281 
282 ////////////////////////////////////////////////////////////////////
283 // Function: TransformBlendTable::make_from_bam
284 // Access: Protected, Static
285 // Description: This function is called by the BamReader's factory
286 // when a new object of type TransformBlendTable is encountered
287 // in the Bam file. It should create the TransformBlendTable
288 // and extract its information from the file.
289 ////////////////////////////////////////////////////////////////////
290 TypedWritable *TransformBlendTable::
291 make_from_bam(const FactoryParams &params) {
293  DatagramIterator scan;
294  BamReader *manager;
295 
296  parse_params(params, scan, manager);
297  object->fillin(scan, manager);
298 
299  return object;
300 }
301 
302 ////////////////////////////////////////////////////////////////////
303 // Function: TransformBlendTable::fillin
304 // Access: Protected
305 // Description: This internal function is called by make_from_bam to
306 // read in all of the relevant data from the BamFile for
307 // the new TransformBlendTable.
308 ////////////////////////////////////////////////////////////////////
309 void TransformBlendTable::
310 fillin(DatagramIterator &scan, BamReader *manager) {
311  TypedWritable::fillin(scan, manager);
312 
313  size_t num_blends = scan.get_uint16();
314  _blends.reserve(num_blends);
315  size_t i;
316  for (i = 0; i < num_blends; ++i) {
317  TransformBlend blend;
318  blend.fillin(scan, manager);
319  _blends.push_back(blend);
320  }
321 
322  if (manager->get_file_minor_ver() >= 7) {
323  _rows.read_datagram(scan, manager);
324  } else {
325  // In this case, for bam files prior to 6.7, we must define the
326  // SparseArray with the full number of vertices. This is done
327  // in GeomVertexData::complete_pointers().
328  }
329 
330  manager->read_cdata(scan, _cycler);
331 }
332 
333 ////////////////////////////////////////////////////////////////////
334 // Function: TransformBlendTable::CData::make_copy
335 // Access: Public, Virtual
336 // Description:
337 ////////////////////////////////////////////////////////////////////
338 CycleData *TransformBlendTable::CData::
339 make_copy() const {
340  return new CData(*this);
341 }
342 
343 ////////////////////////////////////////////////////////////////////
344 // Function: TransformBlendTable::CData::write_datagram
345 // Access: Public, Virtual
346 // Description: Writes the contents of this object to the datagram
347 // for shipping out to a Bam file.
348 ////////////////////////////////////////////////////////////////////
349 void TransformBlendTable::CData::
350 write_datagram(BamWriter *manager, Datagram &dg) const {
351 }
352 
353 ////////////////////////////////////////////////////////////////////
354 // Function: TransformBlendTable::CData::fillin
355 // Access: Public, Virtual
356 // Description: This internal function is called by make_from_bam to
357 // read in all of the relevant data from the BamFile for
358 // the new TransformBlendTable.
359 ////////////////////////////////////////////////////////////////////
360 void TransformBlendTable::CData::
361 fillin(DatagramIterator &scan, BamReader *manager) {
362  Thread *current_thread = Thread::get_current_thread();
363  _modified = VertexTransform::get_next_modified(current_thread);
364  _global_modified = VertexTransform::get_global_modified(current_thread);
365 }
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in 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...
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:753
void write_datagram(BamWriter *manager, Datagram &dg) const
Writes the contents of this object to the datagram for shipping out to a Bam file.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:398
static UpdateSeq get_next_modified(Thread *current_thread)
Returns a monotonically increasing sequence.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:105
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class&#39;s make_from_bam() method to read in all...
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin()...
static UpdateSeq get_global_modified(Thread *current_thread)
Returns the currently highest VertexTransform::get_modified() value in the world. ...
const VertexTransform * get_transform(int n) const
Returns the nth transform stored in the blend object.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
static void register_with_read_factory()
Tells the BamReader how to create objects of type TransformBlendTable.
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
int get_num_transforms() const
Returns the number of transforms stored in the blend object.
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:181
This defines a single entry in a TransformBlendTable.
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
A thread; that is, a lightweight process.
Definition: thread.h:51
void set_blend(int n, const TransformBlend &blend)
Replaces the blend at the nth position with the indicated value.
This structure collects together the different combinations of transforms and blend amounts used by a...
This is our own Panda specialization on the default STL set.
Definition: pset.h:52
void remove_blend(int n)
Removes the blend at the nth position.
A class to retrieve the individual data elements previously stored in a Datagram. ...
int add_blend(const TransformBlend &blend)
Adds a new blend to the table, and returns its index number.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
This is a sequence number that increments monotonically.
Definition: updateSeq.h:43
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
void read_datagram(DatagramIterator &scan, BamReader *manager)
Reads the object that was previously written to a Bam file.