Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/tform/driveInterface.cxx

Go to the documentation of this file.
00001 // Filename: driveInterface.cxx
00002 // Created by:  drose (12Mar02)
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 #include "driveInterface.h"
00020 #include "config_tform.h"
00021 
00022 #include "compose_matrix.h"
00023 #include "mouseAndKeyboard.h"
00024 #include "mouseData.h"
00025 #include "clockObject.h"
00026 #include "modifierButtons.h"
00027 #include "keyboardButton.h"
00028 #include "mouseButton.h"
00029 #include "buttonEventList.h"
00030 #include "dataNodeTransmit.h"
00031 #include "dataGraphTraverser.h"
00032 
00033 TypeHandle DriveInterface::_type_handle;
00034 const float DriveInterface::_hpr_quantize = 0.001;
00035 
00036 DriveInterface::KeyHeld::
00037 KeyHeld() {
00038   _down = false;
00039   _changed_time = 0.0f;
00040   _effect = 0.0f;
00041   _effect_at_change = 0.0f;
00042 }
00043 
00044 float DriveInterface::KeyHeld::
00045 get_effect(float ramp_up_time, float ramp_down_time) {
00046   double elapsed = ClockObject::get_global_clock()->get_frame_time() - _changed_time;
00047 
00048   if (_down) {
00049     // We are currently holding down the key.  That means we base our
00050     // effect on the ramp_up_time.
00051     if (ramp_up_time == 0.0f) {
00052       _effect = 1.0f;
00053 
00054     } else {
00055       float change = elapsed / ramp_up_time;
00056       _effect = min(_effect_at_change + change, 1.0f);
00057     }
00058 
00059   } else {
00060     // We are *not* currently holding down the key.  That means we
00061     // base our effect on the ramp_down_time.
00062     if (ramp_down_time == 0.0f) {
00063       _effect = 0.0f;
00064 
00065     } else {
00066       float change = elapsed / ramp_down_time;
00067       _effect = max(_effect_at_change - change, 0.0f);
00068     }
00069   }
00070 
00071   return _effect;
00072 }
00073 
00074 void DriveInterface::KeyHeld::
00075 set_key(bool down) {
00076   if (_down != down) {
00077     _down = down;
00078     _changed_time = ClockObject::get_global_clock()->get_frame_time();
00079     _effect_at_change = _effect;
00080   }
00081 }
00082 
00083 void DriveInterface::KeyHeld::
00084 clear() {
00085   _down = false;
00086   _changed_time = 0.0f;
00087   _effect = 0.0f;
00088   _effect_at_change = 0.0f;
00089 }
00090 
00091 bool DriveInterface::KeyHeld::
00092 operator < (const DriveInterface::KeyHeld &other) const {
00093   if (_down != other._down) {
00094     // If one has the key held down and the other doesn't, the down
00095     // key wins.
00096     return _down;
00097   }
00098 
00099   // Otherwise, the most-recently changed key wins.
00100   return _changed_time > other._changed_time;
00101 }
00102 
00103 ////////////////////////////////////////////////////////////////////
00104 //     Function: DriveInterface::Constructor
00105 //       Access: Published
00106 //  Description:
00107 ////////////////////////////////////////////////////////////////////
00108 DriveInterface::
00109 DriveInterface(const string &name) : 
00110   DataNode(name) 
00111 {
00112   _xy_input = define_input("xy", EventStoreVec2::get_class_type());
00113   _button_events_input = define_input("button_events", ButtonEventList::get_class_type());
00114 
00115   _transform_output = define_output("transform", EventStoreTransform::get_class_type());
00116   _velocity_output = define_output("velocity", EventStoreVec3::get_class_type());
00117 
00118   _transform = new EventStoreTransform(TransformState::make_identity());
00119   _velocity = new EventStoreVec3(LVector3f::zero());
00120 
00121   _forward_speed = drive_forward_speed;
00122   _reverse_speed = drive_reverse_speed;
00123   _rotate_speed = drive_rotate_speed;
00124   _vertical_dead_zone = drive_vertical_dead_zone;
00125   _horizontal_dead_zone = drive_horizontal_dead_zone;
00126   _vertical_center = drive_vertical_center;
00127   _horizontal_center = drive_horizontal_center;
00128 
00129   _vertical_ramp_up_time = drive_vertical_ramp_up_time;
00130   _vertical_ramp_down_time = drive_vertical_ramp_down_time;
00131   _horizontal_ramp_up_time = drive_horizontal_ramp_up_time;
00132   _horizontal_ramp_down_time = drive_horizontal_ramp_down_time;
00133 
00134   _speed = 0.0f;
00135   _rot_speed = 0.0f;
00136 
00137   _xyz.set(0.0f, 0.0f, 0.0f);
00138   _hpr.set(0.0f, 0.0f, 0.0f);
00139 
00140   _ignore_mouse = false;
00141   _force_mouse = false;
00142   _stop_this_frame = false;
00143 
00144   _mods.add_button(MouseButton::one());
00145   _mods.add_button(MouseButton::two());
00146   _mods.add_button(MouseButton::three());
00147 }
00148 
00149 
00150 
00151 ////////////////////////////////////////////////////////////////////
00152 //     Function: DriveInterface::Destructor
00153 //       Access: Published
00154 //  Description:
00155 ////////////////////////////////////////////////////////////////////
00156 DriveInterface::
00157 ~DriveInterface() {
00158 }
00159 
00160 ////////////////////////////////////////////////////////////////////
00161 //     Function: DriveInterface::reset
00162 //       Access: Published
00163 //  Description: Reinitializes the driver to the origin and resets any
00164 //               knowledge about buttons being held down.
00165 ////////////////////////////////////////////////////////////////////
00166 void DriveInterface::
00167 reset() {
00168   _xyz.set(0.0f, 0.0f, 0.0f);
00169   _hpr.set(0.0f, 0.0f, 0.0f);
00170   _up_arrow.clear();
00171   _down_arrow.clear();
00172   _left_arrow.clear();
00173   _right_arrow.clear();
00174 
00175   _mods.all_buttons_up();
00176 }
00177 
00178 
00179 ////////////////////////////////////////////////////////////////////
00180 //     Function: DriveInterface::set_force_roll
00181 //       Access: Published
00182 //  Description: This function is no longer used and does nothing.  It
00183 //               will be removed soon.
00184 ////////////////////////////////////////////////////////////////////
00185 void DriveInterface::
00186 set_force_roll(float) {
00187 }
00188 
00189 ////////////////////////////////////////////////////////////////////
00190 //     Function: DriveInterface::set_mat
00191 //       Access: Published
00192 //  Description: Stores the indicated transform in the DriveInterface.
00193 ////////////////////////////////////////////////////////////////////
00194 void DriveInterface::
00195 set_mat(const LMatrix4f &mat) {
00196   LVecBase3f scale;
00197   decompose_matrix(mat, scale, _hpr, _xyz);
00198 }
00199 
00200 ////////////////////////////////////////////////////////////////////
00201 //     Function: DriveInterface::get_mat
00202 //       Access: Published
00203 //  Description: Returns the current transform.
00204 ////////////////////////////////////////////////////////////////////
00205 const LMatrix4f &DriveInterface::
00206 get_mat() {
00207   compose_matrix(_mat, LVecBase3f(1.0f, 1.0f, 1.0f), _hpr, _xyz);
00208   return _mat;
00209 }
00210 
00211 ////////////////////////////////////////////////////////////////////
00212 //     Function: DriveInterface::force_dgraph
00213 //       Access: Public
00214 //  Description: This is a special kludge for DriveInterface to allow
00215 //               us to avoid the one-frame latency after a collision.
00216 //               It forces an immediate partial data flow for all data
00217 //               graph nodes below this node, causing all data nodes
00218 //               that depend on this matrix to be updated immediately.
00219 ////////////////////////////////////////////////////////////////////
00220 void DriveInterface::
00221 force_dgraph() {
00222   _transform->set_value(TransformState::make_pos_hpr(_xyz, _hpr));
00223   _velocity->set_value(_vel);
00224 
00225   DataNodeTransmit output;
00226   output.reserve(get_num_outputs());
00227   output.set_data(_transform_output, EventParameter(_transform));
00228   output.set_data(_velocity_output, EventParameter(_velocity));
00229 
00230   DataGraphTraverser dg_trav;
00231   dg_trav.traverse_below(this, output);
00232   dg_trav.collect_leftovers();
00233 }
00234 
00235 
00236 ////////////////////////////////////////////////////////////////////
00237 //     Function: DriveInterface::apply
00238 //       Access: Private
00239 //  Description: Applies the operation indicated by the user's mouse
00240 //               motion to the current state.  Returns the matrix
00241 //               indicating the new state.
00242 ////////////////////////////////////////////////////////////////////
00243 void DriveInterface::
00244 apply(double x, double y, bool any_button) {
00245 
00246   // First reset the speeds
00247   _speed = 0.0f;
00248   _rot_speed = 0.0f;
00249 
00250   if (any_button || _force_mouse) {
00251     // If we're holding down any of the mouse buttons, do this
00252     // computation based on the mouse position.
00253 
00254     // Determine, based on the mouse's position and the amount of time
00255     // elapsed since last frame, how far forward/backward we should
00256     // move and how much we should rotate.
00257 
00258     // First, how fast are we moving?  This is based on the mouse's
00259     // vertical position.
00260 
00261     float dead_zone_top = _vertical_center + _vertical_dead_zone;
00262     float dead_zone_bottom = _vertical_center - _vertical_dead_zone;
00263 
00264     if (y >= dead_zone_top) {
00265       // Motion is forward.  Compute the throttle value: the ratio of
00266       // the mouse pointer within the range of vertical movement.
00267       float throttle =
00268         // double 1.0, not 1.0f, is required here to satisfy min()
00269         (min(y, 1.0) - dead_zone_top) /
00270         (1.0f - dead_zone_top);
00271       _speed = throttle * _forward_speed;
00272 
00273     } else if (y <= dead_zone_bottom) {
00274       // Motion is backward.
00275       float throttle =
00276         (max(y, -1.0) - dead_zone_bottom) /
00277         (-1.0f - dead_zone_bottom);
00278       _speed = -throttle * _reverse_speed;
00279     }
00280 
00281     // Now, what's our rotational velocity?  This is based on the
00282     // mouse's horizontal position.
00283 
00284     float dead_zone_right = _horizontal_center + _horizontal_dead_zone;
00285     float dead_zone_left = _horizontal_center - _horizontal_dead_zone;
00286 
00287     if (x >= dead_zone_right) {
00288       // Rotation is to the right.  Compute the throttle value: the
00289       // ratio of the mouse pointer within the range of horizontal
00290       // movement.
00291       float throttle =
00292         (min(x, 1.0) - dead_zone_right) /
00293         (1.0f - dead_zone_right);
00294       _rot_speed = throttle * _rotate_speed;
00295 
00296     } else if (x <= dead_zone_left) {
00297       // Rotation is to the left.
00298       float throttle =
00299         (max(x, -1.0) - dead_zone_left) /
00300         (-1.0f - dead_zone_left);
00301       _rot_speed = -throttle * _rotate_speed;
00302     }
00303 
00304   } else {
00305     // If we're not holding down any of the mouse buttons, do this
00306     // computation based on the arrow keys.
00307 
00308     // Which vertical arrow key changed state more recently?
00309     float throttle;
00310 
00311     if (_up_arrow < _down_arrow) {
00312       throttle = _up_arrow.get_effect(_vertical_ramp_up_time,
00313                                       _vertical_ramp_down_time);
00314       _speed = throttle * _forward_speed;
00315       _down_arrow._effect = 0.0f;
00316 
00317     } else {
00318       throttle = _down_arrow.get_effect(_vertical_ramp_up_time,
00319                                         _vertical_ramp_down_time);
00320       _speed = -throttle * _reverse_speed;
00321       _up_arrow._effect = 0.0f;
00322     }
00323 
00324     // Which horizontal arrow key changed state more recently?
00325     if (_right_arrow < _left_arrow) {
00326       throttle = _right_arrow.get_effect(_horizontal_ramp_up_time,
00327                                          _horizontal_ramp_down_time);
00328       _rot_speed = throttle * _rotate_speed;
00329       _left_arrow._effect = 0.0f;
00330 
00331     } else {
00332       throttle = _left_arrow.get_effect(_horizontal_ramp_up_time,
00333                                         _horizontal_ramp_down_time);
00334       _rot_speed = -throttle * _rotate_speed;
00335       _right_arrow._effect = 0.0f;
00336     }
00337     _right_arrow._effect = throttle;
00338     _left_arrow._effect = throttle;
00339   }
00340 
00341   if (_speed == 0.0f && _rot_speed == 0.0f) {
00342     _vel.set(0.0f, 0.0f, 0.0f);
00343     return;
00344   }
00345 
00346   // Now how far did we move based on the amount of time elapsed?
00347   float distance = ClockObject::get_global_clock()->get_dt() * _speed;
00348   float rotation = ClockObject::get_global_clock()->get_dt() * _rot_speed;
00349   if (_stop_this_frame) {
00350     distance = 0.0f;
00351     rotation = 0.0f;
00352     _stop_this_frame = false;
00353   }
00354 
00355   // Now apply the vectors.
00356 
00357   // rot_mat is the rotation matrix corresponding to our previous
00358   // heading.
00359   LMatrix3f rot_mat =
00360     LMatrix3f::rotate_mat_normaxis(_hpr[0], LVector3f::up());
00361 
00362   // Take a step in the direction of our previous heading.
00363   _vel = LVector3f::forward() * distance;
00364   LVector3f step = (_vel * rot_mat);
00365 
00366   // To prevent upward drift due to numerical errors, force the
00367   // vertical component of our step to zero (it should be pretty near
00368   // zero anyway).
00369   switch (default_coordinate_system) {
00370   case CS_zup_right:
00371   case CS_zup_left:
00372     step[2] = 0.0f;
00373     break;
00374 
00375   case CS_yup_right:
00376   case CS_yup_left:
00377     step[1] = 0.0f;
00378     break;
00379 
00380   default:
00381     break;
00382   }
00383 
00384   _xyz += step;
00385   _hpr[0] -= rotation;
00386 }
00387 
00388 ////////////////////////////////////////////////////////////////////
00389 //     Function: DriveInterface::do_transmit_data
00390 //       Access: Protected, Virtual
00391 //  Description: The virtual implementation of transmit_data().  This
00392 //               function receives an array of input parameters and
00393 //               should generate an array of output parameters.  The
00394 //               input parameters may be accessed with the index
00395 //               numbers returned by the define_input() calls that
00396 //               were made earlier (presumably in the constructor);
00397 //               likewise, the output parameters should be set with
00398 //               the index numbers returned by the define_output()
00399 //               calls.
00400 ////////////////////////////////////////////////////////////////////
00401 void DriveInterface::
00402 do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
00403   // Look for mouse activity.
00404   double x = 0.0f;
00405   double y = 0.0f;
00406 
00407   bool got_mouse = false;
00408 
00409   if (input.has_data(_xy_input)) {
00410     const EventStoreVec2 *xy;
00411     DCAST_INTO_V(xy, input.get_data(_xy_input).get_ptr());
00412     const LVecBase2f &p = xy->get_value();
00413     x = p[0];
00414     y = p[1];
00415 
00416     got_mouse = true;
00417   }
00418 
00419   // Look for keyboard events.
00420   if (input.has_data(_button_events_input)) {
00421     const ButtonEventList *button_events;
00422     DCAST_INTO_V(button_events, input.get_data(_button_events_input).get_ptr());
00423 
00424     int num_events = button_events->get_num_events();
00425     for (int i = 0; i < num_events; i++) {
00426       const ButtonEvent &be = button_events->get_event(i);
00427       if (be._type != ButtonEvent::T_keystroke) {
00428         bool down = (be._type == ButtonEvent::T_down);
00429 
00430         if (down) {
00431           // We only trap button down events if (a) the mouse is in the
00432           // window, and (b) we aren't set to ignore the mouse.
00433           if (got_mouse && !_ignore_mouse) {
00434             _mods.add_event(be);
00435           }
00436         } else {
00437           // However, we always trap button up events, so we don't get
00438           // confused and believe a button is still being held down when
00439           // it is not.
00440           _mods.add_event(be);
00441         }
00442         
00443         if (be._button == KeyboardButton::up()) {
00444           _up_arrow.set_key(down);
00445         } else if (be._button == KeyboardButton::down()) {
00446           _down_arrow.set_key(down);
00447         } else if (be._button == KeyboardButton::left()) {
00448           _left_arrow.set_key(down);
00449         } else if (be._button == KeyboardButton::right()) {
00450           _right_arrow.set_key(down);
00451         }
00452       }
00453     }
00454   }
00455 
00456   apply(x, y, _mods.is_any_down());
00457   _transform->set_value(TransformState::make_pos_hpr(_xyz, _hpr));
00458   _velocity->set_value(_vel);
00459   output.set_data(_transform_output, EventParameter(_transform));
00460   output.set_data(_velocity_output, EventParameter(_velocity));
00461 }

Generated on Fri May 2 00:44:25 2003 for Panda by doxygen1.3