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