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  */
475 void TexGenAttrib::
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  */
484 void TexGenAttrib::
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  */
504 int TexGenAttrib::
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 }
static size_t add_hash(size_t start, const void *key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:110
get_name
Returns the name of this texture stage.
Definition: textureStage.h:188
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 indicated key into a running hash.
Definition: stl_compares.I:101
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
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
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 void register_with_read_factory()
Tells the BamReader how to create objects of type TexGenAttrib.
A container for geometry primitives.
Definition: geom.h:54
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
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.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Computes texture coordinates for geometry automatically based on vertex position and/or normal.
Definition: texGenAttrib.h:32
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.