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 //	Collision intersection code for EDMS models...
20 //	==============================================
21 
22 //	Seamus, "in Prozac we trust," 1994
23 //	==================================
24 
25 #include "edms_int.h"
26 #include "idof.h"
27 
28 //#ifdef EDMS_SHIPPABLE
29 ////#include <mout.h>
30 //#endif
31 
32 //              Collision wakeups go here...
33 //              ----------------------------
34 extern int32_t alarm_clock[MAX_OBJ];
35 extern int32_t no_no_not_me[MAX_OBJ];
36 
37 bool do_work(int32_t object, int32_t other_object, Q my_rad, Q your_rad, Fixpoint *my_pos, Fixpoint *other_pos,
38              Q &result0, Q &result1, Q &result2);
39 
40 void shall_we_dance(int32_t object, Q &result0, Q &result1, Q &result2);
41 
42 //	Call me instead of having special code everywhere...
43 //	====================================================
shall_we_dance(int32_t object,Q & result0,Q & result1,Q & result2)44 void shall_we_dance(int32_t object, Q &result0, Q &result1, Q &result2) {
45     int32_t other_object;
46 
47     Q my_radius, your_radius;
48 
49     Q my_position[3], your_position[3];
50 
51     //	Collision B/C...
52     //	----------------
53     result0 = result1 = result2 = 0; // B/C...
54 
55     //	Here we assume that all hits are encompassed by the projection of the
56     //	default radius.  If this is not true, then special care must be taken
57     //	in the design of the model...
58     //	-----------------------------
59 
60     // mask contains the bits corresponding to the objects that could be
61     // intersecting object.
62 
63     uint32_t mask = are_you_there(object);
64     uint32_t bit = 0; // which object bit we're checking
65 
66     while (mask != 0) {
67         if (mask & 1) {
68             // Object bit number 'bit' is on, we must check all objects which have that bit
69             for (other_object = bit; other_object < MAX_OBJ && S[other_object][0][0] > END;
70                  other_object += NUM_OBJECT_BITS) {
71 
72                 if (other_object != object && I[object][IDOF_COLLIDE].to_int() != other_object) {
73 
74                     //	Okay, now we have a confirmed hash hit...
75                     //	-----------------------------------------
76 
77                     //	Do the regular guy, workaday collision...
78                     //	-----------------------------------------
79                     my_position[0] = A[object][0][0];
80                     my_position[1] = A[object][1][0];
81                     my_position[2] = A[object][2][0];
82 
83                     // if you're asleep, then we have to look at STATE...
84                     // --------------------------------------------------
85                     if (no_no_not_me[other_object] == 1) {
86                         your_position[0] = A[other_object][0][0];
87                         your_position[1] = A[other_object][1][0];
88                         your_position[2] = A[other_object][2][0];
89                     } else {
90                         your_position[0] = S[other_object][0][0];
91                         your_position[1] = S[other_object][1][0];
92                         your_position[2] = S[other_object][2][0];
93                     }
94 
95                     my_radius = I[object][IDOF_RADIUS];
96                     your_radius = I[other_object][IDOF_RADIUS];
97 
98                     do_work(object, other_object, my_radius, your_radius, my_position, your_position, result0, result1,
99                             result2);
100 
101                     int32_t you_are_special = 0, I_am_special = 0;
102 
103                     //	Are YOU special???
104                     //	------------------
105                     if (I[other_object][IDOF_MODEL] == PELVIS) {
106                         Q offset_x = I[other_object][0] * sin(A[other_object][4][0]),
107                           offset_y = -1.5 * I[other_object][0] * sin(A[other_object][5][0]),
108                           offset_z = I[other_object][0] * cos(A[other_object][4][0]) * cos(A[other_object][5][0]);
109 
110                         Q sin_alpha = 0, cos_alpha = 0;
111 
112                         sincos(-A[other_object][3][0], &sin_alpha, &cos_alpha);
113 
114                         Q final_x = cos_alpha * offset_x + sin_alpha * offset_y;
115                         Q final_y = -sin_alpha * offset_x + cos_alpha * offset_y;
116 
117                         your_position[0] = A[other_object][0][0] + final_x;
118                         your_position[1] = A[other_object][1][0] + final_y;
119                         your_position[2] = A[other_object][2][0] + offset_z;
120 
121                         my_radius = I[object][IDOF_RADIUS];
122                         your_radius = .75 * I[other_object][IDOF_PELVIS_RADIUS];
123 
124                         do_work(object, other_object, my_radius, your_radius, my_position, your_position, result0,
125                                 result1, result2);
126                     } // You're not special.
127 
128                     // Am I special???
129                     // ---------------
130                     if (I[object][IDOF_MODEL] == PELVIS) {
131                         Q offset_x = I[object][0] * sin(A[object][4][0]),
132                           offset_y = -1.5 * I[object][0] * sin(A[object][5][0]),
133                           offset_z = I[object][0] * cos(A[object][4][0]) * cos(A[object][5][0]);
134 
135                         Q sin_alpha = 0, cos_alpha = 0;
136 
137                         sincos(-A[object][3][0], &sin_alpha, &cos_alpha);
138 
139                         Q final_x = cos_alpha * offset_x + sin_alpha * offset_y;
140                         Q final_y = -sin_alpha * offset_x + cos_alpha * offset_y;
141 
142                         my_position[0] = A[object][0][0] + final_x;
143                         my_position[1] = A[object][1][0] + final_y;
144                         my_position[2] = A[object][2][0] + offset_z;
145 
146                         // if you're asleep, then we have to look at STATE...
147                         // --------------------------------------------------
148                         if (no_no_not_me[other_object] == 1) {
149                             your_position[0] = A[other_object][0][0];
150                             your_position[1] = A[other_object][1][0];
151                             your_position[2] = A[other_object][2][0];
152                         } else {
153                             your_position[0] = S[other_object][0][0];
154                             your_position[1] = S[other_object][1][0];
155                             your_position[2] = S[other_object][2][0];
156                         }
157 
158                         my_radius = .75 * I[object][IDOF_PELVIS_RADIUS];
159                         your_radius = I[other_object][IDOF_RADIUS];
160 
161                         do_work(object, other_object, my_radius, your_radius, my_position, your_position, result0,
162                                 result1, result2);
163                     } // I'm not special...
164                 }     // No hash hit...
165             }
166         }
167 
168         // Shift over the mask so we're testing the next object bit
169         mask >>= 1;
170         bit++;
171     }
172 }
173 
174 Q dx, dy, dz;
175 
176 //	Here's the meat of the sutuation...
177 //	===================================
do_work(int32_t object,int32_t other_object,Q my_rad,Q your_rad,Fixpoint * my_pos,Fixpoint * other_pos,Q & result0,Q & result1,Q & result2)178 bool do_work(int32_t object, int32_t other_object, Q my_rad, Q your_rad, Fixpoint *my_pos, Fixpoint *other_pos,
179              Q &result0, Q &result1, Q &result2) {
180     Q cm_radius = (my_rad + your_rad);
181 
182     // First do a preliminary check to avoid overflow.
183     dx = my_pos[0] - other_pos[0];
184     dy = my_pos[1] - other_pos[1];
185     dz = my_pos[2] - other_pos[2];
186 
187     if (dx >= cm_radius || dy >= cm_radius || dz >= cm_radius) {
188         return false; // couldn't possibly collide
189     }
190 
191     // Test for primary collision...
192     // =============================
193     Q test_radius = sqrt(dx * dx + dy * dy + dz * dz);
194 
195     if ((test_radius < cm_radius) && (test_radius > 0.0005)) {
196 
197         // Is there a problem???
198         // ---------------------
199         if (test_radius < .03)
200             test_radius = .03;
201 
202         //	Callback...
203         //	-----------
204         physics_handle C = on2ph[object], V = on2ph[other_object];
205 
206         int32_t badness = (20 * (1. - test_radius / cm_radius)).to_int();
207 
208         fix location[3];
209 
210         location[0] = my_pos[0].to_fix();
211         location[1] = my_pos[1].to_fix();
212         location[2] = my_pos[2].to_fix();
213 
214         EDMS_object_collision(C, V, badness, 0, 0, location);
215 
216         Q Eta = (cm_radius - test_radius); // Eta...
217 
218         test_radius = 1 / test_radius;
219         result0 += Eta * dx * test_radius;
220         result1 += Eta * dy * test_radius;
221         result2 += Eta * dz * test_radius;
222 
223         // God save the Queen...
224         // ---------------------
225         if (result0 > my_rad)
226             result0 = my_rad;
227         if (result0 < -my_rad)
228             result0 = -my_rad;
229 
230         if (result1 > my_rad)
231             result1 = my_rad;
232         if (result1 < -my_rad)
233             result1 = -my_rad;
234 
235         //	Wakeup...
236         //	=========
237         if (no_no_not_me[other_object] == 0) {
238             //       mout << "Other guy was asleep: " << other_object << "\n";
239             //   		collision_wakeup( other_object );
240             alarm_clock[other_object] = 1;
241         }
242 
243         return true; // collision
244     }                // End of radius check...
245     else {
246         return false;
247     }
248 }
249