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