vehicle stuff
[carveJwlIkooP6JGAAIwe30JlM.git] / vehicle.h
1 #ifndef VEHICLE_H
2 #define VEHICLE_H
3
4 #define VG_GAME
5 #include "vg/vg.h"
6 #include "rigidbody.h"
7 #include "world.h"
8 #include "player_physics.h"
9
10 VG_STATIC float k_car_spring = 1.0f,
11 k_car_spring_damp = 0.001f,
12 k_car_spring_length = 0.5f,
13 k_car_wheel_radius = 0.2f,
14 k_car_friction_lat = 0.6f,
15 k_car_friction_roll = 0.01f,
16 k_car_drive_force = 1.0f,
17 k_car_air_resistance = 0.1f,
18 k_car_downforce = 0.5f;
19
20 VG_STATIC struct gvehicle
21 {
22 int alive, inside;
23 rigidbody rb;
24
25 v3f wheels[4];
26
27 float tangent_mass[4][2],
28 normal_forces[4],
29 tangent_forces[4][2];
30
31 float steer, drive;
32 v3f steerv;
33
34 v3f tangent_vectors[4][2];
35 v3f wheels_local[4];
36 }
37 gzoomer =
38 {
39 .rb = { .type = k_rb_shape_sphere, .inf.sphere.radius = 1.0f }
40 };
41
42 VG_STATIC int spawn_car( int argc, const char *argv[] )
43 {
44 v3f ra, rb, rx;
45 v3_copy( main_camera.pos, ra );
46 v3_muladds( ra, main_camera.transform[2], -10.0f, rb );
47
48 float t;
49 if( spherecast_world( ra, rb, gzoomer.rb.inf.sphere.radius, &t, rx ) != -1 )
50 {
51 v3_lerp( ra, rb, t, gzoomer.rb.co );
52 gzoomer.rb.co[1] += 4.0f;
53 q_axis_angle( gzoomer.rb.q, (v3f){1.0f,0.0f,0.0f}, 0.001f );
54 v3_zero( gzoomer.rb.v );
55 v3_zero( gzoomer.rb.w );
56
57 rb_update_transform( &gzoomer.rb );
58 gzoomer.alive = 1;
59
60 vg_success( "Spawned car\n" );
61 }
62 else
63 {
64 vg_error( "Can't spawn here\n" );
65 }
66
67 return 0;
68 }
69
70 VG_STATIC void vehicle_init(void)
71 {
72 q_identity( gzoomer.rb.q );
73 rb_init( &gzoomer.rb );
74
75 VG_VAR_F32_PERSISTENT( k_car_spring );
76 VG_VAR_F32_PERSISTENT( k_car_spring_damp );
77 VG_VAR_F32_PERSISTENT( k_car_spring_length );
78 VG_VAR_F32_PERSISTENT( k_car_wheel_radius );
79 VG_VAR_F32_PERSISTENT( k_car_friction_lat );
80 VG_VAR_F32_PERSISTENT( k_car_friction_roll );
81 VG_VAR_F32_PERSISTENT( k_car_drive_force );
82 VG_VAR_F32_PERSISTENT( k_car_air_resistance );
83 VG_VAR_F32_PERSISTENT( k_car_downforce );
84
85 VG_VAR_I32( gzoomer.inside );
86
87 vg_function_push( (struct vg_cmd){
88 .name = "spawn_car",
89 .function = spawn_car
90 });
91
92 v3_copy((v3f){ -1.0f, -0.25f, -1.5f }, gzoomer.wheels_local[0] );
93 v3_copy((v3f){ 1.0f, -0.25f, -1.5f }, gzoomer.wheels_local[1] );
94 v3_copy((v3f){ -1.0f, -0.25f, 1.5f }, gzoomer.wheels_local[2] );
95 v3_copy((v3f){ 1.0f, -0.25f, 1.5f }, gzoomer.wheels_local[3] );
96 }
97
98 VG_STATIC void vehicle_wheel_force( int index )
99 {
100 v3f pa, pb, n;
101 m4x3_mulv( gzoomer.rb.to_world, gzoomer.wheels_local[index], pa );
102 v3_muladds( pa, gzoomer.rb.up, -k_car_spring_length, pb );
103
104
105 #if 1
106 float t;
107 if( spherecast_world( pa, pb, k_car_wheel_radius, &t, n ) == -1 )
108 t = 1.0f;
109
110 #else
111
112 v3f dir;
113 v3_muls( gzoomer.rb.up, -1.0f, dir );
114
115 ray_hit hit;
116 hit.dist = k_car_spring_length;
117 ray_world( pa, dir, &hit );
118
119 float t = hit.dist / k_car_spring_length;
120
121 #endif
122
123 v3f pc;
124 v3_lerp( pa, pb, t, pc );
125
126 m4x3f mtx;
127 m3x3_copy( gzoomer.rb.to_world, mtx );
128 v3_copy( pc, mtx[3] );
129 debug_sphere( mtx, k_car_wheel_radius, VG__BLACK );
130 vg_line( pa, pc, VG__WHITE );
131 v3_copy( pc, gzoomer.wheels[index] );
132
133 if( t < 1.0f )
134 {
135 /* spring force */
136 float Fv = (1.0f-t) * k_car_spring*k_rb_delta;
137
138 v3f delta;
139 v3_sub( pa, gzoomer.rb.co, delta );
140
141 v3f rv;
142 v3_cross( gzoomer.rb.w, delta, rv );
143 v3_add( gzoomer.rb.v, rv, rv );
144
145 Fv += v3_dot( rv, gzoomer.rb.up ) * -k_car_spring_damp*k_rb_delta;
146
147 /* scale by normal incident */
148 Fv *= v3_dot( n, gzoomer.rb.up );
149
150 v3f F;
151 v3_muls( gzoomer.rb.up, Fv, F );
152
153 rb_linear_impulse( &gzoomer.rb, delta, F );
154
155 /* friction vectors
156 * -------------------------------------------------------------*/
157 v3f tx, ty;
158
159 if( index <= 1 )
160 v3_cross( gzoomer.steerv, n, tx );
161 else
162 v3_cross( gzoomer.rb.forward, n, tx );
163 v3_cross( tx, n, ty );
164
165 v3_copy( tx, gzoomer.tangent_vectors[ index ][0] );
166 v3_copy( ty, gzoomer.tangent_vectors[ index ][1] );
167
168 gzoomer.normal_forces[ index ] = Fv;
169 gzoomer.tangent_forces[ index ][0] = 0.0f;
170 gzoomer.tangent_forces[ index ][1] = 0.0f;
171
172 /* orient inverse inertia tensors */
173 v3f raW;
174 m3x3_mulv( gzoomer.rb.to_world, gzoomer.wheels_local[index], raW );
175
176 v3f raCtx, raCtxI, raCty, raCtyI;
177 v3_cross( tx, raW, raCtx );
178 v3_cross( ty, raW, raCty );
179 m3x3_mulv( gzoomer.rb.iIw, raCtx, raCtxI );
180 m3x3_mulv( gzoomer.rb.iIw, raCty, raCtyI );
181
182 gzoomer.tangent_mass[index][0] = gzoomer.rb.inv_mass;
183 gzoomer.tangent_mass[index][0] += v3_dot( raCtx, raCtxI );
184 gzoomer.tangent_mass[index][0] = 1.0f/gzoomer.tangent_mass[index][0];
185
186 gzoomer.tangent_mass[index][1] = gzoomer.rb.inv_mass;
187 gzoomer.tangent_mass[index][1] += v3_dot( raCty, raCtyI );
188 gzoomer.tangent_mass[index][1] = 1.0f/gzoomer.tangent_mass[index][1];
189
190 /* apply drive force */
191 if( index >= 2 )
192 {
193 v3_muls( ty, gzoomer.drive * k_car_drive_force * k_rb_delta, F );
194 rb_linear_impulse( &gzoomer.rb, raW, F );
195 }
196 }
197 else
198 {
199 gzoomer.normal_forces[ index ] = 0.0f;
200 gzoomer.tangent_forces[ index ][0] = 0.0f;
201 gzoomer.tangent_forces[ index ][1] = 0.0f;
202 }
203 }
204
205 VG_STATIC void vehicle_solve_friction(void)
206 {
207 for( int i=0; i<4; i++ )
208 {
209 v3f raW;
210 m3x3_mulv( gzoomer.rb.to_world, gzoomer.wheels_local[i], raW );
211
212 v3f rv;
213 v3_cross( gzoomer.rb.w, raW, rv );
214 v3_add( gzoomer.rb.v, rv, rv );
215
216 float fx = k_car_friction_lat * gzoomer.normal_forces[i],
217 fy = k_car_friction_roll * gzoomer.normal_forces[i],
218 vtx = v3_dot( rv, gzoomer.tangent_vectors[i][0] ),
219 vty = v3_dot( rv, gzoomer.tangent_vectors[i][1] ),
220 lambdax = gzoomer.tangent_mass[i][0] * -vtx,
221 lambday = gzoomer.tangent_mass[i][1] * -vty;
222
223 float tempx = gzoomer.tangent_forces[i][0],
224 tempy = gzoomer.tangent_forces[i][1];
225 gzoomer.tangent_forces[i][0] = vg_clampf( tempx + lambdax, -fx, fx );
226 gzoomer.tangent_forces[i][1] = vg_clampf( tempy + lambday, -fy, fy );
227 lambdax = gzoomer.tangent_forces[i][0] - tempx;
228 lambday = gzoomer.tangent_forces[i][1] - tempy;
229
230 v3f impulsex, impulsey;
231 v3_muls( gzoomer.tangent_vectors[i][0], lambdax, impulsex );
232 v3_muls( gzoomer.tangent_vectors[i][1], lambday, impulsey );
233 rb_linear_impulse( &gzoomer.rb, raW, impulsex );
234 rb_linear_impulse( &gzoomer.rb, raW, impulsey );
235 }
236 }
237
238 VG_STATIC void vehicle_update_fixed(void)
239 {
240 if( !gzoomer.alive )
241 return;
242
243 gzoomer.steer = vg_lerpf( gzoomer.steer,
244 player.input_walkh->axis.value * 0.4f,
245 k_rb_delta * 8.0f );
246
247 gzoomer.drive = player.input_walkv->axis.value * k_car_drive_force;
248 v3_muls( gzoomer.rb.forward, cosf(gzoomer.steer), gzoomer.steerv );
249 v3_muladds( gzoomer.steerv, gzoomer.rb.right,
250 sinf(gzoomer.steer), gzoomer.steerv );
251
252 /* apply air resistance */
253 v3f Fair, Fdown;
254
255 v3_muls( gzoomer.rb.v, -k_car_air_resistance, Fair );
256 v3_muls( gzoomer.rb.up, -fabsf(v3_dot( gzoomer.rb.v, gzoomer.rb.forward )) *
257 k_car_downforce, Fdown );
258
259 v3_muladds( gzoomer.rb.v, Fair, k_rb_delta, gzoomer.rb.v );
260 v3_muladds( gzoomer.rb.v, Fdown, k_rb_delta, gzoomer.rb.v );
261
262 for( int i=0; i<4; i++ )
263 vehicle_wheel_force( i );
264
265 rb_ct manifold[64];
266
267 int len = rb_sphere_scene( &gzoomer.rb, &world.rb_geo, manifold );
268 rb_manifold_filter_coplanar( manifold, len, 0.05f );
269
270 if( len > 1 )
271 {
272 rb_manifold_filter_backface( manifold, len );
273 rb_manifold_filter_joint_edges( manifold, len, 0.05f );
274 rb_manifold_filter_pairs( manifold, len, 0.05f );
275 }
276 len = rb_manifold_apply_filtered( manifold, len );
277
278 rb_presolve_contacts( manifold, len );
279 for( int i=0; i<8; i++ )
280 {
281 rb_solve_contacts( manifold, len );
282 vehicle_solve_friction();
283 }
284
285 rb_iter( &gzoomer.rb );
286 rb_update_transform( &gzoomer.rb );
287 }
288
289 VG_STATIC void vehicle_update_post(void)
290 {
291 if( !gzoomer.alive )
292 return;
293
294 rb_debug( &gzoomer.rb, VG__WHITE );
295 vg_line( player.phys.rb.co, gzoomer.rb.co, VG__WHITE );
296
297 /* draw friction vectors */
298 v3f p0, px, py;
299
300 for( int i=0; i<4; i++ )
301 {
302 v3_copy( gzoomer.wheels[i], p0 );
303 v3_muladds( p0, gzoomer.tangent_vectors[i][0], 0.5f, px );
304 v3_muladds( p0, gzoomer.tangent_vectors[i][1], 0.5f, py );
305
306 vg_line( p0, px, VG__RED );
307 vg_line( p0, py, VG__GREEN );
308 }
309 }
310
311 VG_STATIC void vehicle_camera(void)
312 {
313 float yaw = atan2f( gzoomer.rb.forward[0], -gzoomer.rb.forward[2] ),
314 pitch = atan2f
315 (
316 -gzoomer.rb.forward[1],
317 sqrtf
318 (
319 gzoomer.rb.forward[0]*gzoomer.rb.forward[0] +
320 gzoomer.rb.forward[2]*gzoomer.rb.forward[2]
321 )
322 );
323
324
325 main_camera.angles[0] = yaw;
326 main_camera.angles[1] = pitch;
327 v3_copy( gzoomer.rb.co, main_camera.pos );
328 }
329
330 #endif /* VEHICLE_H */