00001 // Filename: collisionHandlerEvent.cxx 00002 // Created by: drose (16Mar02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 00020 #include "collisionHandlerEvent.h" 00021 #include "config_collide.h" 00022 00023 #include "eventParameter.h" 00024 #include "throw_event.h" 00025 00026 00027 TypeHandle CollisionHandlerEvent::_type_handle; 00028 00029 //////////////////////////////////////////////////////////////////// 00030 // Function: CollisionHandlerEvent::Constructor 00031 // Access: Public 00032 // Description: The default CollisionHandlerEvent will throw no 00033 // events. Its pattern strings must first be set via a 00034 // call to set_in_pattern() and/or set_out_pattern(). 00035 //////////////////////////////////////////////////////////////////// 00036 CollisionHandlerEvent:: 00037 CollisionHandlerEvent() { 00038 } 00039 00040 //////////////////////////////////////////////////////////////////// 00041 // Function: CollisionHandlerEvent::begin_group 00042 // Access: Public, Virtual 00043 // Description: Will be called by the CollisionTraverser before a new 00044 // traversal is begun. It instructs the handler to 00045 // reset itself in preparation for a number of 00046 // CollisionEntries to be sent. 00047 //////////////////////////////////////////////////////////////////// 00048 void CollisionHandlerEvent:: 00049 begin_group() { 00050 if (collide_cat.is_spam()) { 00051 collide_cat.spam() 00052 << "begin_group.\n"; 00053 } 00054 _last_colliding.swap(_current_colliding); 00055 _current_colliding.clear(); 00056 } 00057 00058 //////////////////////////////////////////////////////////////////// 00059 // Function: CollisionHandlerEvent::add_entry 00060 // Access: Public, Virtual 00061 // Description: Called between a begin_group() .. end_group() 00062 // sequence for each collision that is detected. 00063 //////////////////////////////////////////////////////////////////// 00064 void CollisionHandlerEvent:: 00065 add_entry(CollisionEntry *entry) { 00066 nassertv(entry != (CollisionEntry *)NULL); 00067 00068 // Record this particular entry for later. This will keep track of 00069 // all the unique pairs of node/node intersections. 00070 bool inserted = _current_colliding.insert(entry).second; 00071 00072 if (collide_cat.is_spam()) { 00073 collide_cat.spam() 00074 << "Detected collision from " << (void *)entry->get_from_node() 00075 << " to " << (void *)entry->get_into_node() 00076 << ", inserted = " << inserted << "\n"; 00077 } 00078 } 00079 00080 //////////////////////////////////////////////////////////////////// 00081 // Function: CollisionHandlerEvent::end_group 00082 // Access: Public, Virtual 00083 // Description: Called by the CollisionTraverser at the completion of 00084 // all collision detections for this traversal. It 00085 // should do whatever finalization is required for the 00086 // handler. 00087 //////////////////////////////////////////////////////////////////// 00088 bool CollisionHandlerEvent:: 00089 end_group() { 00090 // Now compare the list of entries we collected this frame with 00091 // those we kept from the last time. Each new entry represents a 00092 // new 'in' event; each missing entry represents a new 'out' event. 00093 00094 if (collide_cat.is_spam()) { 00095 collide_cat.spam() 00096 << "end_group.\n" 00097 << "current_colliding has " << _current_colliding.size() 00098 << " entries, last_colliding has " << _last_colliding.size() 00099 << "\n"; 00100 } 00101 00102 Colliding::iterator ca, cb; 00103 00104 ca = _current_colliding.begin(); 00105 cb = _last_colliding.begin(); 00106 00107 SortEntries order; 00108 while (ca != _current_colliding.end() && cb != _last_colliding.end()) { 00109 if (order(*ca, *cb)) { 00110 // Here's an element in a but not in b. That's a newly entered 00111 // intersection. 00112 throw_event_pattern(_in_pattern, *ca); 00113 ++ca; 00114 00115 } else if (order(*cb, *ca)) { 00116 // Here's an element in b but not in a. That's a newly exited 00117 // intersection. 00118 throw_event_pattern(_out_pattern, *cb); 00119 ++cb; 00120 00121 } else { 00122 // This element is in both b and a. It hasn't changed. 00123 throw_event_pattern(_again_pattern, *cb); 00124 ++ca; 00125 ++cb; 00126 } 00127 } 00128 00129 while (ca != _current_colliding.end()) { 00130 // Here's an element in a but not in b. That's a newly entered 00131 // intersection. 00132 throw_event_pattern(_in_pattern, *ca); 00133 ++ca; 00134 } 00135 00136 while (cb != _last_colliding.end()) { 00137 // Here's an element in b but not in a. That's a newly exited 00138 // intersection. 00139 throw_event_pattern(_out_pattern, *cb); 00140 ++cb; 00141 } 00142 00143 return true; 00144 } 00145 00146 //////////////////////////////////////////////////////////////////// 00147 // Function: CollisionHandlerEvent::clear 00148 // Access: Public 00149 // Description: Empties the list of elements that all colliders are 00150 // known to be colliding with. No "out" events will be 00151 // thrown; if the same collision is detected next frame, 00152 // a new "in" event will be thrown for each collision. 00153 // 00154 // This can be called each frame to defeat the 00155 // persistent "in" event mechanism, which prevents the 00156 // same "in" event from being thrown repeatedly. 00157 // However, also see set_again_pattern(), which can be 00158 // used to set the event that is thrown when a collision 00159 // is detected for two or more consecutive frames. 00160 //////////////////////////////////////////////////////////////////// 00161 void CollisionHandlerEvent:: 00162 clear() { 00163 _last_colliding.clear(); 00164 _current_colliding.clear(); 00165 } 00166 00167 //////////////////////////////////////////////////////////////////// 00168 // Function: CollisionHandlerEvent::throw_event_pattern 00169 // Access: Private 00170 // Description: Throws an event matching the indicated pattern. 00171 //////////////////////////////////////////////////////////////////// 00172 void CollisionHandlerEvent:: 00173 throw_event_pattern(const string &pattern, CollisionEntry *entry) { 00174 if (pattern.empty()) { 00175 return; 00176 } 00177 00178 string event; 00179 for (size_t p = 0; p < pattern.size(); ++p) { 00180 if (pattern[p] == '%') { 00181 string cmd = pattern.substr(p + 1, 2); 00182 p += 2; 00183 if (cmd == "fn") { 00184 event += entry->get_from_node()->get_name(); 00185 00186 } else if (cmd == "in") { 00187 event += entry->get_into_node()->get_name(); 00188 00189 } else if (cmd == "ft") { 00190 event += 00191 (!entry->get_from()->is_tangible() ? 'i' : 't'); 00192 00193 } else if (cmd == "it") { 00194 event += 00195 (entry->has_into() && !entry->get_into()->is_tangible() ? 'i' : 't'); 00196 00197 } else if (cmd == "ig") { 00198 event += 00199 (entry->has_into() ? 'c' : 'g'); 00200 00201 } else { 00202 collide_cat.error() 00203 << "Invalid symbol in event_pattern: %" << cmd << "\n"; 00204 } 00205 } else { 00206 event += pattern[p]; 00207 } 00208 } 00209 00210 if (!event.empty()) { 00211 throw_event(event, EventParameter(entry)); 00212 } 00213 }