1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4
5 #include "sarreality.h"
6
7 #include "obj.h"
8 #include "objutils.h"
9
10 #include "simcb.h"
11 #include "simutils.h"
12 #include "simcontact.h"
13
14
15 int SARSimCrashContactCheck(
16 sar_core_struct *core_ptr,
17 sar_object_struct *obj_ptr
18 );
19 int SARSimHoistDeploymentContactCheck(
20 sar_core_struct *core_ptr,
21 sar_object_struct *obj_ptr
22 );
23
24
25 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
26 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
27 #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h)))
28
29
30 /*
31 * Checks if object obj_ptr has come in contact with another object
32 * on the given core structure.
33 *
34 * Returns the object number of the object that has come in
35 * contact with or -1 if there was no contact.
36 *
37 * Proper procedure will be performed if the object has crashed.
38 */
SARSimCrashContactCheck(sar_core_struct * core_ptr,sar_object_struct * obj_ptr)39 int SARSimCrashContactCheck(
40 sar_core_struct *core_ptr, sar_object_struct *obj_ptr
41 )
42 {
43 int i;
44 float dr, z, d;
45 float z1_min, z1_max, z2_min, z2_max;
46 sar_object_struct *obj_ptr2;
47 const sar_contact_bounds_struct *cb_src = obj_ptr->contact_bounds,
48 *cb_tar;
49 const sar_position_struct *pos_src = &obj_ptr->pos,
50 *pos_tar;
51
52 /* If there is no contact bounds on the source object then
53 * there is no need to do contact check
54 */
55 if(cb_src == NULL)
56 return(-1);
57
58 /* Handle by source contact shape */
59 switch(cb_src->contact_shape)
60 {
61 case SAR_CONTACT_SHAPE_SPHERICAL:
62 /* Iterate through objects */
63 for(i = 0; i < core_ptr->total_objects; i++)
64 {
65 obj_ptr2 = core_ptr->object[i];
66 if(obj_ptr2 == NULL)
67 continue;
68
69 cb_tar = obj_ptr2->contact_bounds;
70 if(cb_tar == NULL)
71 continue;
72
73 /* Target not crashable? */
74 if(!(cb_tar->crash_flags & SAR_CRASH_FLAG_CRASH_CAUSE))
75 continue;
76
77 /* Skip ourself */
78 if(obj_ptr2 == obj_ptr)
79 continue;
80
81 pos_tar = &obj_ptr2->pos;
82
83 /* Handle by target object contact shape */
84 switch(cb_tar->contact_shape)
85 {
86 /* Spherical to Spherical */
87 case SAR_CONTACT_SHAPE_SPHERICAL:
88 /* Check 2d distance for contact first */
89 dr = (float)SFMHypot2(
90 pos_tar->x - pos_src->x,
91 pos_tar->y - pos_src->y
92 );
93 if((dr - cb_src->contact_radius - cb_tar->contact_radius)
94 > 0.0f
95 )
96 break;
97
98 /* Calculate spherical radius and then check if
99 * in contact
100 */
101 z = pos_tar->z - pos_src->z;
102 d = (float)SFMHypot2(dr, z);
103 if((d - cb_src->contact_radius - cb_tar->contact_radius)
104 <= 0.0f
105 )
106 {
107 SARSimObjectCollisionCB(
108 core_ptr, obj_ptr, obj_ptr2, 1.1f
109 );
110 return(i);
111 }
112 break;
113
114 /* Spherical to Cylendrical */
115 case SAR_CONTACT_SHAPE_CYLENDRICAL:
116 /* Check 2d distance for contact first */
117 dr = (float)SFMHypot2(
118 pos_tar->x - pos_src->x,
119 pos_tar->y - pos_src->y
120 );
121 if((dr - cb_src->contact_radius - cb_tar->contact_radius)
122 > 0.0f
123 )
124 break;
125
126 /* Sloppy check on vertical height */
127 z = pos_tar->z;
128 if((pos_src->z >= (z + cb_tar->contact_h_min)) &&
129 (pos_src->z <= (z + cb_tar->contact_h_max))
130 )
131 {
132 SARSimObjectCollisionCB(
133 core_ptr, obj_ptr, obj_ptr2, 1.1
134 );
135 return(i);
136 }
137 break;
138
139 /* Spherical to Rectangular */
140 case SAR_CONTACT_SHAPE_RECTANGULAR:
141 /* We'll be treating the source object as a square
142 * object based on its contact radius.
143 */
144 /* First check z bounds. */
145 z1_min = pos_src->z - cb_src->contact_radius;
146 z1_max = pos_src->z + cb_src->contact_radius;
147 z2_min = pos_tar->z + cb_tar->contact_z_min;
148 z2_max = pos_tar->z + cb_tar->contact_z_max;
149 if((z1_min <= z2_max) &&
150 (z2_min <= z1_max)
151 )
152 {
153 /* Calculate relative deltas from target object
154 * to source object.
155 */
156 float dx = pos_src->x - pos_tar->x,
157 dy = pos_src->y - pos_tar->y,
158 src_radius = cb_src->contact_radius;
159 float dx2, dy2, x_min, x_max, y_min, y_max;
160
161 /* Rotate dx and dy about the center of the target
162 * object inversly incase target object has
163 * a rotated heading.
164 */
165 dx2 = (cb_tar->cos_heading * dx) +
166 (cb_tar->sin_heading * dy);
167 dy2 = (cb_tar->cos_heading * dy) -
168 (cb_tar->sin_heading * dx);
169
170 /* Calculate x and y bounds, add source object's
171 * contact bounds to increase the bounds.
172 */
173 x_min = cb_tar->contact_x_min - src_radius;
174 x_max = cb_tar->contact_x_max + src_radius;
175 y_min = cb_tar->contact_y_min - src_radius;
176 y_max = cb_tar->contact_y_max + src_radius;
177
178 /* Check if rotated dx2 and dy2 are in bounds. */
179 if((dx2 >= x_min) && (dx2 <= x_max) &&
180 (dy2 >= y_min) && (dy2 <= y_max)
181 )
182 {
183 SARSimObjectCollisionCB(
184 core_ptr, obj_ptr, obj_ptr2, 1.1f
185 );
186 return(i);
187 }
188 }
189 break;
190 }
191 }
192 break;
193
194 case SAR_CONTACT_SHAPE_CYLENDRICAL:
195 /* Iterate through objects */
196 for(i = 0; i < core_ptr->total_objects; i++)
197 {
198 obj_ptr2 = core_ptr->object[i];
199 if(obj_ptr2 == NULL)
200 continue;
201
202 cb_tar = obj_ptr2->contact_bounds;
203 if(cb_tar == NULL)
204 continue;
205
206 /* Target not crashable? */
207 if(!(cb_tar->crash_flags & SAR_CRASH_FLAG_CRASH_CAUSE))
208 continue;
209
210 /* Skip ourself */
211 if(obj_ptr2 == obj_ptr)
212 continue;
213
214 pos_tar = &obj_ptr2->pos;
215
216 /* Handle by target object contact shape */
217 switch(cb_tar->contact_shape)
218 {
219 /* Cylendrical to Spherical */
220 case SAR_CONTACT_SHAPE_SPHERICAL:
221 /* Check 2d distance for contact first */
222 dr = (float)SFMHypot2(
223 pos_tar->x - pos_src->x,
224 pos_tar->y - pos_src->y
225 );
226 if((dr - cb_src->contact_radius - cb_tar->contact_radius)
227 > 0.0f
228 )
229 break;
230
231 /* Sloppy check on vertical height */
232 z = pos_tar->z;
233 /*
234 if((z >= (pos_src->z + cb_src->contact_h_min)) &&
235 (z <= (pos_src->z + cb_src->contact_h_max))
236 Adding contact radius check
237 */
238 if ( (z + cb_tar->contact_radius >= (pos_src->z + cb_src->contact_h_min)) &&
239 (z - cb_tar->contact_radius <= (pos_src->z + cb_src->contact_h_max) )
240 )
241 {
242 SARSimObjectCollisionCB(
243 core_ptr, obj_ptr, obj_ptr2, 1.1f
244 );
245 return(i);
246 }
247 break;
248
249 /* Cylendrical to Cylendrical */
250 case SAR_CONTACT_SHAPE_CYLENDRICAL:
251 /* Check 2d distance for contact first */
252 dr = (float)SFMHypot2(
253 pos_tar->x - pos_src->x,
254 pos_tar->y - pos_src->y
255 );
256 if((dr - cb_src->contact_radius - cb_tar->contact_radius)
257 > 0.0f
258 )
259 break;
260
261 /* Get height bounds */
262 z1_min = pos_src->z + cb_src->contact_h_min;
263 z1_max = pos_src->z + cb_src->contact_h_max;
264 z2_min = pos_tar->z + cb_tar->contact_h_min;
265 z2_max = pos_tar->z + cb_tar->contact_h_max;
266 /* Check height bounds */
267 if((z1_min <= z2_max) &&
268 (z2_min <= z1_max)
269 )
270 {
271 SARSimObjectCollisionCB(
272 core_ptr, obj_ptr, obj_ptr2, 1.1
273 );
274 return(i);
275 }
276 break;
277
278 /* Cylendrical to Rectangular */
279 case SAR_CONTACT_SHAPE_RECTANGULAR:
280 /* First check z bounds */
281 z1_min = pos_src->z + cb_src->contact_h_min;
282 z1_max = pos_src->z + cb_src->contact_h_max;
283 z2_min = pos_tar->z + cb_tar->contact_z_min;
284 z2_max = pos_tar->z + cb_tar->contact_z_max;
285 if((z1_min <= z2_max) &&
286 (z2_min <= z1_max)
287 )
288 {
289 /* Calculate relative deltas from target object
290 * to source object
291 */
292 float dx = pos_src->x - pos_tar->x,
293 dy = pos_src->y - pos_tar->y,
294 src_radius = cb_src->contact_radius;
295 float dx2, dy2, x_min, x_max, y_min, y_max;
296
297 /* Rotate dx and dy about the center of the target
298 * object inversly incase target object has
299 * a rotated heading
300 */
301 dx2 = (cb_tar->cos_heading * dx) +
302 (cb_tar->sin_heading * dy);
303 dy2 = (cb_tar->cos_heading * dy) -
304 (cb_tar->sin_heading * dx);
305
306 /* Check if rotated dx and dy are in bounds
307 * with the target object contact bounds.
308 * Increase the bounds by the cylendrical
309 * radius of the source object.
310 */
311 x_min = cb_tar->contact_x_min - src_radius;
312 x_max = cb_tar->contact_x_max + src_radius;
313 y_min = cb_tar->contact_y_min - src_radius;
314 y_max = cb_tar->contact_y_max + src_radius;
315
316 if((dx2 >= x_min) && (dx2 <= x_max) &&
317 (dy2 >= y_min) && (dy2 <= y_max)
318 )
319 {
320 SARSimObjectCollisionCB(
321 core_ptr, obj_ptr, obj_ptr2, 1.1
322 );
323 return(i);
324 }
325 }
326 break;
327 }
328 }
329 break;
330
331 case SAR_CONTACT_SHAPE_RECTANGULAR:
332 /* Iterate through objects */
333 for(i = 0; i < core_ptr->total_objects; i++)
334 {
335 obj_ptr2 = core_ptr->object[i];
336 if(obj_ptr2 == NULL)
337 continue;
338
339 cb_tar = obj_ptr2->contact_bounds;
340 if(cb_tar == NULL)
341 continue;
342
343 /* Target not crashable? */
344 if(!(cb_tar->crash_flags & SAR_CRASH_FLAG_CRASH_CAUSE))
345 continue;
346
347 /* Skip ourself */
348 if(obj_ptr2 == obj_ptr)
349 continue;
350
351 pos_tar = &obj_ptr2->pos;
352
353 /* Handle by target object contact shape */
354 switch(cb_tar->contact_shape)
355 {
356 /* Rectangular to Spherical */
357 case SAR_CONTACT_SHAPE_SPHERICAL:
358 /* We'll be treating the source object as a square
359 * object based on its contact radius.
360 */
361 /* First check z bounds. */
362 z1_min = pos_src->z + cb_src->contact_z_min;
363 z1_max = pos_src->z + cb_src->contact_z_max;
364 z2_min = pos_tar->z - cb_tar->contact_radius;
365 z2_max = pos_tar->z + cb_tar->contact_radius;
366 if((z1_min <= z2_max) &&
367 (z2_min <= z1_max)
368 )
369 {
370 /* Calculate relative deltas from source object
371 * to target object
372 */
373 float dx = pos_tar->x - pos_src->x,
374 dy = pos_tar->y - pos_src->y,
375 tar_radius = cb_tar->contact_radius;
376 float dx2, dy2, x_min, x_max, y_min, y_max;
377
378 /* Rotate dx and dy about the center of the source
379 * object inversly if source object has a rotated
380 * heading
381 */
382 dx2 = (cb_src->cos_heading * dx) +
383 (cb_src->sin_heading * dy);
384 dy2 = (cb_src->cos_heading * dy) -
385 (cb_src->sin_heading * dx);
386
387 /* Calculate x and y bounds, add target object's
388 * contact bounds to increase the bounds.
389 */
390 x_min = cb_src->contact_x_min - tar_radius;
391 x_max = cb_src->contact_x_max + tar_radius;
392 y_min = cb_src->contact_y_min - tar_radius;
393 y_max = cb_src->contact_y_max + tar_radius;
394
395 /* Check if rotated dx2 and dy2 are in bounds. */
396 if((dx2 >= x_min) && (dx2 <= x_max) &&
397 (dy2 >= y_min) && (dy2 <= y_max)
398 )
399 {
400 SARSimObjectCollisionCB(
401 core_ptr, obj_ptr, obj_ptr2, 1.1f
402 );
403 return(i);
404 }
405 }
406 break;
407
408 /* Rectangular to Cylendrical */
409 case SAR_CONTACT_SHAPE_CYLENDRICAL:
410 /* First check z bounds */
411 z1_min = pos_src->z + cb_src->contact_z_min;
412 z1_max = pos_src->z + cb_src->contact_z_max;
413 z2_min = pos_tar->z + cb_tar->contact_h_min;
414 z2_max = pos_tar->z + cb_tar->contact_h_max;
415 if((z1_min <= z2_max) &&
416 (z2_min <= z1_max)
417 )
418 {
419 /* Calculate relative deltas from source object
420 * to target object
421 */
422 float dx = pos_tar->x - pos_src->x,
423 dy = pos_tar->y - pos_src->y,
424 tar_radius = cb_tar->contact_radius;
425 float dx2, dy2, x_min, x_max, y_min, y_max;
426
427 /* Rotate dx and dy about the center of the source
428 * object inversly if target object has a rotated
429 * heading
430 */
431 dx2 = (cb_src->cos_heading * dx) +
432 (cb_src->sin_heading * dy);
433 dy2 = (cb_src->cos_heading * dy) -
434 (cb_src->sin_heading * dx);
435
436 /* Check if rotated dx and dy are in bounds
437 * with the target object contact bounds.
438 * Increase the bounds by the cylendrical
439 * radius of the source object.
440 */
441 x_min = cb_src->contact_x_min - tar_radius;
442 x_max = cb_src->contact_x_max + tar_radius;
443 y_min = cb_src->contact_y_min - tar_radius;
444 y_max = cb_src->contact_y_max + tar_radius;
445
446 if((dx2 >= x_min) && (dx2 <= x_max) &&
447 (dy2 >= y_min) && (dy2 <= y_max)
448 )
449 {
450 SARSimObjectCollisionCB(
451 core_ptr, obj_ptr, obj_ptr2, 1.1
452 );
453 return(i);
454 }
455 }
456 break;
457
458 /* Rectangular to Rectangular */
459 case SAR_CONTACT_SHAPE_RECTANGULAR:
460 /* TODO */
461 break;
462 }
463 }
464 break;
465 }
466
467 return(-1);
468 }
469
470
471 /*
472 * Hoist deployment contact check.
473 *
474 * Checks if an object that can be picked up is within range of the
475 * hoist's deployment to be picked up by the hoist's deployment.
476 *
477 * If an object has come in contact then the proper procedure will
478 * be taken.
479 *
480 * Inputs assumed valid.
481 *
482 * Returns the object number of the picked up object or -1 on no
483 * match.
484 */
SARSimHoistDeploymentContactCheck(sar_core_struct * core_ptr,sar_object_struct * obj_ptr)485 int SARSimHoistDeploymentContactCheck(
486 sar_core_struct *core_ptr, sar_object_struct *obj_ptr
487 )
488 {
489 Boolean need_break;
490 int tar_obj_num, matched_obj_num = -1;
491 float d, contact_radius;
492 sar_object_struct *tar_obj_ptr;
493 sar_object_human_struct *human_ptr;
494 sar_obj_hoist_struct *hoist;
495 const sar_position_struct *pos_src, *pos_tar;
496 const sar_contact_bounds_struct *cb_tar;
497 sar_scene_struct *scene = core_ptr->scene;
498 const sar_option_struct *opt = &core_ptr->option;
499
500 /* Get first hoist on object, if the object does not have a
501 * hoist then that there is nothing to check
502 */
503 hoist = SARObjGetHoistPtr(obj_ptr, 0, NULL);
504 if(hoist == NULL)
505 return(matched_obj_num);
506
507 /* Hoist fully retracted? */
508 if(hoist->rope_cur <= 0.0f)
509 return(matched_obj_num);
510
511 /* Get hoist deployment's flat contact radius
512 *
513 * If this is the player object then multiply the contact radius
514 * with the hoist contact expansion coefficient
515 */
516 contact_radius = hoist->contact_radius * 2.0f *
517 ((scene->player_obj_ptr == obj_ptr) ?
518 MAX(opt->hoist_contact_expansion_coeff, 1.0f) : 1.0f);
519
520 pos_src = &hoist->pos; /* Hoist deployment's position */
521
522
523 /* Iterate through objects, looking for one that can be picked
524 * up by the hoist's deployment
525 */
526 for(tar_obj_num = 0; tar_obj_num < core_ptr->total_objects; tar_obj_num++)
527 {
528 tar_obj_ptr = core_ptr->object[tar_obj_num];
529 if(tar_obj_ptr == NULL)
530 continue;
531
532 /* Get contact bounds for target object */
533 cb_tar = tar_obj_ptr->contact_bounds;
534 if(cb_tar == NULL)
535 continue;
536
537 #if 0
538 /* It is safe to bypass this check */
539 /* Contact shapes for target object must be cylendrical or
540 * spherical shaped
541 */
542 if((cb_tar->contact_shape != SAR_CONTACT_SHAPE_SPHERICAL) &&
543 (cb_tar->contact_shape != SAR_CONTACT_SHAPE_CYLENDRICAL)
544 )
545 continue;
546 #endif
547
548 /* Handle by target object type */
549 switch(tar_obj_ptr->type)
550 {
551 case SAR_OBJ_TYPE_GARBAGE:
552 case SAR_OBJ_TYPE_STATIC:
553 case SAR_OBJ_TYPE_AUTOMOBILE:
554 case SAR_OBJ_TYPE_WATERCRAFT:
555 case SAR_OBJ_TYPE_AIRCRAFT:
556 case SAR_OBJ_TYPE_GROUND:
557 case SAR_OBJ_TYPE_RUNWAY:
558 case SAR_OBJ_TYPE_HELIPAD:
559 break;
560
561 case SAR_OBJ_TYPE_HUMAN:
562 human_ptr = SAR_OBJ_GET_HUMAN(tar_obj_ptr);
563 if(human_ptr == NULL)
564 break;
565
566 /* Does not want to be picked up? */
567 if(!(human_ptr->flags & SAR_HUMAN_FLAG_NEED_RESCUE))
568 break;
569
570 pos_tar = &tar_obj_ptr->pos;
571
572 /* Check contact bounds by target object's contact
573 * shape
574 *
575 * Reset need_break to False, it will be to True if
576 * there was NO contact
577 */
578 need_break = False;
579 switch(cb_tar->contact_shape)
580 {
581 case SAR_CONTACT_SHAPE_SPHERICAL:
582 /* Calculate distance */
583 d = (float)SFMHypot2(
584 pos_tar->x - pos_src->x,
585 pos_tar->y - pos_src->y
586 );
587 /* Within rescue basket pickup distance? */
588 if((d - contact_radius - cb_tar->contact_radius) >
589 0.0f
590 )
591 {
592 need_break = True;
593 break;
594 }
595 /* Is target object under the rescue basket? */
596 if((pos_tar->z + cb_tar->contact_radius) <
597 (pos_src->z + hoist->contact_z_min)
598 )
599 {
600 need_break = True;
601 break;
602 }
603 break;
604
605 case SAR_CONTACT_SHAPE_CYLENDRICAL:
606 /* Calculate distance */
607 d = (float)SFMHypot2(
608 pos_tar->x - pos_src->x,
609 pos_tar->y - pos_src->y
610 );
611 /* Within rescue basket pickup distance? */
612 if((d - contact_radius - cb_tar->contact_radius) >
613 0.0f
614 )
615 {
616 need_break = True;
617 break;
618 }
619 /* Is target object under the rescue basket? */
620 if((pos_tar->z + cb_tar->contact_h_max) <
621 (pos_src->z + hoist->contact_z_min)
622 )
623 {
624 need_break = True;
625 break;
626 }
627 break;
628
629 case SAR_CONTACT_SHAPE_RECTANGULAR:
630 /* Calculate distance */
631 d = (float)SFMHypot2(
632 pos_tar->x - pos_src->x,
633 pos_tar->y - pos_src->y
634 );
635 /* Within rescue basket pickup distance? */
636 /* Using target object's x bounds for now */
637 if((d - contact_radius -
638 (cb_tar->contact_x_max - cb_tar->contact_x_min)) >
639 0.0f
640 )
641 {
642 need_break = True;
643 break;
644 }
645 /* Is target object under the rescue basket? */
646 if((pos_tar->z + cb_tar->contact_z_max) <
647 (pos_src->z + hoist->contact_z_min)
648 )
649 {
650 need_break = True;
651 break;
652 }
653 break;
654 }
655 if(need_break)
656 break;
657
658 /* Put human object into the hoist deployment (if
659 * possible) and update the human object to mark it
660 * as no longer needing rescue
661 */
662 if(SARSimDoPickUpHuman(scene, obj_ptr, human_ptr, tar_obj_num) > 0)
663 {
664 matched_obj_num = tar_obj_num;
665 return(matched_obj_num);
666 }
667 break;
668
669 case SAR_OBJ_TYPE_SMOKE:
670 case SAR_OBJ_TYPE_FIRE:
671 case SAR_OBJ_TYPE_EXPLOSION:
672 case SAR_OBJ_TYPE_CHEMICAL_SPRAY:
673 case SAR_OBJ_TYPE_FUELTANK:
674 case SAR_OBJ_TYPE_PREMODELED:
675 break;
676 }
677 }
678
679 return(matched_obj_num);
680 }
681
682