1 //
2 // SuperTuxKart - a fun racing game with go-kart
3 // Copyright (C) 2018 SuperTuxKart-Team
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 3
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 #include "network/smooth_network_body.hpp"
20 #include "config/stk_config.hpp"
21
22 #include <algorithm>
23
24 // ----------------------------------------------------------------------------
SmoothNetworkBody(bool enable)25 SmoothNetworkBody::SmoothNetworkBody(bool enable)
26 {
27 reset();
28 m_enabled = enable;
29 m_smooth_rotation = true;
30 m_adjust_vertical_offset = true;
31 m_min_adjust_length = stk_config->m_snb_min_adjust_length;
32 m_max_adjust_length = stk_config->m_snb_max_adjust_length;
33 m_min_adjust_speed = stk_config->m_snb_min_adjust_speed;
34 m_max_adjust_time = stk_config->m_snb_max_adjust_time;
35 m_adjust_length_threshold = stk_config->m_snb_adjust_length_threshold;
36 } // SmoothNetworkBody
37
38 // ----------------------------------------------------------------------------
prepareSmoothing(const btTransform & current_transform,const Vec3 & current_velocity)39 void SmoothNetworkBody::prepareSmoothing(const btTransform& current_transform,
40 const Vec3& current_velocity)
41 {
42 #ifndef SERVER_ONLY
43 // Continuous smooth enabled
44 //if (m_smoothing != SS_NONE)
45 // return;
46
47 m_prev_position_data = std::make_pair(current_transform,
48 current_velocity);
49 #endif
50 } // prepareSmoothing
51
52 // ----------------------------------------------------------------------------
53 /** Adds a new error between graphical and physical position/rotation. Called
54 * in case of a rewind to allow to for smoothing the visuals in case of
55 * incorrect client prediction.
56 */
checkSmoothing(const btTransform & current_transform,const Vec3 & current_velocity)57 void SmoothNetworkBody::checkSmoothing(const btTransform& current_transform,
58 const Vec3& current_velocity)
59 {
60 #ifndef SERVER_ONLY
61 // Continuous smooth enabled
62 //if (m_smoothing != SS_NONE)
63 // return;
64
65 float adjust_length = (current_transform.getOrigin() -
66 m_prev_position_data.first.getOrigin()).length();
67 if (adjust_length < m_min_adjust_length ||
68 adjust_length > m_max_adjust_length)
69 return;
70
71 float speed = m_prev_position_data.second.length();
72 speed = std::max(speed, current_velocity.length());
73 if (speed < m_min_adjust_speed)
74 return;
75
76 float adjust_time = (adjust_length * m_adjust_length_threshold) / speed;
77 if (adjust_time > m_max_adjust_time)
78 return;
79
80 m_start_smoothing_postion.first = m_smoothing == SS_NONE ?
81 m_prev_position_data.first.getOrigin() :
82 m_smoothed_transform.getOrigin();
83 m_start_smoothing_postion.second = m_smoothing == SS_NONE ?
84 m_prev_position_data.first.getRotation() :
85 m_smoothed_transform.getRotation();
86 m_start_smoothing_postion.second.normalize();
87
88 m_smoothing = SS_TO_ADJUST;
89 m_adjust_time_dt = 0.0f;
90 m_adjust_time = adjust_time;
91
92 m_adjust_control_point = m_start_smoothing_postion.first +
93 m_prev_position_data.second * m_adjust_time;
94 Vec3 p2 = current_transform.getOrigin() + current_velocity * m_adjust_time;
95
96 m_adjust_position.first.setInterpolate3(m_adjust_control_point, p2, 0.5f);
97 m_adjust_position.second = current_transform.getRotation();
98 m_adjust_position.second.normalize();
99 #endif
100 } // checkSmoothing
101
102 // ------------------------------------------------------------------------
updateSmoothedGraphics(const btTransform & current_transform,const Vec3 & current_velocity,float dt)103 void SmoothNetworkBody::updateSmoothedGraphics(
104 const btTransform& current_transform, const Vec3& current_velocity,
105 float dt)
106 {
107 #ifndef SERVER_ONLY
108 Vec3 cur_xyz = current_transform.getOrigin();
109 btQuaternion cur_rot = current_transform.getRotation();
110
111 if (!m_enabled)
112 {
113 m_smoothed_transform.setOrigin(cur_xyz);
114 m_smoothed_transform.setRotation(cur_rot);
115 return;
116 }
117
118 float ratio = 0.0f;
119 if (m_smoothing != SS_NONE)
120 {
121 float adjust_time_dt = m_adjust_time_dt + dt;
122 ratio = adjust_time_dt / m_adjust_time;
123 if (ratio > 1.0f)
124 {
125 ratio -= 1.0f;
126 m_adjust_time_dt = adjust_time_dt - m_adjust_time;
127 if (m_smoothing == SS_TO_ADJUST)
128 {
129 m_smoothing = SS_TO_REAL;
130 m_adjust_control_point = m_adjust_position.first +
131 current_velocity * m_adjust_time;
132 }
133 else
134 m_smoothing = SS_NONE;
135 }
136 else
137 m_adjust_time_dt = adjust_time_dt;
138 }
139
140 assert(m_adjust_time_dt >= 0.0f);
141 assert(ratio >= 0.0f);
142 if (m_smoothing == SS_TO_ADJUST)
143 {
144 cur_xyz.setInterpolate3(m_start_smoothing_postion.first,
145 m_adjust_position.first, ratio);
146 Vec3 to_control;
147 to_control.setInterpolate3(m_start_smoothing_postion.first,
148 m_adjust_control_point, ratio);
149 cur_xyz.setInterpolate3(cur_xyz, to_control, 1.0f - ratio);
150 if (m_smooth_rotation)
151 {
152 cur_rot = m_start_smoothing_postion.second;
153 if (dot(cur_rot, m_adjust_position.second) < 0.0f)
154 cur_rot = -cur_rot;
155 cur_rot = cur_rot.slerp(m_adjust_position.second, ratio);
156 }
157 }
158 else if (m_smoothing == SS_TO_REAL)
159 {
160 Vec3 to_control;
161 to_control.setInterpolate3(m_adjust_position.first,
162 m_adjust_control_point, ratio);
163 float ratio_sqrt = sqrtf(ratio);
164 cur_xyz.setInterpolate3(m_adjust_position.first, cur_xyz, ratio_sqrt);
165 cur_xyz.setInterpolate3(to_control, cur_xyz, ratio);
166 if (m_smooth_rotation)
167 {
168 cur_rot.normalize();
169 if (dot(cur_rot, m_adjust_position.second) < 0.0f)
170 cur_rot = -cur_rot;
171 cur_rot = cur_rot.slerp(m_adjust_position.second, 1.0f - ratio);
172 }
173 }
174
175 m_smoothed_transform.setOrigin(cur_xyz);
176 m_smoothed_transform.setRotation(cur_rot);
177
178 if (m_adjust_vertical_offset && m_smoothing != SS_NONE)
179 {
180 Vec3 lc = current_transform.inverse()(cur_xyz);
181 // Adjust vertical position for up/down-sloping
182 cur_xyz = m_smoothed_transform(Vec3(0.0f, -lc.y(), 0.0f));
183 m_smoothed_transform.setOrigin(cur_xyz);
184 }
185 #endif
186 } // updateSmoothedGraphics
187