Panda3D
|
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 ¶ms) { 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 }