1 /*
2
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (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, see <http://www.gnu.org/licenses/>.
17
18 */
19 /*
20 * $Header: n:/project/lib/src/edms/RCS/interfac.cc 1.11 1994/04/20 18:44:15 roadkill Exp $
21 */
22
23 // State information and utilities...
24 // ========================
25
26 #include "fixpp.h"
27 #include "edms_int.h"
28 #include "idof.h"
29
30 #pragma require_prototypes off // Added by KC for this file for Mac version.
31
32 #ifdef EDMS_SHIPPABLE
33 //#include "mout.h"
34 #endif
35
36 // Here we need include files for each and every model that we'll be using...
37 // =====================================================
38 #include "robot.h"
39
40 // The physics handles definitions...
41 // ==================================
42 #include "physhand.h"
43
44 // Sanity...
45 // ---------
46 extern int EDMS_integrating;
47
48 // Callbacks...
49 // ============
50 void (*EDMS_object_collision)(physics_handle caller, physics_handle victim, int32_t badness, int32_t DATA1,
51 int32_t DATA2, fix location[3]) = NULL,
52 (*EDMS_autodestruct)(physics_handle caller) = NULL,
53 (*EDMS_off_playfield)(physics_handle caller) = NULL,
54 (*EDMS_sleepy_snoozy)(physics_handle caller) = NULL;
55
56 // Robots...
57 // ---------
58 typedef struct {
59 fix mass, size, hardness, pep, gravity;
60 int32_t cyber_space;
61 } Robot;
62
63 // Conversions...
64 // ==============
65 // physics handle to object number...
66 // ----------------------------------
67 object_number ph2on[MAX_OBJ];
68
69 // Object number to physics handle...
70 // ----------------------------------
71 physics_handle on2ph[MAX_OBJ];
72
73 // Constants...
74 // ============
75 Q fix_zero = 0.;
76
77 // Bridge routine to the terrain functions. C++ functions are all lower case, C are Capped...
78 // ===========================================================================================
79
80 // This is outside the extern "C" {} thing
81 // because it is not called by the user,
82 // but rather calls the user function Terrain().
83 // =============================================
terrain(Q X,Q Y,int32_t deriv)84 Q terrain(Q X, Q Y, int32_t deriv) {
85 Q ans;
86
87 printf("There is no terrain in space!\n");
88 // ans.fix_to( Terrain( X.to_fix(), Y.to_fix(), deriv ) );
89 return ans;
90 }
91
92 // Same with Indoors...
93 // --------------------
indoor_terrain(Q X,Q Y,Q Z,Q R,physics_handle ph,TFType type)94 TerrainHit indoor_terrain(Q X, Q Y, Q Z, Q R, physics_handle ph, TFType type) {
95 if ((X > 1) && (Y > 1) && (X < 64) && (Y < 64)) {
96 return Indoor_Terrain(X.to_fix(), Y.to_fix(), Z.to_fix(), R.to_fix(), ph, type);
97 } else {
98 // EDMS_robot_global_badness_indicator = 1000;
99 // mout << "!EDMS: integrator = " << EDMS_integrating << " !!\n";
100 // mout << "!EDMS: Physics handle: " << ph << " is asking for bad terrain.\n";
101 // mout << "!EDMS: Asked for location: (" << X << ", " << Y << ", " << Z << ").\n";
102
103 if (ph > -1) {
104 int on = ph2on[ph];
105 // mout << "!EDMS: Integration location (should match): (" << A[on][0][0] << ", " << A[on][1][0] <<
106 // ", " << A[on][2][0] << ").\n"; mout << "!EDMS: Object location last frame: (" << S[on][0][0] <<
107 // ", " << S[on][1][0] << ", " << S[on][2][0] << ").\n"; mout << "!EDMS: Sleep: " <<
108 // no_no_not_me[on] << ", EDMS_sanity_check = " << sanity_check() << ".\n"; mout << "!EDMS: object
109 // number " << on << ", EDMS_type: " << I[on][30] << "\n"; mout << "!EDMS: Calling AWOL
110 // callback...\n"; mout << "Awol in interfac.cc\n";
111
112 EDMS_off_playfield(ph);
113 no_no_not_me[on] = 0; // Safety!!!
114 } else {
115 // mout << "!EDMS: No further information is available for physics handle -1. SORRY!\n";
116 }
117 }
118 // If we're off the map, we should probably terminate the search.
119 return HIT_FACELET;
120 }
121
122 // And with Freefall...
123 // --------------------
ff_terrain(Q X,Q Y,Q Z,uchar fast,terrain_ff * FFT)124 bool ff_terrain(Q X, Q Y, Q Z, uchar fast, terrain_ff *FFT) {
125 return FF_terrain(X.to_fix(), Y.to_fix(), Z.to_fix(), fast, FFT);
126 }
127
ff_raycast(Q x,Q y,Q z,Fixpoint * vec,Q range,Fixpoint * where_hit,terrain_ff * FFT)128 bool ff_raycast(Q x, Q y, Q z, Fixpoint *vec, Q range, Fixpoint *where_hit, terrain_ff *FFT) {
129 return FF_raycast(x.to_fix(), y.to_fix(), z.to_fix(), (fix *)vec, range.to_fix(), (fix *)where_hit, FFT);
130 }
131
FF_terrain(fix X,fix Y,fix Z,uchar fast,terrain_ff * TFF)132 bool FF_terrain(fix X, fix Y, fix Z, uchar fast, terrain_ff *TFF) { return (true); }
133
FF_raycast(fix x,fix y,fix z,fix * vec,fix range,fix * where_hit,terrain_ff * tff)134 bool FF_raycast(fix x, fix y, fix z, fix *vec, fix range, fix *where_hit, terrain_ff *tff) { return (true); }
135
136 // We need to link to c...
137 // =======================
138 extern "C" {
139
140 // Startup the mighty and perilous EDMS engine...
141 // ==============================================
EDMS_startup(EDMS_data * D)142 void EDMS_startup(EDMS_data *D) {
143 // Stoke the internals...
144 // ======================
145 EDMS_initialize(D);
146
147 // Get the handles in order...
148 // ===========================
149 EDMS_init_handles();
150
151 // Set the callbacks...
152 // ====================
153 EDMS_object_collision = D->collision_callback;
154 EDMS_autodestruct = D->autodestruct_callback;
155 EDMS_off_playfield = D->awol_callback;
156 EDMS_sleepy_snoozy = D->snooz_callback;
157
158 // Done.
159 // =====
160 }
161
162 //////////////////////////////
163 //
164 // Tells EDMS what space to use for A
165 //
EDMS_set_workspace(void * place)166 void EDMS_set_workspace(void *place) { A = (EDMS_Argblock_Pointer)place; }
167
168 // Although this seems a very stupid way to do this, it's actually not...
169 // ======================================================================
170
171 // Autodestruct gets turned on...
172 // ==============================
EDMS_set_autodestruct(physics_handle ph)173 void EDMS_set_autodestruct(physics_handle ph) {
174 if (ph > -1) {
175 int32_t object = ph2on[ph];
176 I[object][38] = 1;
177 }
178 }
179
180 // Autodestruct gets turned off...
181 // ===============================
EDMS_defuse_autodestruct(physics_handle ph)182 void EDMS_defuse_autodestruct(physics_handle ph) {
183 if (ph > -1) {
184 int object = ph2on[ph];
185 I[object][38] = 0;
186 }
187 }
188
189 // I am death incarnate. 666. So there.
190 // =====================================
EDMS_kill_object(physics_handle ph)191 void EDMS_kill_object(physics_handle ph) {
192 // Are you there, really???
193 // ========================
194 if (ph > -1) {
195 int on = physics_handle_to_object_number(ph), i;
196
197 // Do it, just do it...
198 // --------------------
199 EDMS_kill(on);
200 EDMS_release_object(ph);
201
202 // Simulate the action of soliton packing...
203 // -----------------------------------------
204 for (i = (on + 1); (i < MAX_OBJ); i++) {
205 EDMS_remap_object_number(i, (i - 1));
206 }
207
208 if (EDMS_integrating == 1) {
209 // mout << "Killed " << on << " while integrating!\n";
210
211 // You were...
212 // ===========
213 }
214 }
215 }
216
217 // How you get your damn stuff out...
218 // ==================================
EDMS_get_state(physics_handle ph,State * s)219 void EDMS_get_state(physics_handle ph, State *s) {
220
221 int on = physics_handle_to_object_number(ph);
222 if (on > -1 && on < MAX_OBJ) {
223 s->X = S[on][0][0].to_fix();
224 s->X_dot = S[on][0][1].to_fix();
225 s->Y = S[on][1][0].to_fix();
226 s->Y_dot = S[on][1][1].to_fix();
227 s->Z = S[on][2][0].to_fix();
228 s->Z_dot = S[on][2][1].to_fix();
229 s->alpha = S[on][3][0].to_fix();
230 s->alpha_dot = S[on][3][1].to_fix();
231 s->beta = S[on][4][0].to_fix();
232 s->beta_dot = S[on][4][1].to_fix();
233 s->gamma = S[on][5][0].to_fix();
234 s->gamma_dot = S[on][5][1].to_fix();
235 }
236
237 #ifdef EDMS_SHIPPABLE
238 else
239 cout << "Hey, EDMS_get_state sez: physics_handle " << ph << " is nonexistant!!\n";
240 #endif
241 }
242
243 // This does exactly what it looks like it does. It is up to the caller to make sure
244 // that the transport coordinate is not dangerous, for now. Later, perhaps,
245 // it should make sure of this itself, since this is not a real-time kind of function...
246 // ========================================================
EDMS_holistic_teleport(physics_handle ph,State * s)247 void EDMS_holistic_teleport(physics_handle ph, State *s) {
248 if (ph > -1) {
249 int on = physics_handle_to_object_number(ph); // Who are youuuu...
250
251 // First, get rid of the collision hash reference (in state since frame is over)...
252 // =====================================================
253 state_delete_object(on);
254
255 // Now move the thing...
256 // =====================
257 S[on][0][0].fix_to(s->X);
258 S[on][0][1].fix_to(s->X_dot);
259 S[on][1][0].fix_to(s->Y);
260 S[on][1][1].fix_to(s->Y_dot);
261 S[on][2][0].fix_to(s->Z);
262 S[on][2][1].fix_to(s->Z_dot);
263
264 if (I[on][30] != D_FRAME) {
265 S[on][3][0].fix_to(s->alpha);
266 S[on][3][1] = fix_zero;
267 S[on][4][0].fix_to(s->beta);
268 S[on][4][1] = fix_zero;
269 S[on][5][0].fix_to(s->gamma);
270 S[on][5][1] = fix_zero;
271 } else {
272 Q alpha, beta, gamma, sin_alpha, cos_alpha, sin_beta, cos_beta, sin_gamma, cos_gamma;
273
274 // alpha.fix_to( s -> alpha);
275 // beta.fix_to( s -> beta);
276 // gamma.fix_to( s -> gamma);
277
278 // For shock...
279 // ------------
280 alpha.fix_to(s->beta);
281 beta.fix_to(s->gamma);
282 gamma.fix_to(s->alpha);
283
284 alpha = beta = 0;
285
286 sincos(.5 * alpha, &sin_alpha, &cos_alpha);
287 sincos(.5 * beta, &sin_beta, &cos_beta);
288 sincos(.5 * gamma, &sin_gamma, &cos_gamma);
289
290 S[on][3][0] = cos_gamma * cos_alpha * cos_beta + sin_gamma * sin_alpha * sin_beta;
291 S[on][4][0] = cos_gamma * cos_alpha * sin_beta - sin_gamma * sin_alpha * cos_beta;
292 S[on][5][0] = cos_gamma * sin_alpha * cos_beta + sin_gamma * cos_alpha * sin_beta;
293 S[on][6][0] = -cos_gamma * sin_alpha * sin_beta + sin_gamma * cos_alpha * cos_beta;
294
295 // Derivatives
296 S[on][3][1] = 0;
297 S[on][4][1] = 0;
298 S[on][5][1] = 0;
299 S[on][6][1] = 0;
300 }
301
302 // Restart collisions on it...
303 // ===========================
304 state_write_object(on);
305
306 // Gee, I hope that that is a good location, sunny, and free of solid objects...
307 // ==================================================
308 }
309 }
310
311 // Here we exclude objects from hitting each specific others...
312 // ============================================================
EDMS_ignore_collisions(physics_handle ph1,physics_handle ph2)313 void EDMS_ignore_collisions(physics_handle ph1, physics_handle ph2) {
314 int32_t on1, on2;
315
316 // Safety dance...
317 // ---------------
318 if ((ph1 > -1) && (ph2 > -1)) {
319 on1 = ph2on[ph1];
320 on2 = ph2on[ph2];
321
322 exclude_from_collisions(on1, on2);
323 }
324 }
325
326 // Here we reallow collisions...
327 // =============================
EDMS_obey_collisions(physics_handle ph1)328 void EDMS_obey_collisions(physics_handle ph1) {
329 int32_t on1;
330
331 // Safety ballet...
332 // ---------------
333 if (ph1 > -1) {
334 on1 = ph2on[ph1];
335 reset_collisions(on1);
336 }
337 }
338
339 // Turns collisions OFF for a given robot, useful in a variety of household chores...
340 // ==================================================================================
EDMS_make_robot_antisocial(physics_handle ph)341 void EDMS_make_robot_antisocial(physics_handle ph) {
342 int32_t on = 0;
343
344 // Do you suck...
345 // --------------
346 if (ph > -1) {
347 on = ph2on[ph];
348 if (I[on][30] == ROBOT)
349 I[on][5] = -1;
350 } // You suck...
351 }
352
353 // Turns collisions ON for a given robot, useful in a variety of household chores...
354 // =================================================================================
EDMS_make_robot_social(physics_handle ph)355 void EDMS_make_robot_social(physics_handle ph) {
356 int32_t on = 0;
357
358 // Do you suck...
359 // --------------
360 if (ph > -1) {
361 on = ph2on[ph];
362 if (I[on][30] == ROBOT)
363 I[on][5] = 0;
364 } // You suck...
365 }
366
367 // Here is a routine that will attempt to settle an object to the local b/c. It is NOT intended for
368 // online use. A negative return value indicates a badly placed or unphysical model...
369 // =================================================================
EDMS_settle_object(physics_handle ph)370 int32_t EDMS_settle_object(physics_handle ph) {
371 int32_t on = 0, return_value = -1;
372
373 // Are you really there?
374 // ---------------------
375 if (ph > -1) {
376 on = ph2on[ph];
377 return_value = settle_object(on);
378 } // Happy joy...
379
380 // All done...
381 // -----------
382 return return_value;
383 }
384
385 // Prints out a state vector...
386 // ============================
EDMS_mprint_state(physics_handle ph)387 void EDMS_mprint_state(physics_handle ph) {
388 int32_t on = ph2on[ph];
389
390 mprint_state(on);
391 }
392
393 // Here is the beginning of an EDMS diagnostic statistics tool...
394 // ==============================================================
EDMS_inventory_and_statistics(int32_t show_sleepers)395 void EDMS_inventory_and_statistics(int32_t show_sleepers) { inventory_and_statistics(show_sleepers); }
396
397 // Here is the sanity checker, but you already can read that, can't you...
398 // =======================================================================
EDMS_sanity_check()399 int32_t EDMS_sanity_check() { return sanity_check(); }
400
401 // Here are the bridge routines to the "default" EDMS models, others are segregates(d)...
402 // ======================================================================================
403
404 // Robot routines...
405 // ==================
406
407 // Hardness scale for robots...
408 // ----------------------------
409 #define ROBOT_HARD_FAC 10
410
411 // This guy is BROKEN FOR NOW (until we get the params finalized)...
412 // ------------------------------------------------
EDMS_get_robot_parameters(physics_handle ph,Robot * m)413 void EDMS_get_robot_parameters(physics_handle ph, Robot *m) {
414 int32_t on = physics_handle_to_object_number(ph);
415
416 #ifdef EDMS_SHIPPABLE
417 if (I[on][IDOF_MODEL] != ROBOT)
418 mout << "You are trying to get ROBOT parameters for an " << I[on][IDOF_MODEL] << "!\n";
419 #endif
420
421 // mout << "RD: " << I[on][IDOF_ROBOT_ROLL_DRAG] << " : M:" << I[on][IDOF_ROBOT_MASS] << "\n";
422 m->pep = (I[on][IDOF_ROBOT_ROLL_DRAG] / (1.5 * I[on][IDOF_ROBOT_MASS])).to_fix();
423 m->size = I[on][IDOF_ROBOT_RADIUS].to_fix();
424 m->hardness = (I[on][IDOF_ROBOT_K] * I[on][IDOF_ROBOT_RADIUS] / (I[on][IDOF_ROBOT_MASS] * ROBOT_HARD_FAC)).to_fix();
425 m->mass = I[on][IDOF_ROBOT_MASS].to_fix();
426 m->gravity = I[on][IDOF_ROBOT_GRAVITY].to_fix();
427 m->cyber_space = I[on][IDOF_CYBERSPACE].to_int();
428 }
429
430 // And the compression test for terrain "traps..."
431 // ===============================================
EDMS_get_robot_damage(physics_handle ph)432 fix EDMS_get_robot_damage(physics_handle ph) {
433 int32_t object;
434
435 object = ph2on[ph]; // As stupid as it gets...
436 return (I[object][14]).to_fix();
437 }
438
439 // In flux (Thrust, attitude and JumpJets)...
440 // ==========================================
EDMS_control_robot(physics_handle ph,fix T,fix A,fix J)441 void EDMS_control_robot(physics_handle ph, fix T, fix A, fix J) {
442
443 Q TT, // thrust
444 AA, // attitude jets
445 JJ; // jump jets
446
447 #ifdef EDMS_SHIPPABLE
448 if (ph < 0)
449 mout << "Hey, you are an idiot...";
450 #endif
451
452 TT.fix_to(T);
453 AA.fix_to(A);
454 JJ.fix_to(J);
455
456 int32_t on = physics_handle_to_object_number(ph);
457 robot_set_control(on, TT, AA, JJ);
458 }
459
460 // AI control routines...
461 // ======================
EDMS_ai_control_robot(physics_handle ph,fix D_H,fix D_S,fix S_S,fix U,fix * T_Y,fix D)462 void EDMS_ai_control_robot(physics_handle ph, fix D_H, fix D_S, fix S_S, fix U, fix *T_Y, fix D) {
463 Q DH, // desired heading
464 DS, // desired speed
465 SS, // sidestep
466 UU, // urgency
467 TU, // there yet?
468 DD; // distance
469
470 #ifdef EDMS_SHIPPABLE
471 if (ph < 0)
472 mout << "Hey, you are and idiot...";
473 #endif
474
475 DH.fix_to(D_H);
476 DS.fix_to(D_S);
477 SS.fix_to(S_S);
478 UU.fix_to(U);
479 DD.fix_to(D);
480
481 int32_t on = physics_handle_to_object_number(ph);
482 robot_set_ai_control(on, DH, DS, SS, UU, TU, DD);
483
484 *T_Y = TU.to_fix();
485 }
486
487 // These are different parameters than for the marble now...
488 // ---------------------------------------------------------
EDMS_make_robot(Robot * m,State * s)489 physics_handle EDMS_make_robot(Robot *m, State *s) {
490 Q params[10], init_state[6][3];
491
492 Q mass, pep, hardness, size, gravity;
493
494 int32_t cyber_space;
495
496 int32_t on = 0;
497 physics_handle ph = 0;
498
499 init_state[DOF_X][0].fix_to(s->X);
500 init_state[DOF_X][1].fix_to(s->X_dot);
501 init_state[DOF_Y][0].fix_to(s->Y);
502 init_state[DOF_Y][1].fix_to(s->Y_dot);
503 init_state[DOF_Z][0].fix_to(s->Z);
504 init_state[DOF_Z][1].fix_to(s->Z_dot);
505 init_state[DOF_ALPHA][0].fix_to(s->alpha);
506 init_state[DOF_ALPHA][1].fix_to(s->alpha_dot);
507 init_state[DOF_BETA][0] = init_state[DOF_BETA][1] = init_state[DOF_GAMMA][0] = init_state[DOF_GAMMA][1] = END;
508
509 mass.fix_to(m->mass);
510 size.fix_to(m->size);
511 // if ( size > .45/hash_scale ) size = .45/hash_scale;
512 hardness.fix_to(m->hardness);
513 pep.fix_to(m->pep);
514 gravity.fix_to(m->gravity);
515 cyber_space = m->cyber_space;
516
517 // if (hardness > 15) { mout << "Hardness too too too: " << hardness << "\n"; hardness = 15; }
518
519 if (mass < 1)
520 mass = 1;
521 if (mass > 30)
522 mass = 30;
523
524 hardness = hardness * (mass * ROBOT_HARD_FAC / size);
525 if (hardness > 4000) {
526 hardness = 4000;
527 // mout << "Hard cap!\n";
528 }
529
530 params[OFFSET(IDOF_ROBOT_K)] = hardness;
531 params[OFFSET(IDOF_ROBOT_D)] = 1.5 * sqrt(params[OFFSET(IDOF_ROBOT_K)]) * sqrt(mass);
532 params[OFFSET(IDOF_ROBOT_RADIUS)] = size;
533
534 // mout << params[OFFSET(IDOF_ROBOT_D)] << "\n";
535
536 params[OFFSET(IDOF_ROBOT_ROLL_DRAG)] = 1.5 * pep * mass;
537 params[OFFSET(IDOF_ROBOT_MASS_RECIP)] = 1. / mass;
538 params[OFFSET(IDOF_ROBOT_GRAVITY)] = gravity;
539 params[OFFSET(IDOF_ROBOT_MASS)] = mass;
540 // params[7] = 1. / ( .4*mass*size*size );
541 // params[8] = 5.*(1. / params[7]);
542 // params[9] = .4*mass*size*size;
543 params[OFFSET(IDOF_ROBOT_MOI)] = .4 * mass * size * size;
544 params[OFFSET(IDOF_ROBOT_ROT_DRAG)] = 5 * params[OFFSET(IDOF_ROBOT_MOI)];
545
546 if (params[OFFSET(IDOF_ROBOT_MOI)] != 0)
547
548 params[OFFSET(IDOF_ROBOT_MOI_RECIP)] = 1.0 / params[OFFSET(IDOF_ROBOT_MOI)];
549 else
550 params[OFFSET(IDOF_ROBOT_MOI_RECIP)] = 0.0;
551
552 on = make_robot(init_state, params);
553
554 // Here is where cyberspace gets turned on...
555 // ------------------------------------------
556 I[on][IDOF_CYBERSPACE] = (cyber_space > 0);
557
558 ph = EDMS_bind_object_number(on);
559
560 #ifdef EDMS_SHIPPABLE
561 if (params[OFFSET(IDOF_ROBOT_MOI)] == 0)
562 mout << "object " << on << " got 0 size or mass\n";
563 #endif
564
565 return ph;
566 }
567
EDMS_set_robot_parameters(physics_handle ph,Robot * m)568 void EDMS_set_robot_parameters(physics_handle ph, Robot *m) {
569 Q mass, hardness, size, pep, gravity;
570
571 int32_t cyber_space;
572
573 mass.fix_to(m->mass);
574 size.fix_to(m->size);
575 // if ( size > .45/hash_scale ) size = .45/hash_scale;
576 hardness.fix_to(m->hardness);
577 pep.fix_to(m->pep);
578 gravity.fix_to(m->gravity);
579 cyber_space = m->cyber_space;
580
581 int32_t on = physics_handle_to_object_number(ph);
582
583 #ifdef EDMS_SHIPPABLE
584 if (I[on][IDOF_MODEL] != ROBOT)
585 mout << "You are trying to set ROBOT parameters for an " << I[on][30] << "!\n";
586 #endif
587
588 // mout << "Set Robot " << on << "\n";
589 // mout << " mass: " << mass << "\n";
590 // mout << " size: " << size << "\n";
591 // mout << " hard: " << hardness << "\n";
592 // mout << " pepp: " << pep << "\n";
593 // mout << " grav: " << gravity << "\n";
594
595 if (mass < 1)
596 mass = 1;
597 if (mass > 30)
598 mass = 30;
599
600 hardness = hardness * (mass * ROBOT_HARD_FAC / size);
601
602 // hardness = hardness*(mass*ROBOT_HARD_FAC/size);
603 if (hardness > 4000) {
604 hardness = 4000;
605 // mout << "Hard cap!\n";
606 }
607
608 I[on][IDOF_ROBOT_K] = hardness;
609 I[on][IDOF_ROBOT_D] = 1.5 * sqrt(I[on][IDOF_ROBOT_K]) * sqrt(mass);
610 I[on][IDOF_ROBOT_RADIUS] = size;
611 I[on][IDOF_ROBOT_ROLL_DRAG] = 1.5 * pep * mass;
612 I[on][IDOF_ROBOT_MASS_RECIP] = 1. / mass;
613 I[on][IDOF_ROBOT_GRAVITY] = gravity;
614 I[on][IDOF_ROBOT_MASS] = mass;
615 I[on][IDOF_ROBOT_MOI_RECIP] = 1. / (.4 * mass * size * size);
616 I[on][IDOF_ROBOT_ROT_DRAG] = 5. * (1. / I[on][IDOF_ROBOT_MOI_RECIP]);
617 I[on][IDOF_ROBOT_MOI] = .4 * mass * size * size;
618 I[on][IDOF_CYBERSPACE] = (cyber_space > 0);
619
620 // mout << "Roll: " << I[on][IDOF_ROBOT_ROLL_DRAG] << "\n";
621 }
622
623 // Bridge routines to the solvers!!
624 // ================================
625
626 // 4th order and very stable...
627 // ----------------------------
EDMS_soliton(fix timestep)628 void EDMS_soliton(fix timestep) {
629 Q temp;
630 temp.fix_to(timestep);
631 soliton(temp);
632 }
633
634 // 2nd order and needs some attention...
635 // -------------------------------------
EDMS_soliton_lite(fix timestep)636 void EDMS_soliton_lite(fix timestep) {
637 Q temp;
638 temp.fix_to(timestep);
639 soliton_lite(temp);
640 }
641
642 // Efficient and unstoppable...
643 // ----------------------------
EDMS_soliton_vector(fix timestep)644 void EDMS_soliton_vector(fix timestep) {
645 Q temp;
646 temp.fix_to(timestep);
647 soliton_vector(temp);
648 }
649
650 // Won't allow objects to collide w/one another...
651 // -----------------------------------------------
EDMS_soliton_vector_holistic(fix timestep)652 void EDMS_soliton_vector_holistic(fix timestep) {
653 Q temp;
654 temp.fix_to(timestep);
655 soliton_vector_holistic(temp);
656 }
657
658 // This code here handles the mapping between the user's physics handles and the
659 // dynamically changing intername object numbers.
660 // ==============================================
661 // To make a physics handle, edms calls EDMS_bind_object_number to "bind" an internal
662 // object number to a physics handle. When this object number changes, the function
663 // EDMS_remap_object_number() needs to be called to map the nu object number to
664 // the physics number.
665 // ===================
666 // The physics handles are valid throughout the life of a physics object; in contrast,
667 // the object numbers change as the array of objects is compacted.
668 // ===============================================================
669 // Make sure the include stuff is included before this.
670 // ====================================================
671
672 // Initialization... must call this, man...
673 // ========================================
EDMS_init_handles(void)674 void EDMS_init_handles(void) {
675 // Fill with the 'end' code...
676 // ---------------------------
677 for (int32_t i = 0; i < MAX_OBJ; ++i)
678 ph2on[i] = on2ph[i] = -1;
679 }
680
681 // To bind a physics handle to an object number, use this function.
682 // ================================================================
EDMS_bind_object_number(object_number on)683 physics_handle EDMS_bind_object_number(object_number on) {
684 physics_handle ph = EDMS_get_free_ph();
685
686 if (ph == -1)
687 return -1;
688
689 ph2on[ph] = on;
690 on2ph[on] = ph;
691
692 return ph;
693 }
694
695 // EDMS_remap_object_number() remaps object numbers so that the physics_handle that
696 // used to refer to object number #old will now refer to object number #nu.
697 // If object #old is not mapped, nothing happens...
698 // ================================================
699
EDMS_remap_object_number(object_number old,object_number nu)700 void EDMS_remap_object_number(object_number old, object_number nu) {
701 physics_handle ph = on2ph[old];
702
703 if (ph == -1)
704 return;
705
706 on2ph[nu] = ph;
707 on2ph[old] = -1;
708 ph2on[ph] = nu;
709 }
710
711 // To release the mapping between physics handle and object number
712 // (say, when deleting an object)...
713 // =================================
714
EDMS_release_object(physics_handle ph)715 void EDMS_release_object(physics_handle ph) {
716 object_number on = ph2on[ph];
717
718 // First, clear out the object number...
719 // -------------------------------------
720 on2ph[on] = -1;
721
722 // Then clear out the physics_handle...
723 // ------------------------------------
724 ph2on[ph] = -1;
725 }
726
727 // Internal routine to find an unused physics_handle.
728 // ==================================================
729
EDMS_get_free_ph(void)730 physics_handle EDMS_get_free_ph(void) {
731 for (int32_t i = min_physics_handle; i < MAX_OBJ; ++i) {
732 // Ho, ho...
733 // ---------
734 if (ph2on[i] == -1)
735 return i;
736 }
737 // Failed to find one...
738 // ---------------------
739 return -1;
740 // Fun...
741 // ======
742 }
743
744 } // End of extern "C" for the &^%$@% compiler...
745