/*
Copyright (C) 2015-2018 Night Dive Studios, LLC.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
// Collision intersection code for EDMS models...
// ==============================================
// Seamus, "in Prozac we trust," 1994
// ==================================
#include "edms_int.h"
#include "idof.h"
//#ifdef EDMS_SHIPPABLE
////#include
//#endif
// Collision wakeups go here...
// ----------------------------
extern int32_t alarm_clock[MAX_OBJ];
extern int32_t no_no_not_me[MAX_OBJ];
bool 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);
void shall_we_dance(int32_t object, Q &result0, Q &result1, Q &result2);
// Call me instead of having special code everywhere...
// ====================================================
void shall_we_dance(int32_t object, Q &result0, Q &result1, Q &result2) {
int32_t other_object;
Q my_radius, your_radius;
Q my_position[3], your_position[3];
// Collision B/C...
// ----------------
result0 = result1 = result2 = 0; // B/C...
// Here we assume that all hits are encompassed by the projection of the
// default radius. If this is not true, then special care must be taken
// in the design of the model...
// -----------------------------
// mask contains the bits corresponding to the objects that could be
// intersecting object.
uint32_t mask = are_you_there(object);
uint32_t bit = 0; // which object bit we're checking
while (mask != 0) {
if (mask & 1) {
// Object bit number 'bit' is on, we must check all objects which have that bit
for (other_object = bit; other_object < MAX_OBJ && S[other_object][0][0] > END;
other_object += NUM_OBJECT_BITS) {
if (other_object != object && I[object][IDOF_COLLIDE].to_int() != other_object) {
// Okay, now we have a confirmed hash hit...
// -----------------------------------------
// Do the regular guy, workaday collision...
// -----------------------------------------
my_position[0] = A[object][0][0];
my_position[1] = A[object][1][0];
my_position[2] = A[object][2][0];
// if you're asleep, then we have to look at STATE...
// --------------------------------------------------
if (no_no_not_me[other_object] == 1) {
your_position[0] = A[other_object][0][0];
your_position[1] = A[other_object][1][0];
your_position[2] = A[other_object][2][0];
} else {
your_position[0] = S[other_object][0][0];
your_position[1] = S[other_object][1][0];
your_position[2] = S[other_object][2][0];
}
my_radius = I[object][IDOF_RADIUS];
your_radius = I[other_object][IDOF_RADIUS];
do_work(object, other_object, my_radius, your_radius, my_position, your_position, result0, result1,
result2);
int32_t you_are_special = 0, I_am_special = 0;
// Are YOU special???
// ------------------
if (I[other_object][IDOF_MODEL] == PELVIS) {
Q offset_x = I[other_object][0] * sin(A[other_object][4][0]),
offset_y = -1.5 * I[other_object][0] * sin(A[other_object][5][0]),
offset_z = I[other_object][0] * cos(A[other_object][4][0]) * cos(A[other_object][5][0]);
Q sin_alpha = 0, cos_alpha = 0;
sincos(-A[other_object][3][0], &sin_alpha, &cos_alpha);
Q final_x = cos_alpha * offset_x + sin_alpha * offset_y;
Q final_y = -sin_alpha * offset_x + cos_alpha * offset_y;
your_position[0] = A[other_object][0][0] + final_x;
your_position[1] = A[other_object][1][0] + final_y;
your_position[2] = A[other_object][2][0] + offset_z;
my_radius = I[object][IDOF_RADIUS];
your_radius = .75 * I[other_object][IDOF_PELVIS_RADIUS];
do_work(object, other_object, my_radius, your_radius, my_position, your_position, result0,
result1, result2);
} // You're not special.
// Am I special???
// ---------------
if (I[object][IDOF_MODEL] == PELVIS) {
Q offset_x = I[object][0] * sin(A[object][4][0]),
offset_y = -1.5 * I[object][0] * sin(A[object][5][0]),
offset_z = I[object][0] * cos(A[object][4][0]) * cos(A[object][5][0]);
Q sin_alpha = 0, cos_alpha = 0;
sincos(-A[object][3][0], &sin_alpha, &cos_alpha);
Q final_x = cos_alpha * offset_x + sin_alpha * offset_y;
Q final_y = -sin_alpha * offset_x + cos_alpha * offset_y;
my_position[0] = A[object][0][0] + final_x;
my_position[1] = A[object][1][0] + final_y;
my_position[2] = A[object][2][0] + offset_z;
// if you're asleep, then we have to look at STATE...
// --------------------------------------------------
if (no_no_not_me[other_object] == 1) {
your_position[0] = A[other_object][0][0];
your_position[1] = A[other_object][1][0];
your_position[2] = A[other_object][2][0];
} else {
your_position[0] = S[other_object][0][0];
your_position[1] = S[other_object][1][0];
your_position[2] = S[other_object][2][0];
}
my_radius = .75 * I[object][IDOF_PELVIS_RADIUS];
your_radius = I[other_object][IDOF_RADIUS];
do_work(object, other_object, my_radius, your_radius, my_position, your_position, result0,
result1, result2);
} // I'm not special...
} // No hash hit...
}
}
// Shift over the mask so we're testing the next object bit
mask >>= 1;
bit++;
}
}
Q dx, dy, dz;
// Here's the meat of the sutuation...
// ===================================
bool 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) {
Q cm_radius = (my_rad + your_rad);
// First do a preliminary check to avoid overflow.
dx = my_pos[0] - other_pos[0];
dy = my_pos[1] - other_pos[1];
dz = my_pos[2] - other_pos[2];
if (dx >= cm_radius || dy >= cm_radius || dz >= cm_radius) {
return false; // couldn't possibly collide
}
// Test for primary collision...
// =============================
Q test_radius = sqrt(dx * dx + dy * dy + dz * dz);
if ((test_radius < cm_radius) && (test_radius > 0.0005)) {
// Is there a problem???
// ---------------------
if (test_radius < .03)
test_radius = .03;
// Callback...
// -----------
physics_handle C = on2ph[object], V = on2ph[other_object];
int32_t badness = (20 * (1. - test_radius / cm_radius)).to_int();
fix location[3];
location[0] = my_pos[0].to_fix();
location[1] = my_pos[1].to_fix();
location[2] = my_pos[2].to_fix();
EDMS_object_collision(C, V, badness, 0, 0, location);
Q Eta = (cm_radius - test_radius); // Eta...
test_radius = 1 / test_radius;
result0 += Eta * dx * test_radius;
result1 += Eta * dy * test_radius;
result2 += Eta * dz * test_radius;
// God save the Queen...
// ---------------------
if (result0 > my_rad)
result0 = my_rad;
if (result0 < -my_rad)
result0 = -my_rad;
if (result1 > my_rad)
result1 = my_rad;
if (result1 < -my_rad)
result1 = -my_rad;
// Wakeup...
// =========
if (no_no_not_me[other_object] == 0) {
// mout << "Other guy was asleep: " << other_object << "\n";
// collision_wakeup( other_object );
alarm_clock[other_object] = 1;
}
return true; // collision
} // End of radius check...
else {
return false;
}
}