Panda3D
|
00001 // Filename: smoothMover.h 00002 // Created by: drose (19Oct01) 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 #ifndef SMOOTHMOVER_H 00016 #define SMOOTHMOVER_H 00017 00018 #include "directbase.h" 00019 #include "luse.h" 00020 #include "clockObject.h" 00021 #include "circBuffer.h" 00022 #include "nodePath.h" 00023 #include "pdeque.h" 00024 00025 static const int max_position_reports = 10; 00026 static const int max_timestamp_delays = 10; 00027 00028 00029 //////////////////////////////////////////////////////////////////// 00030 // Class : SmoothMover 00031 // Description : This class handles smoothing of sampled motion points 00032 // over time, e.g. for smoothing the apparent movement 00033 // of remote avatars, whose positions are sent via 00034 // occasional telemetry updates. 00035 // 00036 // It can operate in any of three modes: off, in which 00037 // it does not smooth any motion but provides the last 00038 // position it was told; smoothing only, in which it 00039 // smooths motion information but never tries to 00040 // anticipate where the avatar might be going; or full 00041 // prediction, in which it smooths motion as well as 00042 // tries to predict the avatar's position in lead of the 00043 // last position update. The assumption is that all 00044 // SmoothMovers in the world will be operating in the 00045 // same mode together. 00046 //////////////////////////////////////////////////////////////////// 00047 class EXPCL_DIRECT SmoothMover { 00048 PUBLISHED: 00049 SmoothMover(); 00050 ~SmoothMover(); 00051 00052 // These methods are used to specify each position update. Call the 00053 // appropriate set_* function(s), as needed, and then call 00054 // mark_position(). The return value of each function is true if 00055 // the parameter value has changed, or false if it remains the same 00056 // as last time. 00057 INLINE bool set_pos(const LVecBase3 &pos); 00058 INLINE bool set_pos(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z); 00059 INLINE bool set_x(PN_stdfloat x); 00060 INLINE bool set_y(PN_stdfloat y); 00061 INLINE bool set_z(PN_stdfloat z); 00062 00063 INLINE bool set_hpr(const LVecBase3 &hpr); 00064 INLINE bool set_hpr(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r); 00065 INLINE bool set_h(PN_stdfloat h); 00066 INLINE bool set_p(PN_stdfloat p); 00067 INLINE bool set_r(PN_stdfloat r); 00068 00069 INLINE bool set_pos_hpr(const LVecBase3 &pos, const LVecBase3 &hpr); 00070 INLINE bool set_pos_hpr(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r); 00071 00072 INLINE const LPoint3 &get_sample_pos() const; 00073 INLINE const LVecBase3 &get_sample_hpr() const; 00074 00075 INLINE void set_phony_timestamp(double timestamp = 0.0, bool period_adjust = false); 00076 00077 INLINE void set_timestamp(double timestamp); 00078 00079 INLINE bool has_most_recent_timestamp() const; 00080 INLINE double get_most_recent_timestamp() const; 00081 00082 void mark_position(); 00083 void clear_positions(bool reset_velocity); 00084 00085 INLINE bool compute_smooth_position(); 00086 bool compute_smooth_position(double timestamp); 00087 bool get_latest_position(); 00088 00089 INLINE const LPoint3 &get_smooth_pos() const; 00090 INLINE const LVecBase3 &get_smooth_hpr() const; 00091 00092 INLINE void apply_smooth_pos(NodePath &node) const; 00093 INLINE void apply_smooth_pos_hpr(NodePath &pos_node, NodePath &hpr_node) const; 00094 INLINE void apply_smooth_hpr(NodePath &node) const; 00095 00096 INLINE void compute_and_apply_smooth_pos(NodePath &node); 00097 INLINE void compute_and_apply_smooth_pos_hpr(NodePath &pos_node, NodePath &hpr_node); 00098 INLINE void compute_and_apply_smooth_hpr(NodePath &hpr_node); 00099 00100 INLINE PN_stdfloat get_smooth_forward_velocity() const; 00101 INLINE PN_stdfloat get_smooth_lateral_velocity() const; 00102 INLINE PN_stdfloat get_smooth_rotational_velocity() const; 00103 INLINE const LVecBase3 &get_forward_axis() const; 00104 00105 void handle_wrt_reparent(NodePath &old_parent, NodePath &new_parent); 00106 00107 enum SmoothMode { 00108 SM_off, 00109 SM_on, 00110 // We might conceivably add more kinds of smooth modes later, for 00111 // instance, SM_spline. 00112 }; 00113 enum PredictionMode { 00114 PM_off, 00115 PM_on, 00116 // Similarly for other kinds of prediction modes. I don't know 00117 // why, though; linear interpolation seems to work pretty darn 00118 // well. 00119 }; 00120 00121 INLINE void set_smooth_mode(SmoothMode mode); 00122 INLINE SmoothMode get_smooth_mode(); 00123 00124 INLINE void set_prediction_mode(PredictionMode mode); 00125 INLINE PredictionMode get_prediction_mode(); 00126 00127 INLINE void set_delay(double delay); 00128 INLINE double get_delay(); 00129 00130 INLINE void set_accept_clock_skew(bool flag); 00131 INLINE bool get_accept_clock_skew(); 00132 00133 INLINE void set_max_position_age(double age); 00134 INLINE double get_max_position_age(); 00135 00136 INLINE void set_expected_broadcast_period(double period); 00137 INLINE double get_expected_broadcast_period(); 00138 00139 INLINE void set_reset_velocity_age(double age); 00140 INLINE double get_reset_velocity_age(); 00141 00142 INLINE void set_directional_velocity(bool flag); 00143 INLINE bool get_directional_velocity(); 00144 00145 INLINE void set_default_to_standing_still(bool flag); 00146 INLINE bool get_default_to_standing_still(); 00147 00148 void output(ostream &out) const; 00149 void write(ostream &out) const; 00150 00151 private: 00152 void set_smooth_pos(const LPoint3 &pos, const LVecBase3 &hpr, 00153 double timestamp); 00154 void linear_interpolate(int point_before, int point_after, double timestamp); 00155 void compute_velocity(const LVector3 &pos_delta, 00156 const LVecBase3 &hpr_delta, 00157 double age); 00158 00159 void record_timestamp_delay(double timestamp); 00160 INLINE double get_avg_timestamp_delay() const; 00161 00162 public: 00163 // This internal class is declared public to work around compiler 00164 // issues. 00165 class SamplePoint { 00166 public: 00167 LPoint3 _pos; 00168 LVecBase3 _hpr; 00169 double _timestamp; 00170 }; 00171 00172 private: 00173 SamplePoint _sample; 00174 00175 LPoint3 _smooth_pos; 00176 LVecBase3 _smooth_hpr; 00177 LVector3 _forward_axis; 00178 double _smooth_timestamp; 00179 bool _smooth_position_known; 00180 bool _smooth_position_changed; 00181 bool _computed_forward_axis; 00182 00183 double _smooth_forward_velocity; 00184 double _smooth_lateral_velocity; 00185 double _smooth_rotational_velocity; 00186 00187 bool _has_most_recent_timestamp; 00188 double _most_recent_timestamp; 00189 00190 // typedef CircBuffer<SamplePoint, max_position_reports> Points; 00191 typedef pdeque<SamplePoint> Points; 00192 Points _points; 00193 int _last_point_before; 00194 int _last_point_after; 00195 00196 // This array is used to record the average delay in receiving 00197 // timestamps from a particular client, in milliseconds. This value 00198 // will measure both the latency and clock skew from that client, 00199 // allowing us to present smooth motion in spite of extreme latency 00200 // or poor clock synchronization. 00201 typedef CircBuffer<int, max_timestamp_delays> TimestampDelays; 00202 TimestampDelays _timestamp_delays; 00203 int _net_timestamp_delay; 00204 double _last_heard_from; 00205 00206 SmoothMode _smooth_mode; 00207 PredictionMode _prediction_mode; 00208 double _delay; 00209 bool _accept_clock_skew; 00210 double _max_position_age; 00211 double _expected_broadcast_period; 00212 double _reset_velocity_age; 00213 bool _directional_velocity; 00214 bool _default_to_standing_still; 00215 }; 00216 00217 #include "smoothMover.I" 00218 00219 #endif