Panda3D

lightAttrib.cxx

00001 // Filename: lightAttrib.cxx
00002 // Created by:  drose (26Mar02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "lightAttrib.h"
00016 #include "pandaNode.h"
00017 #include "nodePath.h"
00018 #include "graphicsStateGuardianBase.h"
00019 #include "bamReader.h"
00020 #include "bamWriter.h"
00021 #include "datagram.h"
00022 #include "datagramIterator.h"
00023 #include "config_pgraph.h"
00024 #include "attribNodeRegistry.h"
00025 #include "indent.h"
00026 
00027 CPT(RenderAttrib) LightAttrib::_empty_attrib;
00028 int LightAttrib::_attrib_slot;
00029 CPT(RenderAttrib) LightAttrib::_all_off_attrib;
00030 TypeHandle LightAttrib::_type_handle;
00031 
00032 // This STL Function object is used in filter_to_max(), below, to sort
00033 // a list of Lights in reverse order by priority.  In the case of two
00034 // lights with equal priority, the class priority is compared.
00035 class CompareLightPriorities {
00036 public:
00037   bool operator ()(const NodePath &a, const NodePath &b) const {
00038     nassertr(!a.is_empty() && !b.is_empty(), a < b);
00039     Light *la = a.node()->as_light();
00040     Light *lb = b.node()->as_light();
00041     nassertr(la != (Light *)NULL && lb != (Light *)NULL, a < b);
00042              
00043     if (la->get_priority() != lb->get_priority()) {
00044       return la->get_priority() > lb->get_priority();
00045     }
00046     return la->get_class_priority() > lb->get_class_priority();
00047   }
00048 };
00049 
00050 ////////////////////////////////////////////////////////////////////
00051 //     Function: LightAttrib::make
00052 //       Access: Published, Static
00053 //  Description: Constructs a new LightAttrib object that turns on (or
00054 //               off, according to op) the indicated light(s).
00055 //
00056 //               This method is now deprecated.  Use add_on_light() or
00057 //               add_off_light() instead.
00058 ////////////////////////////////////////////////////////////////////
00059 CPT(RenderAttrib) LightAttrib::
00060 make(LightAttrib::Operation op, Light *light) {
00061   pgraph_cat.warning()
00062     << "Using deprecated LightAttrib interface.\n";
00063 
00064   CPT(RenderAttrib) attrib;
00065 
00066   switch (op) {
00067   case O_set:
00068     attrib = make_all_off();
00069     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light->as_node()));
00070     return attrib;
00071    
00072   case O_add:
00073     attrib = make();
00074     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light->as_node()));
00075     return attrib;
00076 
00077   case O_remove:
00078     attrib = make();
00079     attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light->as_node()));
00080     return attrib;
00081   }
00082 
00083   nassertr(false, make());
00084   return make();
00085 }
00086 
00087 ////////////////////////////////////////////////////////////////////
00088 //     Function: LightAttrib::make
00089 //       Access: Published, Static
00090 //  Description: Constructs a new LightAttrib object that turns on (or
00091 //               off, according to op) the indicate light(s).
00092 //
00093 //               This method is now deprecated.  Use add_on_light() or
00094 //               add_off_light() instead.
00095 ////////////////////////////////////////////////////////////////////
00096 CPT(RenderAttrib) LightAttrib::
00097 make(LightAttrib::Operation op, Light *light1, Light *light2) {
00098   pgraph_cat.warning()
00099     << "Using deprecated LightAttrib interface.\n";
00100 
00101   CPT(RenderAttrib) attrib;
00102 
00103   switch (op) {
00104   case O_set:
00105     attrib = make_all_off();
00106     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
00107     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
00108     return attrib;
00109    
00110   case O_add:
00111     attrib = make();
00112     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
00113     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
00114     return attrib;
00115 
00116   case O_remove:
00117     attrib = make();
00118     attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light1->as_node()));
00119     attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light2->as_node()));
00120     return attrib;
00121   }
00122 
00123   nassertr(false, make());
00124   return make();
00125 }
00126 
00127 ////////////////////////////////////////////////////////////////////
00128 //     Function: LightAttrib::make
00129 //       Access: Published, Static
00130 //  Description: Constructs a new LightAttrib object that turns on (or
00131 //               off, according to op) the indicate light(s).
00132 //
00133 //               This method is now deprecated.  Use add_on_light() or
00134 //               add_off_light() instead.
00135 ////////////////////////////////////////////////////////////////////
00136 CPT(RenderAttrib) LightAttrib::
00137 make(LightAttrib::Operation op, Light *light1, Light *light2,
00138      Light *light3) { 
00139   pgraph_cat.warning()
00140     << "Using deprecated LightAttrib interface.\n";
00141 
00142   CPT(RenderAttrib) attrib;
00143 
00144   switch (op) {
00145   case O_set:
00146     attrib = make_all_off();
00147     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
00148     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
00149     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light3->as_node()));
00150     return attrib;
00151    
00152   case O_add:
00153     attrib = make();
00154     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
00155     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
00156     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light3->as_node()));
00157     return attrib;
00158 
00159   case O_remove:
00160     attrib = make();
00161     attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light1->as_node()));
00162     attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light2->as_node()));
00163     attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light3->as_node()));
00164     return attrib;
00165   }
00166 
00167   nassertr(false, make());
00168   return make();
00169 }
00170 
00171 ////////////////////////////////////////////////////////////////////
00172 //     Function: LightAttrib::make
00173 //       Access: Published, Static
00174 //  Description: Constructs a new LightAttrib object that turns on (or
00175 //               off, according to op) the indicate light(s).
00176 //
00177 //               This method is now deprecated.  Use add_on_light() or
00178 //               add_off_light() instead.
00179 ////////////////////////////////////////////////////////////////////
00180 CPT(RenderAttrib) LightAttrib::
00181 make(LightAttrib::Operation op, Light *light1, Light *light2,
00182      Light *light3, Light *light4) {
00183   pgraph_cat.warning()
00184     << "Using deprecated LightAttrib interface.\n";
00185 
00186   CPT(RenderAttrib) attrib;
00187 
00188   switch (op) {
00189   case O_set:
00190     attrib = make_all_off();
00191     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
00192     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
00193     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light3->as_node()));
00194     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light4->as_node()));
00195     return attrib;
00196    
00197   case O_add:
00198     attrib = make();
00199     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
00200     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
00201     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light3->as_node()));
00202     attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light4->as_node()));
00203     return attrib;
00204 
00205   case O_remove:
00206     attrib = make();
00207     attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light1->as_node()));
00208     attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light2->as_node()));
00209     attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light3->as_node()));
00210     attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light4->as_node()));
00211     return attrib;
00212   }
00213 
00214   nassertr(false, make());
00215   return make();
00216 }
00217 
00218 ////////////////////////////////////////////////////////////////////
00219 //     Function: LightAttrib::make_default
00220 //       Access: Published, Static
00221 //  Description: Returns a RenderAttrib that corresponds to whatever
00222 //               the standard default properties for render attributes
00223 //               of this type ought to be.
00224 ////////////////////////////////////////////////////////////////////
00225 CPT(RenderAttrib) LightAttrib::
00226 make_default() {
00227   return return_new(new LightAttrib);
00228 }
00229 
00230 ////////////////////////////////////////////////////////////////////
00231 //     Function: LightAttrib::get_operation
00232 //       Access: Published
00233 //  Description: Returns the basic operation type of the LightAttrib.
00234 //               If this is O_set, the lights listed here completely
00235 //               replace any lights that were already on.  If this is
00236 //               O_add, the lights here are added to the set of of
00237 //               lights that were already on, and if O_remove, the
00238 //               lights here are removed from the set of lights that
00239 //               were on.
00240 //
00241 //               This method is now deprecated.  LightAttribs nowadays
00242 //               have a separate list of on_lights and off_lights, so
00243 //               this method doesn't make sense.  Query the lists
00244 //               independently.
00245 ////////////////////////////////////////////////////////////////////
00246 LightAttrib::Operation LightAttrib::
00247 get_operation() const {
00248   pgraph_cat.warning()
00249     << "Using deprecated LightAttrib interface.\n";
00250 
00251   if (has_all_off()) {
00252     return O_set;
00253 
00254   } else if (get_num_off_lights() == 0) {
00255     return O_add;
00256 
00257   } else {
00258     return O_remove;
00259   }
00260 }
00261 
00262 ////////////////////////////////////////////////////////////////////
00263 //     Function: LightAttrib::get_num_lights
00264 //       Access: Published
00265 //  Description: Returns the number of lights listed in the attribute.
00266 //
00267 //               This method is now deprecated.  LightAttribs nowadays
00268 //               have a separate list of on_lights and off_lights, so
00269 //               this method doesn't make sense.  Query the lists
00270 //               independently.
00271 ////////////////////////////////////////////////////////////////////
00272 int LightAttrib::
00273 get_num_lights() const {
00274   pgraph_cat.warning()
00275     << "Using deprecated LightAttrib interface.\n";
00276 
00277   if (get_num_off_lights() == 0) {
00278     return get_num_on_lights();
00279   } else {
00280     return get_num_off_lights();
00281   }
00282 }
00283 
00284 ////////////////////////////////////////////////////////////////////
00285 //     Function: LightAttrib::get_light
00286 //       Access: Published
00287 //  Description: Returns the nth light listed in the attribute.
00288 //
00289 //               This method is now deprecated.  LightAttribs nowadays
00290 //               have a separate list of on_lights and off_lights, so
00291 //               this method doesn't make sense.  Query the lists
00292 //               independently.
00293 ////////////////////////////////////////////////////////////////////
00294 Light *LightAttrib::
00295 get_light(int n) const {
00296   pgraph_cat.warning()
00297     << "Using deprecated LightAttrib interface.\n";
00298 
00299   if (get_num_off_lights() == 0) {
00300     return get_on_light(n).node()->as_light();
00301   } else {
00302     return get_off_light(n).node()->as_light();
00303   }
00304 }
00305 
00306 ////////////////////////////////////////////////////////////////////
00307 //     Function: LightAttrib::has_light
00308 //       Access: Published
00309 //  Description: Returns true if the indicated light is listed in the
00310 //               attrib, false otherwise.
00311 //
00312 //               This method is now deprecated.  LightAttribs nowadays
00313 //               have a separate list of on_lights and off_lights, so
00314 //               this method doesn't make sense.  Query the lists
00315 //               independently.
00316 ////////////////////////////////////////////////////////////////////
00317 bool LightAttrib::
00318 has_light(Light *light) const {
00319   pgraph_cat.warning()
00320     << "Using deprecated LightAttrib interface.\n";
00321 
00322   if (get_num_off_lights() == 0) {
00323     return has_on_light(NodePath(light->as_node()));
00324   } else {
00325     return has_off_light(NodePath(light->as_node()));
00326   }
00327 }
00328 
00329 ////////////////////////////////////////////////////////////////////
00330 //     Function: LightAttrib::add_light
00331 //       Access: Published
00332 //  Description: Returns a new LightAttrib, just like this one, but
00333 //               with the indicated light added to the list of lights.
00334 //
00335 //               This method is now deprecated.  Use add_on_light() or
00336 //               add_off_light() instead.
00337 ////////////////////////////////////////////////////////////////////
00338 CPT(RenderAttrib) LightAttrib::
00339 add_light(Light *light) const {
00340   pgraph_cat.warning()
00341     << "Using deprecated LightAttrib interface.\n";
00342 
00343   if (get_num_off_lights() == 0) {
00344     return add_on_light(NodePath(light->as_node()));
00345   } else {
00346     return add_off_light(NodePath(light->as_node()));
00347   }
00348 }
00349 
00350 ////////////////////////////////////////////////////////////////////
00351 //     Function: LightAttrib::remove_light
00352 //       Access: Published
00353 //  Description: Returns a new LightAttrib, just like this one, but
00354 //               with the indicated light removed from the list of
00355 //               lights.
00356 //
00357 //               This method is now deprecated.  Use remove_on_light()
00358 //               or remove_off_light() instead.
00359 ////////////////////////////////////////////////////////////////////
00360 CPT(RenderAttrib) LightAttrib::
00361 remove_light(Light *light) const {
00362   pgraph_cat.warning()
00363     << "Using deprecated LightAttrib interface.\n";
00364 
00365   if (get_num_off_lights() == 0) {
00366     return remove_on_light(NodePath(light->as_node()));
00367   } else {
00368     return remove_off_light(NodePath(light->as_node()));
00369   }
00370 }
00371 
00372 ////////////////////////////////////////////////////////////////////
00373 //     Function: LightAttrib::make
00374 //       Access: Published, Static
00375 //  Description: Constructs a new LightAttrib object that does
00376 //               nothing.
00377 ////////////////////////////////////////////////////////////////////
00378 CPT(RenderAttrib) LightAttrib::
00379 make() {
00380   // We make it a special case and store a pointer to the empty attrib
00381   // forever once we find it the first time, as an optimization.
00382   if (_empty_attrib == (RenderAttrib *)NULL) {
00383     _empty_attrib = return_new(new LightAttrib);
00384   }
00385 
00386   return _empty_attrib;
00387 }
00388 
00389 ////////////////////////////////////////////////////////////////////
00390 //     Function: LightAttrib::make_all_off
00391 //       Access: Published, Static
00392 //  Description: Constructs a new LightAttrib object that turns off
00393 //               all lights (and hence disables lighting).
00394 ////////////////////////////////////////////////////////////////////
00395 CPT(RenderAttrib) LightAttrib::
00396 make_all_off() {
00397   // We make it a special case and store a pointer to the off attrib
00398   // forever once we find it the first time, as an optimization.
00399   if (_all_off_attrib == (RenderAttrib *)NULL) {
00400     LightAttrib *attrib = new LightAttrib;
00401     attrib->_off_all_lights = true;
00402     _all_off_attrib = return_new(attrib);
00403   }
00404 
00405   return _all_off_attrib;
00406 }
00407 
00408 ////////////////////////////////////////////////////////////////////
00409 //     Function: LightAttrib::add_on_light
00410 //       Access: Published
00411 //  Description: Returns a new LightAttrib, just like this one, but
00412 //               with the indicated light added to the list of lights
00413 //               turned on by this attrib.
00414 ////////////////////////////////////////////////////////////////////
00415 CPT(RenderAttrib) LightAttrib::
00416 add_on_light(const NodePath &light) const {
00417   nassertr(!light.is_empty() && light.node()->as_light() != (Light *)NULL, this);
00418   LightAttrib *attrib = new LightAttrib(*this);
00419   attrib->_on_lights.insert(light);
00420   attrib->_off_lights.erase(light);
00421 
00422   pair<Lights::iterator, bool> insert_result = 
00423     attrib->_on_lights.insert(Lights::value_type(light));
00424   if (insert_result.second) {
00425     // Also ensure it is removed from the off_lights list.
00426     attrib->_off_lights.erase(light);
00427   }
00428 
00429   return return_new(attrib);
00430 }
00431 
00432 ////////////////////////////////////////////////////////////////////
00433 //     Function: LightAttrib::remove_on_light
00434 //       Access: Published
00435 //  Description: Returns a new LightAttrib, just like this one, but
00436 //               with the indicated light removed from the list of
00437 //               lights turned on by this attrib.
00438 ////////////////////////////////////////////////////////////////////
00439 CPT(RenderAttrib) LightAttrib::
00440 remove_on_light(const NodePath &light) const {
00441   nassertr(!light.is_empty() && light.node()->as_light() != (Light *)NULL, this);
00442   LightAttrib *attrib = new LightAttrib(*this);
00443   attrib->_on_lights.erase(light);
00444   return return_new(attrib);
00445 }
00446 
00447 ////////////////////////////////////////////////////////////////////
00448 //     Function: LightAttrib::add_off_light
00449 //       Access: Published
00450 //  Description: Returns a new LightAttrib, just like this one, but
00451 //               with the indicated light added to the list of lights
00452 //               turned off by this attrib.
00453 ////////////////////////////////////////////////////////////////////
00454 CPT(RenderAttrib) LightAttrib::
00455 add_off_light(const NodePath &light) const {
00456   nassertr(!light.is_empty() && light.node()->as_light() != (Light *)NULL, this);
00457   LightAttrib *attrib = new LightAttrib(*this);
00458   if (!_off_all_lights) {
00459     attrib->_off_lights.insert(light);
00460   }
00461   attrib->_on_lights.erase(light);
00462   return return_new(attrib);
00463 }
00464 
00465 ////////////////////////////////////////////////////////////////////
00466 //     Function: LightAttrib::remove_off_light
00467 //       Access: Published
00468 //  Description: Returns a new LightAttrib, just like this one, but
00469 //               with the indicated light removed from the list of
00470 //               lights turned off by this attrib.
00471 ////////////////////////////////////////////////////////////////////
00472 CPT(RenderAttrib) LightAttrib::
00473 remove_off_light(const NodePath &light) const {
00474   nassertr(!light.is_empty() && light.node()->as_light() != (Light *)NULL, this);
00475   LightAttrib *attrib = new LightAttrib(*this);
00476   attrib->_off_lights.erase(light);
00477   return return_new(attrib);
00478 }
00479 
00480 ////////////////////////////////////////////////////////////////////
00481 //     Function: LightAttrib::filter_to_max
00482 //       Access: Public
00483 //  Description: Returns a new LightAttrib, very much like this one,
00484 //               but with the number of on_lights reduced to be no
00485 //               more than max_lights.  The number of off_lights in
00486 //               the new LightAttrib is undefined.
00487 //
00488 //               The number of AmbientLights is not included in the
00489 //               count.  All AmbientLights in the original attrib are
00490 //               always included in the result, regardless of the
00491 //               value of max_lights.
00492 ////////////////////////////////////////////////////////////////////
00493 CPT(LightAttrib) LightAttrib::
00494 filter_to_max(int max_lights) const {
00495   if (max_lights < 0 || (int)_on_lights.size() <= max_lights) {
00496     // Trivial case: this LightAttrib qualifies.
00497     return this;
00498   }
00499 
00500   // Since check_filtered() will clear the _filtered list if we are out
00501   // of date, we should call it first.
00502   check_filtered();
00503 
00504   Filtered::const_iterator fi;
00505   fi = _filtered.find(max_lights);
00506   if (fi != _filtered.end()) {
00507     // Easy case: we have already computed this for this particular
00508     // LightAttrib.
00509     return (*fi).second;
00510   }
00511 
00512   // Harder case: we have to compute it now.  We must choose the n
00513   // lights with the highest priority in our list of lights.
00514   Lights priority_lights, ambient_lights;
00515 
00516   // Separate the list of lights into ambient lights and other lights.
00517   Lights::const_iterator li;
00518   for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
00519     const NodePath &np = (*li);
00520     nassertr(!np.is_empty() && np.node()->as_light() != (Light *)NULL, this);
00521     if (np.node()->is_ambient_light()) {
00522       ambient_lights.push_back(np);
00523     } else {
00524       priority_lights.push_back(np);
00525     }
00526   }
00527 
00528   // This sort function uses the STL function object defined above.
00529   sort(priority_lights.begin(), priority_lights.end(), 
00530        CompareLightPriorities());
00531 
00532   // Now lop off all of the lights after the first max_lights.
00533   if ((int)priority_lights.size() > max_lights) { 
00534     priority_lights.erase(priority_lights.begin() + max_lights,
00535                           priority_lights.end());
00536   }
00537 
00538   // Put the ambient lights back into the list.
00539   for (li = ambient_lights.begin(); li != ambient_lights.end(); ++li) {
00540     priority_lights.push_back(*li);
00541   }
00542 
00543   // And re-sort the ov_set into its proper order.
00544   priority_lights.sort();
00545 
00546   // Now create a new attrib reflecting these lights.
00547   PT(LightAttrib) attrib = new LightAttrib;
00548   attrib->_on_lights.swap(priority_lights);
00549 
00550   CPT(RenderAttrib) new_attrib = return_new(attrib);
00551 
00552   // Finally, record this newly-created attrib in the map for next
00553   // time.
00554   CPT(LightAttrib) light_attrib = (const LightAttrib *)new_attrib.p();
00555   ((LightAttrib *)this)->_filtered[max_lights] = light_attrib;
00556   return light_attrib;
00557 }
00558 
00559 ////////////////////////////////////////////////////////////////////
00560 //     Function: LightAttrib::get_most_important_light
00561 //       Access: Public
00562 //  Description: Returns the most important light (that is, the light
00563 //               with the highest priority) in the LightAttrib,
00564 //               excluding any ambient lights.  Returns an empty
00565 //               NodePath if no non-ambient lights are found.
00566 ////////////////////////////////////////////////////////////////////
00567 NodePath LightAttrib::
00568 get_most_important_light() const {
00569   NodePath best;
00570 
00571   CompareLightPriorities compare;
00572 
00573   Lights::const_iterator li;
00574   for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
00575     const NodePath &np = (*li);
00576     nassertr(!np.is_empty() && np.node()->as_light() != (Light *)NULL, NodePath());
00577     if (!np.node()->is_ambient_light()) {
00578       if (best.is_empty() || compare(np, best)) {
00579         best = np;
00580       }
00581     }
00582   }
00583 
00584   return best;
00585 }
00586 
00587 ////////////////////////////////////////////////////////////////////
00588 //     Function: LightAttrib::output
00589 //       Access: Public, Virtual
00590 //  Description: 
00591 ////////////////////////////////////////////////////////////////////
00592 void LightAttrib::
00593 output(ostream &out) const {
00594   out << get_type() << ":";
00595   if (_off_lights.empty()) {
00596     if (_on_lights.empty()) {
00597       if (_off_all_lights) {
00598         out << "all off";
00599       } else {
00600         out << "identity";
00601       }
00602     } else {
00603       if (_off_all_lights) {
00604         out << "set";
00605       } else {
00606         out << "on";
00607       }
00608     }
00609 
00610   } else {
00611     out << "off";
00612     Lights::const_iterator fi;
00613     for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
00614       NodePath light = (*fi);
00615       if (light.is_empty()) {
00616         out << " " << light;
00617       } else {
00618         out << " " << light.get_name();
00619       }        
00620     }
00621 
00622     if (!_on_lights.empty()) {
00623       out << " on";
00624     }
00625   }
00626     
00627   Lights::const_iterator li;
00628   for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
00629     NodePath light = (*li);
00630     if (light.is_empty()) {
00631       out << " " << light;
00632     } else {
00633       out << " " << light.get_name();
00634     }        
00635   }
00636 }
00637 
00638 ////////////////////////////////////////////////////////////////////
00639 //     Function: LightAttrib::write
00640 //       Access: Public, Virtual
00641 //  Description: 
00642 ////////////////////////////////////////////////////////////////////
00643 void LightAttrib::
00644 write(ostream &out, int indent_level) const {
00645   indent(out, indent_level) << get_type() << ":";
00646   if (_off_lights.empty()) {
00647     if (_on_lights.empty()) {
00648       if (_off_all_lights) {
00649         out << "all off\n";
00650       } else {
00651         out << "identity\n";
00652       }
00653     } else {
00654       if (_off_all_lights) {
00655         out << "set\n";
00656       } else {
00657         out << "on\n";
00658       }
00659     }
00660 
00661   } else {
00662     out << "off\n";
00663     Lights::const_iterator fi;
00664     for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
00665       NodePath light = (*fi);
00666       indent(out, indent_level + 2) << light << "\n";
00667     }
00668 
00669     if (!_on_lights.empty()) {
00670       indent(out, indent_level) << "on\n";
00671     }
00672   }
00673     
00674   Lights::const_iterator li;
00675   for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
00676     NodePath light = (*li);
00677     indent(out, indent_level + 2) << light << "\n";
00678   }
00679 }
00680 
00681 ////////////////////////////////////////////////////////////////////
00682 //     Function: LightAttrib::compare_to_impl
00683 //       Access: Protected, Virtual
00684 //  Description: Intended to be overridden by derived LightAttrib
00685 //               types to return a unique number indicating whether
00686 //               this LightAttrib is equivalent to the other one.
00687 //
00688 //               This should return 0 if the two LightAttrib objects
00689 //               are equivalent, a number less than zero if this one
00690 //               should be sorted before the other one, and a number
00691 //               greater than zero otherwise.
00692 //
00693 //               This will only be called with two LightAttrib
00694 //               objects whose get_type() functions return the same.
00695 ////////////////////////////////////////////////////////////////////
00696 int LightAttrib::
00697 compare_to_impl(const RenderAttrib *other) const {
00698   const LightAttrib *ta;
00699   DCAST_INTO_R(ta, other, 0);
00700 
00701   if (_off_all_lights != ta->_off_all_lights) {
00702     return (int)_off_all_lights - (int)ta->_off_all_lights;
00703   }
00704 
00705   Lights::const_iterator li = _on_lights.begin();
00706   Lights::const_iterator oli = ta->_on_lights.begin();
00707 
00708   while (li != _on_lights.end() && oli != ta->_on_lights.end()) {
00709     NodePath light = (*li);
00710     NodePath other_light = (*oli);
00711 
00712     int compare = light.compare_to(other_light);
00713     if (compare != 0) {
00714       return compare;
00715     }
00716 
00717     ++li;
00718     ++oli;
00719   }
00720 
00721   if (li != _on_lights.end()) {
00722     return 1;
00723   }
00724   if (oli != ta->_on_lights.end()) {
00725     return -1;
00726   }
00727 
00728   Lights::const_iterator fi = _off_lights.begin();
00729   Lights::const_iterator ofi = ta->_off_lights.begin();
00730 
00731   while (fi != _off_lights.end() && ofi != ta->_off_lights.end()) {
00732     NodePath light = (*fi);
00733     NodePath other_light = (*ofi);
00734 
00735     int compare = light.compare_to(other_light);
00736     if (compare != 0) {
00737       return compare;
00738     }
00739 
00740     ++fi;
00741     ++ofi;
00742   }
00743 
00744   if (fi != _off_lights.end()) {
00745     return 1;
00746   }
00747   if (ofi != ta->_off_lights.end()) {
00748     return -1;
00749   }
00750   
00751   return 0;
00752 }
00753 
00754 ////////////////////////////////////////////////////////////////////
00755 //     Function: LightAttrib::compose_impl
00756 //       Access: Protected, Virtual
00757 //  Description: Intended to be overridden by derived RenderAttrib
00758 //               types to specify how two consecutive RenderAttrib
00759 //               objects of the same type interact.
00760 //
00761 //               This should return the result of applying the other
00762 //               RenderAttrib to a node in the scene graph below this
00763 //               RenderAttrib, which was already applied.  In most
00764 //               cases, the result is the same as the other
00765 //               RenderAttrib (that is, a subsequent RenderAttrib
00766 //               completely replaces the preceding one).  On the other
00767 //               hand, some kinds of RenderAttrib (for instance,
00768 //               ColorTransformAttrib) might combine in meaningful
00769 //               ways.
00770 ////////////////////////////////////////////////////////////////////
00771 CPT(RenderAttrib) LightAttrib::
00772 compose_impl(const RenderAttrib *other) const {
00773   const LightAttrib *ta;
00774   DCAST_INTO_R(ta, other, 0);
00775 
00776   if (ta->_off_all_lights) {
00777     // If the other type turns off all lights, it doesn't matter what
00778     // we are.
00779     return ta;
00780   }
00781 
00782   // This is a three-way merge between ai, bi, and ci, except that bi
00783   // and ci should have no intersection and therefore needn't be
00784   // compared to each other.
00785   Lights::const_iterator ai = _on_lights.begin();
00786   Lights::const_iterator bi = ta->_on_lights.begin();
00787   Lights::const_iterator ci = ta->_off_lights.begin();
00788 
00789   // Create a new LightAttrib that will hold the result.
00790   LightAttrib *new_attrib = new LightAttrib;
00791   back_insert_iterator<Lights> result = 
00792     back_inserter(new_attrib->_on_lights);
00793 
00794   while (ai != _on_lights.end() && 
00795          bi != ta->_on_lights.end() && 
00796          ci != ta->_off_lights.end()) {
00797     if ((*ai) < (*bi)) {
00798       if ((*ai) < (*ci)) {
00799         // Here is a light that we have in the original, which is not
00800         // present in the secondary.
00801         *result = *ai;
00802         ++ai;
00803         ++result;
00804 
00805       } else if ((*ci) < (*ai)) {
00806         // Here is a light that is turned off in the secondary, but
00807         // was not present in the original.
00808         ++ci;
00809 
00810       } else { // (*ci) == (*ai)
00811         // Here is a light that is turned off in the secondary, and
00812         // was present in the original.
00813         ++ai;
00814         ++ci;
00815       }
00816 
00817     } else if ((*bi) < (*ai)) {
00818       // Here is a new light we have in the secondary, that was not
00819       // present in the original.
00820       *result = *bi;
00821       ++bi;
00822       ++result;
00823 
00824     } else {  // (*bi) == (*ai)
00825       // Here is a light we have in both.
00826       *result = *bi;
00827       ++ai;
00828       ++bi;
00829       ++result;
00830     }
00831   }
00832 
00833   while (ai != _on_lights.end() && bi != ta->_on_lights.end()) {
00834     if ((*ai) < (*bi)) {
00835       // Here is a light that we have in the original, which is not
00836       // present in the secondary.
00837       *result = *ai;
00838       ++ai;
00839       ++result;
00840 
00841     } else if ((*bi) < (*ai)) {
00842       // Here is a new light we have in the secondary, that was not
00843       // present in the original.
00844       *result = *bi;
00845       ++bi;
00846       ++result;
00847 
00848     } else {
00849       // Here is a light we have in both.
00850       *result = *bi;
00851       ++ai;
00852       ++bi;
00853       ++result;
00854     }
00855   }
00856 
00857   while (ai != _on_lights.end() && ci != ta->_off_lights.end()) {
00858     if ((*ai) < (*ci)) {
00859       // Here is a light that we have in the original, which is not
00860       // present in the secondary.
00861       *result = *ai;
00862       ++ai;
00863       ++result;
00864       
00865     } else if ((*ci) < (*ai)) {
00866       // Here is a light that is turned off in the secondary, but
00867       // was not present in the original.
00868       ++ci;
00869       
00870     } else { // (*ci) == (*ai)
00871       // Here is a light that is turned off in the secondary, and
00872       // was present in the original.
00873       ++ai;
00874       ++ci;
00875     }
00876   }
00877 
00878   while (ai != _on_lights.end()) {
00879     *result = *ai;
00880     ++ai;
00881     ++result;
00882   }
00883 
00884   while (bi != ta->_on_lights.end()) {
00885     *result = *bi;
00886     ++bi;
00887     ++result;
00888   }
00889 
00890   return return_new(new_attrib);
00891 }
00892 
00893 ////////////////////////////////////////////////////////////////////
00894 //     Function: LightAttrib::invert_compose_impl
00895 //       Access: Protected, Virtual
00896 //  Description: Intended to be overridden by derived RenderAttrib
00897 //               types to specify how two consecutive RenderAttrib
00898 //               objects of the same type interact.
00899 //
00900 //               See invert_compose() and compose_impl().
00901 ////////////////////////////////////////////////////////////////////
00902 CPT(RenderAttrib) LightAttrib::
00903 invert_compose_impl(const RenderAttrib *other) const {
00904   // I think in this case the other attrib always wins.  Maybe this
00905   // needs a bit more thought.  It's hard to imagine that it's even
00906   // important to compute this properly.
00907   return other;
00908 }
00909 
00910 ////////////////////////////////////////////////////////////////////
00911 //     Function: LightAttrib::sort_on_lights
00912 //       Access: Private
00913 //  Description: This is patterned after
00914 //               TextureAttrib::sort_on_stages(), but since lights
00915 //               don't actually require sorting, this only empties the
00916 //               _filtered map.
00917 ////////////////////////////////////////////////////////////////////
00918 void LightAttrib::
00919 sort_on_lights() {
00920   _sort_seq = Light::get_sort_seq();
00921   _filtered.clear();
00922 }
00923 
00924 ////////////////////////////////////////////////////////////////////
00925 //     Function: LightAttrib::register_with_read_factory
00926 //       Access: Public, Static
00927 //  Description: Tells the BamReader how to create objects of type
00928 //               LightAttrib.
00929 ////////////////////////////////////////////////////////////////////
00930 void LightAttrib::
00931 register_with_read_factory() {
00932   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00933 }
00934 
00935 ////////////////////////////////////////////////////////////////////
00936 //     Function: LightAttrib::write_datagram
00937 //       Access: Public, Virtual
00938 //  Description: Writes the contents of this object to the datagram
00939 //               for shipping out to a Bam file.
00940 ////////////////////////////////////////////////////////////////////
00941 void LightAttrib::
00942 write_datagram(BamWriter *manager, Datagram &dg) {
00943   RenderAttrib::write_datagram(manager, dg);
00944 
00945   dg.add_bool(_off_all_lights);
00946 
00947   // write the number of off_lights
00948   dg.add_uint16(get_num_off_lights());
00949   // write the off lights pointers if any
00950   Lights::const_iterator fi;
00951   for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
00952     NodePath light = (*fi);
00953 
00954     // Since we can't write out a NodePath, we write out just the
00955     // plain PandaNode.  The user can use the AttribNodeRegistry on
00956     // re-read if there is any ambiguity that needs to be resolved.
00957     manager->write_pointer(dg, light.node());
00958   }
00959 
00960   // write the number of on lights
00961   dg.add_uint16(get_num_on_lights());
00962   // write the on lights pointers if any
00963   Lights::const_iterator nti;
00964   for (nti = _on_lights.begin(); nti != _on_lights.end(); ++nti) {
00965     NodePath light = (*nti);
00966     manager->write_pointer(dg, light.node());
00967   }
00968 }
00969 
00970 ////////////////////////////////////////////////////////////////////
00971 //     Function: LightAttrib::complete_pointers
00972 //       Access: Public, Virtual
00973 //  Description: Receives an array of pointers, one for each time
00974 //               manager->read_pointer() was called in fillin().
00975 //               Returns the number of pointers processed.
00976 ////////////////////////////////////////////////////////////////////
00977 int LightAttrib::
00978 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00979   int pi = RenderAttrib::complete_pointers(p_list, manager);
00980 
00981   BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights");
00982   nassertr(aux != NULL, pi);
00983 
00984   int i;
00985   aux->_off_list.reserve(aux->_num_off_lights);
00986   for (i = 0; i < aux->_num_off_lights; ++i) {
00987     PandaNode *node;
00988     DCAST_INTO_R(node, p_list[pi++], pi);
00989     aux->_off_list.push_back(node);
00990   }
00991 
00992   aux->_on_list.reserve(aux->_num_on_lights);
00993   for (i = 0; i < aux->_num_on_lights; ++i) {
00994     PandaNode *node;
00995     DCAST_INTO_R(node, p_list[pi++], pi);
00996     aux->_on_list.push_back(node);
00997   }
00998 
00999   return pi;
01000 }
01001 
01002 ////////////////////////////////////////////////////////////////////
01003 //     Function: LightAttrib::finalize
01004 //       Access: Public, Virtual
01005 //  Description: Called by the BamReader to perform any final actions
01006 //               needed for setting up the object after all objects
01007 //               have been read and all pointers have been completed.
01008 ////////////////////////////////////////////////////////////////////
01009 void LightAttrib::
01010 finalize(BamReader *manager) {
01011   // Now it's safe to convert our saved PandaNodes into NodePaths.
01012   BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights");
01013   nassertv(aux != NULL);
01014   nassertv(aux->_num_off_lights == (int)aux->_off_list.size());
01015   nassertv(aux->_num_on_lights == (int)aux->_on_list.size());
01016 
01017   AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
01018 
01019   _off_lights.reserve(aux->_off_list.size());
01020   NodeList::iterator ni;
01021   for (ni = aux->_off_list.begin(); ni != aux->_off_list.end(); ++ni) {
01022     PandaNode *node = (*ni);
01023     int n = areg->find_node(node->get_type(), node->get_name());
01024     if (n != -1) {
01025       // If it's in the registry, add that NodePath.
01026       _off_lights.push_back(areg->get_node(n));
01027     } else {
01028       // Otherwise, add any arbitrary NodePath.  Complain if it's
01029       // ambiguous.
01030       _off_lights.push_back(NodePath(node));
01031     }
01032   }
01033   _off_lights.sort();
01034 
01035   _on_lights.reserve(aux->_on_list.size());
01036   for (ni = aux->_on_list.begin(); ni != aux->_on_list.end(); ++ni) {
01037     PandaNode *node = (*ni);
01038     int n = areg->find_node(node->get_type(), node->get_name());
01039     if (n != -1) {
01040       // If it's in the registry, add that NodePath.
01041       _on_lights.push_back(areg->get_node(n));
01042     } else {
01043       // Otherwise, add any arbitrary NodePath.  Complain if it's
01044       // ambiguous.
01045       _on_lights.push_back(NodePath(node));
01046     }
01047   }
01048   _on_lights.sort();
01049 }
01050 
01051 ////////////////////////////////////////////////////////////////////
01052 //     Function: LightAttrib::make_from_bam
01053 //       Access: Protected, Static
01054 //  Description: This function is called by the BamReader's factory
01055 //               when a new object of type LightAttrib is encountered
01056 //               in the Bam file.  It should create the LightAttrib
01057 //               and extract its information from the file.
01058 ////////////////////////////////////////////////////////////////////
01059 TypedWritable *LightAttrib::
01060 make_from_bam(const FactoryParams &params) {
01061   LightAttrib *attrib = new LightAttrib;
01062   DatagramIterator scan;
01063   BamReader *manager;
01064 
01065   parse_params(params, scan, manager);
01066   attrib->fillin(scan, manager);
01067 
01068   manager->register_finalize(attrib);
01069 
01070   return attrib;
01071 }
01072 
01073 ////////////////////////////////////////////////////////////////////
01074 //     Function: LightAttrib::fillin
01075 //       Access: Protected
01076 //  Description: This internal function is called by make_from_bam to
01077 //               read in all of the relevant data from the BamFile for
01078 //               the new LightAttrib.
01079 ////////////////////////////////////////////////////////////////////
01080 void LightAttrib::
01081 fillin(DatagramIterator &scan, BamReader *manager) {
01082   RenderAttrib::fillin(scan, manager);
01083 
01084   _off_all_lights = scan.get_bool();
01085 
01086   BamAuxData *aux = new BamAuxData;
01087   manager->set_aux_data(this, "lights", aux);
01088 
01089   aux->_num_off_lights = scan.get_uint16();
01090   manager->read_pointers(scan, aux->_num_off_lights);
01091     
01092   aux->_num_on_lights = scan.get_uint16();
01093   manager->read_pointers(scan, aux->_num_on_lights);
01094 }
 All Classes Functions Variables Enumerations