Panda3D
 All Classes Functions Variables Enumerations
collisionHandlerEvent.cxx
00001 // Filename: collisionHandlerEvent.cxx
00002 // Created by:  drose (16Mar02)
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 
00016 #include "collisionHandlerEvent.h"
00017 #include "config_collide.h"
00018 
00019 #include "eventParameter.h"
00020 #include "throw_event.h"
00021 
00022 
00023 TypeHandle CollisionHandlerEvent::_type_handle;
00024 
00025 ////////////////////////////////////////////////////////////////////
00026 //     Function: CollisionHandlerEvent::Constructor
00027 //       Access: Public
00028 //  Description: The default CollisionHandlerEvent will throw no
00029 //               events.  Its pattern strings must first be set via a
00030 //               call to add_in_pattern() and/or add_out_pattern().
00031 ////////////////////////////////////////////////////////////////////
00032 CollisionHandlerEvent::
00033 CollisionHandlerEvent() {
00034 }
00035 
00036 ////////////////////////////////////////////////////////////////////
00037 //     Function: CollisionHandlerEvent::begin_group
00038 //       Access: Public, Virtual
00039 //  Description: Will be called by the CollisionTraverser before a new
00040 //               traversal is begun.  It instructs the handler to
00041 //               reset itself in preparation for a number of
00042 //               CollisionEntries to be sent.
00043 ////////////////////////////////////////////////////////////////////
00044 void CollisionHandlerEvent::
00045 begin_group() {
00046   if (collide_cat.is_spam()) {
00047     collide_cat.spam()
00048       << "begin_group.\n";
00049   }
00050   _last_colliding.swap(_current_colliding);
00051   _current_colliding.clear();
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: CollisionHandlerEvent::add_entry
00056 //       Access: Public, Virtual
00057 //  Description: Called between a begin_group() .. end_group()
00058 //               sequence for each collision that is detected.
00059 ////////////////////////////////////////////////////////////////////
00060 void CollisionHandlerEvent::
00061 add_entry(CollisionEntry *entry) {
00062   nassertv(entry != (CollisionEntry *)NULL);
00063 
00064   // Record this particular entry for later.  This will keep track of
00065   // all the unique pairs of node/node intersections.
00066   bool inserted = _current_colliding.insert(entry).second;
00067 
00068   if (collide_cat.is_spam()) {
00069     collide_cat.spam()
00070       << "Detected collision from " << entry->get_from_node_path()
00071       << " to " << entry->get_into_node_path()
00072       << ", inserted = " << inserted << "\n";
00073   }
00074 }
00075 
00076 ////////////////////////////////////////////////////////////////////
00077 //     Function: CollisionHandlerEvent::end_group
00078 //       Access: Public, Virtual
00079 //  Description: Called by the CollisionTraverser at the completion of
00080 //               all collision detections for this traversal.  It
00081 //               should do whatever finalization is required for the
00082 //               handler.
00083 ////////////////////////////////////////////////////////////////////
00084 bool CollisionHandlerEvent::
00085 end_group() {
00086   // Now compare the list of entries we collected this frame with
00087   // those we kept from the last time.  Each new entry represents a
00088   // new 'in' event; each missing entry represents a new 'out' event.
00089 
00090   if (collide_cat.is_spam()) {
00091     collide_cat.spam()
00092       << "end_group.\n"
00093       << "current_colliding has " << _current_colliding.size()
00094       << " entries, last_colliding has " << _last_colliding.size()
00095       << "\n";
00096   }
00097 
00098   Colliding::iterator ca, cb;
00099 
00100   ca = _current_colliding.begin();
00101   cb = _last_colliding.begin();
00102 
00103   SortEntries order;
00104   while (ca != _current_colliding.end() && cb != _last_colliding.end()) {
00105     if (order(*ca, *cb)) {
00106       // Here's an element in a but not in b.  That's a newly entered
00107       // intersection.
00108       throw_event_for(_in_patterns, *ca);
00109       ++ca;
00110     } else if (order(*cb, *ca)) {
00111       // Here's an element in b but not in a.  That's a newly exited
00112       // intersection.
00113       throw_event_for(_out_patterns, *cb);
00114       ++cb;
00115     } else {
00116       // This element is in both b and a.  It hasn't changed.
00117       throw_event_for(_again_patterns, *cb);
00118       ++ca;
00119       ++cb;
00120     }
00121   }
00122 
00123   while (ca != _current_colliding.end()) {
00124     // Here's an element in a but not in b.  That's a newly entered
00125     // intersection.
00126     throw_event_for(_in_patterns, *ca);
00127     ++ca;
00128   }
00129 
00130   while (cb != _last_colliding.end()) {
00131     // Here's an element in b but not in a.  That's a newly exited
00132     // intersection.
00133     throw_event_for(_out_patterns, *cb);
00134     ++cb;
00135   }
00136 
00137   return true;
00138 }
00139 
00140 ////////////////////////////////////////////////////////////////////
00141 //     Function: CollisionHandlerEvent::clear
00142 //       Access: Public
00143 //  Description: Empties the list of elements that all colliders are
00144 //               known to be colliding with.  No "out" events will be
00145 //               thrown; if the same collision is detected next frame,
00146 //               a new "in" event will be thrown for each collision.
00147 //
00148 //               This can be called each frame to defeat the
00149 //               persistent "in" event mechanism, which prevents the
00150 //               same "in" event from being thrown repeatedly.
00151 //               However, also see add_again_pattern(), which can be
00152 //               used to set the event that is thrown when a collision
00153 //               is detected for two or more consecutive frames.
00154 ////////////////////////////////////////////////////////////////////
00155 void CollisionHandlerEvent::
00156 clear() {
00157   _last_colliding.clear();
00158   _current_colliding.clear();
00159 }
00160 
00161 ////////////////////////////////////////////////////////////////////
00162 //     Function: CollisionHandlerEvent::flush
00163 //       Access: Public
00164 //  Description: Same as clear() except "out" events are thrown.
00165 ////////////////////////////////////////////////////////////////////
00166 void CollisionHandlerEvent::
00167 flush() {
00168   begin_group();
00169   end_group();
00170 }
00171 
00172 ////////////////////////////////////////////////////////////////////
00173 //     Function: CollisionHandlerEvent::throw_event_for
00174 //       Access: Private
00175 //  Description: Throws whatever events are suggested by the list of
00176 //               patterns.
00177 ////////////////////////////////////////////////////////////////////
00178 void CollisionHandlerEvent::
00179 throw_event_for(const vector_string &patterns, CollisionEntry *entry) {
00180   vector_string::const_iterator pi;
00181   for (pi = patterns.begin(); pi != patterns.end(); ++pi) {
00182     throw_event_pattern(*pi, entry);
00183   }
00184 }
00185 
00186 ////////////////////////////////////////////////////////////////////
00187 //     Function: CollisionHandlerEvent::throw_event_pattern
00188 //       Access: Private
00189 //  Description: Throws an event matching the indicated pattern.
00190 ////////////////////////////////////////////////////////////////////
00191 void CollisionHandlerEvent::
00192 throw_event_pattern(const string &pattern, CollisionEntry *entry) {
00193   if (pattern.empty()) {
00194     return;
00195   }
00196 
00197   string event;
00198   for (size_t p = 0; p < pattern.size(); ++p) {
00199     if (pattern[p] == '%') {
00200       string key;
00201       if (p + 1 < pattern.size() && pattern[p + 1] == '(') {
00202         // Extract out the key--the name up until the closing paren.
00203         size_t close = pattern.find(')', p + 2);
00204         if (close != string::npos) {
00205           key = pattern.substr(p + 2, close - (p + 2));
00206           p = close;
00207         }
00208       }
00209 
00210       // Get out the command--the two characters following the percent
00211       // sign (or the key).
00212       string cmd = pattern.substr(p + 1, 2);
00213       p += 2;
00214       if (cmd == "fn") {
00215         event += entry->get_from_node()->get_name();
00216 
00217       } else if (cmd == "in") {
00218         if (entry->has_into()) {
00219           event += entry->get_into_node()->get_name();
00220         }
00221 
00222       } else if (cmd == "fs") {
00223         event +=
00224           (!entry->get_from()->is_tangible() ? 'i' : 't');
00225 
00226       } else if (cmd == "is") {
00227         event +=
00228           (entry->has_into() && !entry->get_into()->is_tangible() ? 'i' : 't');
00229 
00230       } else if (cmd == "ig") {
00231         event +=
00232           (entry->has_into() ? 'c' : 'g');
00233 
00234       } else if (cmd == "fh") {
00235         if (!entry->get_from_node_path().has_net_tag(key)) {
00236           return;
00237         }
00238 
00239       } else if (cmd == "fx") {
00240         if (entry->get_from_node_path().has_net_tag(key)) {
00241           return;
00242         }
00243 
00244       } else if (cmd == "ih") {
00245         if (!(entry->has_into() && entry->get_into_node_path().has_net_tag(key))) {
00246           return;
00247         }
00248 
00249       } else if (cmd == "ix") {
00250         if (entry->has_into() && entry->get_into_node_path().has_net_tag(key)) {
00251           return;
00252         }
00253 
00254       } else if (cmd == "ft") {
00255         event += entry->get_from_node_path().get_net_tag(key);
00256 
00257       } else if (cmd == "it") {
00258         if (entry->has_into()) {
00259           event += entry->get_into_node_path().get_net_tag(key);
00260         }
00261         
00262       } else {
00263         collide_cat.error()
00264           << "Invalid symbol in event_pattern: %" << cmd << "\n";
00265       }
00266     } else {
00267       event += pattern[p];
00268     }
00269   }
00270   
00271   if (!event.empty()) {
00272     throw_event(event, EventParameter(entry));
00273   }
00274 }
 All Classes Functions Variables Enumerations