Panda3D
Loading...
Searching...
No Matches
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
23CPT(RenderAttrib) TexGenAttrib::_empty_attrib;
24TypeHandle TexGenAttrib::_type_handle;
25int TexGenAttrib::_attrib_slot;
26
27/**
28 *
29 */
30TexGenAttrib::
31~TexGenAttrib() {
32}
33
34/**
35 * Constructs a TexGenAttrib that generates no stages at all.
36 */
37CPT(RenderAttrib) TexGenAttrib::
38make() {
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 */
51CPT(RenderAttrib) TexGenAttrib::
52make(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 */
60CPT(RenderAttrib) TexGenAttrib::
61make_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 */
70CPT(RenderAttrib) TexGenAttrib::
71add_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 */
92CPT(RenderAttrib) TexGenAttrib::
93add_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 */
112CPT(RenderAttrib) TexGenAttrib::
113remove_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 */
137bool TexGenAttrib::
138is_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 */
146bool TexGenAttrib::
147has_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 */
156TexGenAttrib::Mode TexGenAttrib::
157get_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 */
170bool TexGenAttrib::
171has_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 */
180const LTexCoord3 &TexGenAttrib::
181get_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 */
192void TexGenAttrib::
193output(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 */
258int TexGenAttrib::
259compare_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 */
304size_t TexGenAttrib::
305get_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 */
333CPT(RenderAttrib) TexGenAttrib::
334compose_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 */
387CPT(RenderAttrib) TexGenAttrib::
388invert_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 */
441void TexGenAttrib::
442filled_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 */
455void TexGenAttrib::
456record_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 */
485write_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 */
505complete_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 */
526TypedWritable *TexGenAttrib::
527make_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 */
542void TexGenAttrib::
543fillin(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.
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.
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...
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...
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.
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.
get_name
Returns the name of this texture stage.
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.
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.
static size_t add_hash(size_t start, const void *key)
Adds the indicated key into a running hash.
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.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.