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