Panda3D
texProjectorEffect.cxx
1 // Filename: texProjectorEffect.cxx
2 // Created by: drose (25Jul04)
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 "texProjectorEffect.h"
16 #include "cullTraverserData.h"
17 #include "texMatrixAttrib.h"
18 #include "lensNode.h"
19 #include "config_pgraph.h"
20 #include "nodePath.h"
21 #include "bamReader.h"
22 #include "bamWriter.h"
23 #include "datagram.h"
24 #include "datagramIterator.h"
25 
26 CPT(RenderEffect) TexProjectorEffect::_empty_effect;
27 TypeHandle TexProjectorEffect::_type_handle;
28 
29 ////////////////////////////////////////////////////////////////////
30 // Function: TexProjectorEffect::Destructor
31 // Access: Public, Virtual
32 // Description:
33 ////////////////////////////////////////////////////////////////////
34 TexProjectorEffect::
35 ~TexProjectorEffect() {
36 }
37 
38 ////////////////////////////////////////////////////////////////////
39 // Function: TexProjectorEffect::make
40 // Access: Published, Static
41 // Description: Constructs a TexProjectorEffect that modifies
42 // no stages at all.
43 ////////////////////////////////////////////////////////////////////
44 CPT(RenderEffect) TexProjectorEffect::
45 make() {
46  // We make it a special case and store a pointer to the empty effect
47  // forever once we find it the first time, as an optimization.
48  if (_empty_effect == (RenderEffect *)NULL) {
49  _empty_effect = return_new(new TexProjectorEffect);
50  }
51 
52  return _empty_effect;
53 }
54 
55 ////////////////////////////////////////////////////////////////////
56 // Function: TexProjectorEffect::add_stage
57 // Access: Published, Static
58 // Description: Returns a new TexProjectorEffect just like this one,
59 // with the indicated projection for the given stage.
60 // If this stage already exists, its projection
61 // definition is replaced.
62 //
63 // The relative transform between the "from" and the
64 // "to" nodes is automatically applied to the texture
65 // transform each frame.
66 //
67 // Furthermore, if the "to" node is a LensNode, its
68 // projection matrix is also applied to the texture
69 // transform. In this case, the lens_index may be used
70 // to select the particular lens that should be used.
71 ////////////////////////////////////////////////////////////////////
72 CPT(RenderEffect) TexProjectorEffect::
73 add_stage(TextureStage *stage, const NodePath &from, const NodePath &to, int lens_index) const {
74  TexProjectorEffect *effect = new TexProjectorEffect(*this);
75  StageDef &def = effect->_stages[stage];
76  def.set_from(from);
77  def.set_to(to);
78  def.set_lens_index(lens_index);
79  return return_new(effect);
80 }
81 
82 ////////////////////////////////////////////////////////////////////
83 // Function: TexProjectorEffect::remove_stage
84 // Access: Published, Static
85 // Description: Returns a new TexProjectorEffect just like this one,
86 // with the indicated stage removed.
87 ////////////////////////////////////////////////////////////////////
88 CPT(RenderEffect) TexProjectorEffect::
89 remove_stage(TextureStage *stage) const {
90  TexProjectorEffect *effect = new TexProjectorEffect(*this);
91  effect->_stages.erase(stage);
92  return return_new(effect);
93 }
94 
95 ////////////////////////////////////////////////////////////////////
96 // Function: TexProjectorEffect::is_empty
97 // Access: Published
98 // Description: Returns true if no stages are defined in the
99 // TexProjectorEffect, false if at least one is.
100 ////////////////////////////////////////////////////////////////////
101 bool TexProjectorEffect::
102 is_empty() const {
103  return _stages.empty();
104 }
105 
106 ////////////////////////////////////////////////////////////////////
107 // Function: TexProjectorEffect::has_stage
108 // Access: Published
109 // Description: Returns true if there is a transform associated with
110 // the indicated stage, or false otherwise (in which
111 // case get_transform(stage) will return the identity
112 // transform).
113 ////////////////////////////////////////////////////////////////////
114 bool TexProjectorEffect::
115 has_stage(TextureStage *stage) const {
116  Stages::const_iterator mi = _stages.find(stage);
117  return (mi != _stages.end());
118 }
119 
120 ////////////////////////////////////////////////////////////////////
121 // Function: TexProjectorEffect::get_from
122 // Access: Published
123 // Description: Returns the "from" node associated with the
124 // TexProjectorEffect on the indicated stage. The
125 // relative transform between the "from" and the "to"
126 // nodes is automatically applied to the texture
127 // transform each frame.
128 ////////////////////////////////////////////////////////////////////
129 NodePath TexProjectorEffect::
130 get_from(TextureStage *stage) const {
131  Stages::const_iterator mi = _stages.find(stage);
132  nassertr(mi != _stages.end(), NodePath::fail());
133  return (*mi).second._from;
134 }
135 
136 ////////////////////////////////////////////////////////////////////
137 // Function: TexProjectorEffect::get_to
138 // Access: Published
139 // Description: Returns the "to" node associated with the
140 // TexProjectorEffect on the indicated stage. The
141 // relative transform between the "from" and the "to"
142 // nodes is automatically applied to the texture
143 // transform each frame.
144 //
145 // Furthermore, if the "to" node is a LensNode, its
146 // projection matrix is also applied to the texture
147 // transform.
148 ////////////////////////////////////////////////////////////////////
149 NodePath TexProjectorEffect::
150 get_to(TextureStage *stage) const {
151  Stages::const_iterator mi = _stages.find(stage);
152  nassertr(mi != _stages.end(), NodePath::fail());
153  return (*mi).second._to;
154 }
155 
156 ////////////////////////////////////////////////////////////////////
157 // Function: TexProjectorEffect::get_lens_index
158 // Access: Published
159 // Description: Returns the lens_index associated with the
160 // TexProjectorEffect on the indicated stage. This is
161 // only used if the "to" node is a LensNode, in which
162 // case it specifies the particular lens that should be
163 // used.
164 ////////////////////////////////////////////////////////////////////
165 int TexProjectorEffect::
166 get_lens_index(TextureStage *stage) const {
167  Stages::const_iterator mi = _stages.find(stage);
168  nassertr(mi != _stages.end(), 0);
169  return (*mi).second._lens_index;
170 }
171 
172 ////////////////////////////////////////////////////////////////////
173 // Function: TexProjectorEffect::output
174 // Access: Public, Virtual
175 // Description:
176 ////////////////////////////////////////////////////////////////////
177 void TexProjectorEffect::
178 output(ostream &out) const {
179  out << get_type() << ":";
180 
181  Stages::const_iterator mi;
182  for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
183  TextureStage *stage = (*mi).first;
184  const StageDef &def = (*mi).second;
185  out << " " << stage->get_name() << "(" << def._to
186  << ", " << def._from << ", " << def._lens_index << ")";
187  }
188 }
189 
190 ////////////////////////////////////////////////////////////////////
191 // Function: TexProjectorEffect::has_cull_callback
192 // Access: Public, Virtual
193 // Description: Should be overridden by derived classes to return
194 // true if cull_callback() has been defined. Otherwise,
195 // returns false to indicate cull_callback() does not
196 // need to be called for this effect during the cull
197 // traversal.
198 ////////////////////////////////////////////////////////////////////
199 bool TexProjectorEffect::
200 has_cull_callback() const {
201  return !_stages.empty();
202 }
203 
204 ////////////////////////////////////////////////////////////////////
205 // Function: TexProjectorEffect::cull_callback
206 // Access: Public, Virtual
207 // Description: If has_cull_callback() returns true, this function
208 // will be called during the cull traversal to perform
209 // any additional operations that should be performed at
210 // cull time. This may include additional manipulation
211 // of render state or additional visible/invisible
212 // decisions, or any other arbitrary operation.
213 //
214 // At the time this function is called, the current
215 // node's transform and state have not yet been applied
216 // to the net_transform and net_state. This callback
217 // may modify the node_transform and node_state to apply
218 // an effective change to the render state at this
219 // level.
220 ////////////////////////////////////////////////////////////////////
221 void TexProjectorEffect::
222 cull_callback(CullTraverser *trav, CullTraverserData &data,
223  CPT(TransformState) &node_transform,
224  CPT(RenderState) &node_state) const {
225  CPT(TexMatrixAttrib) tex_matrix = DCAST(TexMatrixAttrib, TexMatrixAttrib::make());
226 
227  Stages::const_iterator mi;
228  for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
229  TextureStage *stage = (*mi).first;
230  const StageDef &def = (*mi).second;
231 
232  CPT(TransformState) transform = def._from.get_transform(def._to);
233 
234  if (def._to_lens_node != (LensNode *)NULL &&
235  def._to_lens_node->get_lens() != (Lens *)NULL) {
236 
237  // Get the lens's projection matrix, as a TransformState.
238  Lens *lens = def._to_lens_node->get_lens(def._lens_index);
239  if (lens != NULL) {
240  CPT(TransformState) projmat = TransformState::make_mat(lens->get_projection_mat());
241 
242  // We need a special transform to convert the -0.5, 0.5
243  // centering of the lens's projection matrix to UV's in the
244  // range of (0, 1).
245  static CPT(TransformState) fixmat;
246  if (fixmat == (TransformState *)NULL) {
247  fixmat = TransformState::make_pos_hpr_scale
248  (LVecBase3(0.5f, 0.5f, 0.0f),
249  LVecBase3(0.0f, 0.0f, 0.0f),
250  LVecBase3(0.5f, 0.5f, 1.0f));
251  }
252 
253  // Now apply both to the current transform.
254  transform = fixmat->compose(projmat)->compose(transform);
255  }
256  }
257 
258  if (!transform->is_identity()) {
259  tex_matrix = DCAST(TexMatrixAttrib,
260  tex_matrix->add_stage(stage, transform));
261  }
262  }
263 
264  if (!tex_matrix->is_empty()) {
265  node_state = node_state->compose(RenderState::make(tex_matrix));
266  }
267 }
268 
269 ////////////////////////////////////////////////////////////////////
270 // Function: TexProjectorEffect::compare_to_impl
271 // Access: Protected, Virtual
272 // Description: Intended to be overridden by derived TexProjectorEffect
273 // types to return a unique number indicating whether
274 // this TexProjectorEffect is equivalent to the other one.
275 //
276 // This should return 0 if the two TexProjectorEffect objects
277 // are equivalent, a number less than zero if this one
278 // should be sorted before the other one, and a number
279 // greater than zero otherwise.
280 //
281 // This will only be called with two TexProjectorEffect
282 // objects whose get_type() functions return the same.
283 ////////////////////////////////////////////////////////////////////
284 int TexProjectorEffect::
285 compare_to_impl(const RenderEffect *other) const {
286  const TexProjectorEffect *ta;
287  DCAST_INTO_R(ta, other, 0);
288 
289  Stages::const_iterator ai, bi;
290  ai = _stages.begin();
291  bi = ta->_stages.begin();
292  while (ai != _stages.end() && bi != ta->_stages.end()) {
293  if ((*ai).first < (*bi).first) {
294  // This stage is in a but not in b.
295  return -1;
296 
297  } else if ((*bi).first < (*ai).first) {
298  // This stage is in b but not in a.
299  return 1;
300 
301  } else {
302  // This stage is in both; compare the stages.
303  int compare = (*ai).second.compare_to((*bi).second);
304  if (compare != 0) {
305  return compare;
306  }
307  ++ai;
308  ++bi;
309  }
310  }
311 
312  if (bi != ta->_stages.end()) {
313  // a ran out first; b was longer.
314  return -1;
315  }
316 
317  if (ai != _stages.end()) {
318  // b ran out first; a was longer.
319  return 1;
320  }
321 
322  return 0;
323 }
324 
325 ////////////////////////////////////////////////////////////////////
326 // Function: TexProjectorEffect::register_with_read_factory
327 // Access: Public, Static
328 // Description: Tells the BamReader how to create objects of type
329 // TexProjectorEffect.
330 ////////////////////////////////////////////////////////////////////
331 void TexProjectorEffect::
332 register_with_read_factory() {
333  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
334 }
335 
336 ////////////////////////////////////////////////////////////////////
337 // Function: TexProjectorEffect::write_datagram
338 // Access: Public, Virtual
339 // Description: Writes the contents of this object to the datagram
340 // for shipping out to a Bam file.
341 ////////////////////////////////////////////////////////////////////
344  RenderEffect::write_datagram(manager, dg);
345 
346  // For now, we don't write anything to the bam file for a
347  // TexProjectorEffect, except a bogus 0 "size" which may one day
348  // indicate the number of stages in the map that we might write out.
349  dg.add_uint16(0);
350 
351  // One day we will write the whole map out. We don't do this yet,
352  // because (a) we don't have an interface for writing out NodePaths
353  // to a bam file, and (b) it won't matter until we have the
354  // Panda-monium system in place, since you can't load a
355  // TexProjectorEffect from an egg file.
356 }
357 
358 ////////////////////////////////////////////////////////////////////
359 // Function: TexProjectorEffect::complete_pointers
360 // Access: Public, Virtual
361 // Description: Receives an array of pointers, one for each time
362 // manager->read_pointer() was called in fillin().
363 // Returns the number of pointers processed.
364 ////////////////////////////////////////////////////////////////////
367  int pi = RenderEffect::complete_pointers(p_list, manager);
368 
369  return pi;
370 }
371 
372 ////////////////////////////////////////////////////////////////////
373 // Function: TexProjectorEffect::make_from_bam
374 // Access: Protected, Static
375 // Description: This function is called by the BamReader's factory
376 // when a new object of type TexProjectorEffect is encountered
377 // in the Bam file. It should create the TexProjectorEffect
378 // and extract its information from the file.
379 ////////////////////////////////////////////////////////////////////
380 TypedWritable *TexProjectorEffect::
381 make_from_bam(const FactoryParams &params) {
383  DatagramIterator scan;
384  BamReader *manager;
385 
386  parse_params(params, scan, manager);
387  effect->fillin(scan, manager);
388 
389  return effect;
390 }
391 
392 ////////////////////////////////////////////////////////////////////
393 // Function: TexProjectorEffect::fillin
394 // Access: Protected
395 // Description: This internal function is called by make_from_bam to
396 // read in all of the relevant data from the BamFile for
397 // the new TexProjectorEffect.
398 ////////////////////////////////////////////////////////////////////
399 void TexProjectorEffect::
400 fillin(DatagramIterator &scan, BamReader *manager) {
401  RenderEffect::fillin(scan, manager);
402 
403  size_t num_stages = scan.get_uint16();
404 
405  // Since we don't support full reading and writing of
406  // TexProjectorEffects yet, this value had better be zero. If it's
407  // not, maybe we're trying to read a bam file that was generated by
408  // some future version of Panda that does support these things.
409  nassertv(num_stages == 0);
410 }
411 
412 ////////////////////////////////////////////////////////////////////
413 // Function: TexProjectorEffect::StageDef::set_to
414 // Access: Public
415 // Description:
416 ////////////////////////////////////////////////////////////////////
417 void TexProjectorEffect::StageDef::
418 set_to(const NodePath &to) {
419  _to = to;
420  if (!_to.is_empty() && _to.node()->is_of_type(LensNode::get_class_type())) {
421  DCAST_INTO_V(_to_lens_node, _to.node());
422  } else {
423  _to_lens_node = (LensNode *)NULL;
424  }
425 }
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:45
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
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 node that contains a Lens.
Definition: lensNode.h:32
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
This is the base class for a number of special render effects that may be set on scene graph nodes to...
Definition: renderEffect.h:56
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
static NodePath fail()
Creates a NodePath with the ET_fail error type set.
Definition: nodePath.I:185
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()...
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin()...
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
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
const string & get_name() const
Returns the name of this texture stage.
Definition: textureStage.I:32
Applies a transform matrix to UV&#39;s before they are rendered.
const LMatrix4 & get_projection_mat(StereoChannel channel=SC_mono) const
Returns the complete transformation matrix from a 3-d point in space to a point on the film...
Definition: lens.I:717
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 WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
This effect automatically applies a computed texture matrix to the specified texture stage...
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:85
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:38
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48