Panda3D
texGenAttrib.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 texGenAttrib.cxx
10  * @author masad
11  * @date 2004-06-21
12  */
13 
14 #include "texGenAttrib.h"
15 #include "texturePool.h"
17 #include "bamReader.h"
18 #include "bamWriter.h"
19 #include "datagram.h"
20 #include "datagramIterator.h"
21 #include "dcast.h"
22 
23 CPT(RenderAttrib) TexGenAttrib::_empty_attrib;
24 TypeHandle TexGenAttrib::_type_handle;
25 int TexGenAttrib::_attrib_slot;
26 
27 /**
28  *
29  */
30 TexGenAttrib::
31 ~TexGenAttrib() {
32 }
33 
34 /**
35  * Constructs a TexGenAttrib that generates no stages at all.
36  */
37 CPT(RenderAttrib) TexGenAttrib::
38 make() {
39  // We make it a special case and store a pointer to the empty attrib forever
40  // once we find it the first time, as an optimization.
41  if (_empty_attrib == nullptr) {
42  _empty_attrib = return_new(new TexGenAttrib);
43  }
44 
45  return _empty_attrib;
46 }
47 
48 /**
49  * Constructs a TexGenAttrib that generates just the indicated stage.
50  */
51 CPT(RenderAttrib) TexGenAttrib::
52 make(TextureStage *stage, TexGenAttrib::Mode mode) {
53  return DCAST(TexGenAttrib, make())->add_stage(stage, mode);
54 }
55 
56 /**
57  * Returns a RenderAttrib that corresponds to whatever the standard default
58  * properties for render attributes of this type ought to be.
59  */
60 CPT(RenderAttrib) TexGenAttrib::
61 make_default() {
62  return return_new(new TexGenAttrib);
63 }
64 
65 /**
66  * Returns a new TexGenAttrib just like this one, with the indicated
67  * generation mode for the given stage. If this stage already exists, its
68  * mode is replaced.
69  */
70 CPT(RenderAttrib) TexGenAttrib::
71 add_stage(TextureStage *stage, TexGenAttrib::Mode mode) const {
72  nassertr(mode != M_constant, this);
73 
74  CPT(RenderAttrib) removed = remove_stage(stage);
75  TexGenAttrib *attrib = new TexGenAttrib(*DCAST(TexGenAttrib, removed));
76 
77  ModeDef &mode_def = attrib->_stages[stage];
78  mode_def._mode = mode;
79  attrib->record_stage(stage, mode_def);
80 
81  return return_new(attrib);
82 }
83 
84 /**
85  * Returns a new TexGenAttrib just like this one, with the indicated
86  * generation mode for the given stage. If this stage already exists, its
87  * mode is replaced.
88  *
89  * This variant also accepts constant_value, which is only meaningful if mode
90  * is M_constant.
91  */
92 CPT(RenderAttrib) TexGenAttrib::
93 add_stage(TextureStage *stage, TexGenAttrib::Mode mode,
94  const LTexCoord3 &constant_value) const {
95  nassertr(mode == M_constant, this);
96 
97  CPT(RenderAttrib) removed = remove_stage(stage);
98  TexGenAttrib *attrib = new TexGenAttrib(*DCAST(TexGenAttrib, removed));
99 
100  ModeDef &mode_def = attrib->_stages[stage];
101  mode_def._mode = mode;
102  mode_def._constant_value = constant_value;
103  attrib->record_stage(stage, mode_def);
104 
105  return return_new(attrib);
106 }
107 
108 /**
109  * Returns a new TexGenAttrib just like this one, with the indicated stage
110  * removed.
111  */
112 CPT(RenderAttrib) TexGenAttrib::
113 remove_stage(TextureStage *stage) const {
114  Stages::const_iterator si;
115  si = _stages.find(stage);
116  if (si == _stages.end()) {
117  return this;
118  }
119 
120  Mode mode = (*si).second._mode;
121  TexGenAttrib *attrib = new TexGenAttrib(*this);
122  attrib->_stages.erase(stage);
123  attrib->_no_texcoords.erase(stage);
124  if (mode == M_point_sprite) {
125  attrib->_num_point_sprites--;
126  if (attrib->_num_point_sprites == 0) {
127  attrib->_point_geom_rendering &= ~Geom::GR_point_sprite;
128  }
129  }
130  return return_new(attrib);
131 }
132 
133 /**
134  * Returns true if no stages are defined in the TexGenAttrib, false if at
135  * least one is.
136  */
137 bool TexGenAttrib::
138 is_empty() const {
139  return _stages.empty();
140 }
141 
142 /**
143  * Returns true if there is a mode associated with the indicated stage, or
144  * false otherwise (in which case get_transform(stage) will return M_off).
145  */
146 bool TexGenAttrib::
147 has_stage(TextureStage *stage) const {
148  Stages::const_iterator mi = _stages.find(stage);
149  return (mi != _stages.end());
150 }
151 
152 /**
153  * Returns the generation mode associated with the named texture stage, or
154  * M_off if nothing is associated with the indicated stage.
155  */
156 TexGenAttrib::Mode TexGenAttrib::
157 get_mode(TextureStage *stage) const {
158  Stages::const_iterator mi = _stages.find(stage);
159  if (mi != _stages.end()) {
160  return (*mi).second._mode;
161  }
162  return M_off;
163 }
164 
165 /**
166  * Returns true if the indicated TextureStage will have texture coordinates
167  * generated for it automatically (and thus there is no need to upload the
168  * texture coordinates encoded in the vertices).
169  */
170 bool TexGenAttrib::
171 has_gen_texcoord_stage(TextureStage *stage) const {
172  NoTexCoordStages::const_iterator mi = _no_texcoords.find(stage);
173  return (mi != _no_texcoords.end());
174 }
175 
176 /**
177  * Returns the constant value associated with the named texture stage. This
178  * is only meaningful if the mode is M_constant.
179  */
180 const LTexCoord3 &TexGenAttrib::
181 get_constant_value(TextureStage *stage) const {
182  Stages::const_iterator mi = _stages.find(stage);
183  if (mi != _stages.end()) {
184  return (*mi).second._constant_value;
185  }
186  return LTexCoord3::zero();
187 }
188 
189 /**
190  *
191  */
192 void TexGenAttrib::
193 output(std::ostream &out) const {
194  out << get_type() << ":";
195 
196  Stages::const_iterator mi;
197  for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
198  TextureStage *stage = (*mi).first;
199  const ModeDef &mode_def = (*mi).second;
200  out << " " << stage->get_name() << "(";
201  switch (mode_def._mode) {
202  case M_off:
203  out << "off";
204  break;
205 
206  case M_eye_sphere_map:
207  out << "eye_sphere_map";
208  break;
209 
210  case M_world_cube_map:
211  out << "world_cube_map";
212  break;
213  case M_eye_cube_map:
214  out << "eye_cube_map";
215  break;
216 
217  case M_world_normal:
218  out << "world_normal";
219  break;
220  case M_eye_normal:
221  out << "eye_normal";
222  break;
223 
224  case M_world_position:
225  out << "world_position";
226  break;
227  case M_eye_position:
228  out << "eye_position";
229  break;
230 
231  case M_point_sprite:
232  out << "point_sprite";
233  break;
234 
235  case M_constant:
236  out << "constant: " << mode_def._constant_value;
237  break;
238 
239  case M_unused:
240  case M_unused2:
241  break;
242  }
243  out << ")";
244  }
245 }
246 
247 /**
248  * Intended to be overridden by derived TexGenAttrib types to return a unique
249  * number indicating whether this TexGenAttrib is equivalent to the other one.
250  *
251  * This should return 0 if the two TexGenAttrib objects are equivalent, a
252  * number less than zero if this one should be sorted before the other one,
253  * and a number greater than zero otherwise.
254  *
255  * This will only be called with two TexGenAttrib objects whose get_type()
256  * functions return the same.
257  */
258 int TexGenAttrib::
259 compare_to_impl(const RenderAttrib *other) const {
260  const TexGenAttrib *ta = (const TexGenAttrib *)other;
261 
262  Stages::const_iterator ai, bi;
263  ai = _stages.begin();
264  bi = ta->_stages.begin();
265  while (ai != _stages.end() && bi != ta->_stages.end()) {
266  if ((*ai).first < (*bi).first) {
267  // This stage is in a but not in b.
268  return -1;
269 
270  } else if ((*bi).first < (*ai).first) {
271  // This stage is in b but not in a.
272  return 1;
273 
274  } else {
275  // This stage is in both; compare the stages.
276  int compare = (*ai).second.compare_to((*bi).second);
277  if (compare != 0) {
278  return compare;
279  }
280  ++ai;
281  ++bi;
282  }
283  }
284 
285  if (bi != ta->_stages.end()) {
286  // a ran out first; b was longer.
287  return -1;
288  }
289 
290  if (ai != _stages.end()) {
291  // b ran out first; a was longer.
292  return 1;
293  }
294 
295  return 0;
296 }
297 
298 /**
299  * Intended to be overridden by derived RenderAttrib types to return a unique
300  * hash for these particular properties. RenderAttribs that compare the same
301  * with compare_to_impl(), above, should return the same hash; RenderAttribs
302  * that compare differently should return a different hash.
303  */
304 size_t TexGenAttrib::
305 get_hash_impl() const {
306  size_t hash = 0;
307  Stages::const_iterator ri;
308  for (ri = _stages.begin(); ri != _stages.end(); ++ri) {
309  const TextureStage *stage = (*ri).first;
310  const ModeDef &mode_def = (*ri).second;
311 
312  hash = pointer_hash::add_hash(hash, stage);
313  hash = int_hash::add_hash(hash, (int)mode_def._mode);
314  hash = string_hash::add_hash(hash, mode_def._source_name);
315  hash = mode_def._light.add_hash(hash);
316  hash = mode_def._constant_value.add_hash(hash);
317  }
318 
319  return hash;
320 }
321 
322 /**
323  * Intended to be overridden by derived RenderAttrib types to specify how two
324  * consecutive RenderAttrib objects of the same type interact.
325  *
326  * This should return the result of applying the other RenderAttrib to a node
327  * in the scene graph below this RenderAttrib, which was already applied. In
328  * most cases, the result is the same as the other RenderAttrib (that is, a
329  * subsequent RenderAttrib completely replaces the preceding one). On the
330  * other hand, some kinds of RenderAttrib (for instance, ColorTransformAttrib)
331  * might combine in meaningful ways.
332  */
333 CPT(RenderAttrib) TexGenAttrib::
334 compose_impl(const RenderAttrib *other) const {
335  const TexGenAttrib *ta = (const TexGenAttrib *)other;
336 
337  // The composition is the union of the two attribs. In the case when a
338  // stage is in both attribs, we compose the stages.
339 
340  TexGenAttrib *attrib = new TexGenAttrib;
341 
342  Stages::const_iterator ai, bi;
343  ai = _stages.begin();
344  bi = ta->_stages.begin();
345  while (ai != _stages.end() && bi != ta->_stages.end()) {
346  if ((*ai).first < (*bi).first) {
347  // This stage is in a but not in b.
348  attrib->_stages.insert(attrib->_stages.end(), *ai);
349  ++ai;
350 
351  } else if ((*bi).first < (*ai).first) {
352  // This stage is in b but not in a.
353  attrib->_stages.insert(attrib->_stages.end(), *bi);
354  ++bi;
355 
356  } else {
357  // This stage is in both; b wins.
358  attrib->_stages.insert(attrib->_stages.end(), *bi);
359  ++bi;
360  ++ai;
361  }
362  }
363 
364  while (ai != _stages.end()) {
365  // This stage is in a but not in b.
366  attrib->_stages.insert(attrib->_stages.end(), *ai);
367  ++ai;
368  }
369 
370  while (bi != ta->_stages.end()) {
371  // This stage is in b but not in a.
372  attrib->_stages.insert(attrib->_stages.end(), *bi);
373  ++bi;
374  }
375 
376  attrib->filled_stages();
377 
378  return return_new(attrib);
379 }
380 
381 /**
382  * Intended to be overridden by derived RenderAttrib types to specify how two
383  * consecutive RenderAttrib objects of the same type interact.
384  *
385  * See invert_compose() and compose_impl().
386  */
387 CPT(RenderAttrib) TexGenAttrib::
388 invert_compose_impl(const RenderAttrib *other) const {
389  const TexGenAttrib *ta = (const TexGenAttrib *)other;
390 
391  // The inverse composition works a lot like the composition, except we
392  // invert the ai stages.
393 
394  TexGenAttrib *attrib = new TexGenAttrib;
395 
396  Stages::const_iterator ai, bi;
397  ai = _stages.begin();
398  bi = ta->_stages.begin();
399  while (ai != _stages.end() && bi != ta->_stages.end()) {
400  if ((*ai).first < (*bi).first) {
401  // This stage is in a but not in b. Turn a off.
402  attrib->_stages.insert(attrib->_stages.end(), Stages::value_type((*ai).first, ModeDef()));
403  ++ai;
404 
405  } else if ((*bi).first < (*ai).first) {
406  // This stage is in b but not in a.
407  attrib->_stages.insert(attrib->_stages.end(), *bi);
408  ++bi;
409 
410  } else {
411  // This stage is in both; b wins.
412  attrib->_stages.insert(attrib->_stages.end(), *bi);
413  ++bi;
414  ++ai;
415  }
416  }
417 
418  while (ai != _stages.end()) {
419  // This stage is in a but not in b.
420  attrib->_stages.insert(attrib->_stages.end(), Stages::value_type((*ai).first, ModeDef()));
421  ++ai;
422  }
423 
424  while (bi != ta->_stages.end()) {
425  // This stage is in b but not in a.
426  attrib->_stages.insert(attrib->_stages.end(), *bi);
427  ++bi;
428  }
429 
430  attrib->filled_stages();
431 
432  return return_new(attrib);
433 }
434 
435 /**
436  * This method is to be called after the _stages map has been built up
437  * internally through some artificial means; it copies the appropriate
438  * settings to _no_texcoords and updates other internal cache values
439  * appropriately.
440  */
441 void TexGenAttrib::
442 filled_stages() {
443  Stages::iterator ri;
444  for (ri = _stages.begin(); ri != _stages.end(); ++ri) {
445  TextureStage *stage = (*ri).first;
446  ModeDef &mode_def = (*ri).second;
447  record_stage(stage, mode_def);
448  }
449 }
450 
451 /**
452  * Updates the appropriate internal caches before adding the indicated stage
453  * with the given mode to the _stages map.
454  */
455 void TexGenAttrib::
456 record_stage(TextureStage *stage, TexGenAttrib::ModeDef &mode_def) {
457  switch (mode_def._mode) {
458  case M_point_sprite:
459  _no_texcoords.insert(stage);
460  _point_geom_rendering |= Geom::GR_point_sprite;
461  _num_point_sprites++;
462  break;
463 
464  case M_off:
465  break;
466 
467  default:
468  _no_texcoords.insert(stage);
469  }
470 }
471 
472 /**
473  * Tells the BamReader how to create objects of type TexGenAttrib.
474  */
477  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
478 }
479 
480 /**
481  * Writes the contents of this object to the datagram for shipping out to a
482  * Bam file.
483  */
485 write_datagram(BamWriter *manager, Datagram &dg) {
486  RenderAttrib::write_datagram(manager, dg);
487 
488  dg.add_uint16(_stages.size());
489 
490  Stages::const_iterator si;
491  for (si = _stages.begin(); si != _stages.end(); ++si) {
492  TextureStage *stage = (*si).first;
493  Mode mode = (*si).second._mode;
494 
495  manager->write_pointer(dg, stage);
496  dg.add_uint8((unsigned int)mode);
497  }
498 }
499 
500 /**
501  * Receives an array of pointers, one for each time manager->read_pointer()
502  * was called in fillin(). Returns the number of pointers processed.
503  */
505 complete_pointers(TypedWritable **p_list, BamReader *manager) {
506  int pi = RenderAttrib::complete_pointers(p_list, manager);
507 
509  for (mi = _read_modes.begin(); mi != _read_modes.end(); ++mi) {
510  Mode mode = (*mi);
511 
512  TextureStage *stage = DCAST(TextureStage, p_list[pi++]);
513  _stages[stage]._mode = mode;
514  }
515 
516  filled_stages();
517 
518  return pi;
519 }
520 
521 /**
522  * This function is called by the BamReader's factory when a new object of
523  * type TexGenAttrib is encountered in the Bam file. It should create the
524  * TexGenAttrib and extract its information from the file.
525  */
526 TypedWritable *TexGenAttrib::
527 make_from_bam(const FactoryParams &params) {
528  TexGenAttrib *attrib = new TexGenAttrib;
529  DatagramIterator scan;
530  BamReader *manager;
531 
532  parse_params(params, scan, manager);
533  attrib->fillin(scan, manager);
534 
535  return attrib;
536 }
537 
538 /**
539  * This internal function is called by make_from_bam to read in all of the
540  * relevant data from the BamFile for the new TexGenAttrib.
541  */
542 void TexGenAttrib::
543 fillin(DatagramIterator &scan, BamReader *manager) {
544  RenderAttrib::fillin(scan, manager);
545 
546  size_t num_stages = scan.get_uint16();
547 
548  // For now, read in a linear list of the modes we will assign to each
549  // associated TextureStage pointer. Later, in complete_pointers, we'll fill
550  // up the map the with appropriate TextureStageMode pairing.
551  _read_modes.clear();
552  _read_modes.reserve(num_stages);
553  for (size_t i = 0; i < num_stages; i++) {
554  manager->read_pointer(scan);
555  Mode mode = (Mode)scan.get_uint8();
556  _read_modes.push_back(mode);
557  }
558 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
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
A class to retrieve the individual data elements previously stored in a Datagram.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
A container for geometry primitives.
Definition: geom.h:54
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Computes texture coordinates for geometry automatically based on vertex position and/or normal.
Definition: texGenAttrib.h:32
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
static void register_with_read_factory()
Tells the BamReader how to create objects of type TexGenAttrib.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
get_name
Returns the name of this texture stage.
Definition: textureStage.h:190
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
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 size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:101
static size_t add_hash(size_t start, const void *key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:110
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
static size_t add_hash(size_t start, const Key &key)
Adds the elements of the indicated key into a running hash.
Definition: stl_compares.I:168
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(RenderAttrib) TexGenAttrib
Constructs a TexGenAttrib that generates no stages at all.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.