Implements camera wobble and concussion (#289)

* implements wobble and concussion

Co-authored-by: Anonymous Maarten <madebr@users.noreply.github.com>
This commit is contained in:
Dethrace Engineering Department 2023-02-20 21:34:34 +13:00 committed by GitHub
parent 7f44f7f962
commit 81f8edc803
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 142 additions and 80 deletions

View File

@ -27,6 +27,7 @@
#define BR_ANGLE_RAD(rad) ((br_angle)((rad)*10430))
#define BrDegreeToRadian(d) ((br_scalar)((d) * (PI / 180.0)))
#define BrRadianToDegree(r) ((br_scalar)((r) * (180.0 / PI)))
#define BrDegreeToAngle(d) ((br_angle)(long)((d) * (65536.0f / 360.0f))) // "d * 182.044444444"
#define BrAngleToDegrees(a) ((br_angle)(long)((a) * (360.0f / 65536.0f))) // "d * 0.0054931640625"

View File

@ -50,8 +50,8 @@ void (*ControlCar[6])(tCar_spec*, br_scalar) = {
&ControlCar5,
NULL,
};
int gControl__car = 3; // suffix added to avoid duplicate symbol
int gFace_num__car = 1; // suffix added to avoid duplicate symbol
int gControl__car = 3; // suffix added to avoid duplicate symbol
int gFace_num__car = 1; // suffix added to avoid duplicate symbol
br_angle gOld_yaw__car = 0; // suffix added to avoid duplicate symbol
br_angle gOld_zoom = 0;
br_vector3 gCamera_pos_before_collide = { { 0 } };
@ -78,7 +78,7 @@ tU32 gQuite_wild_end = 0;
tU32 gOn_me_wheels_start = 0;
int gWoz_upside_down_at_all = 0;
tS3_sound_tag gSkid_tag[2] = { 0, 0 };
tCar_spec* gLast_car_to_skid[2] = { NULL, NULL};
tCar_spec* gLast_car_to_skid[2] = { NULL, NULL };
int gEliminate_faces = 0;
br_vector3 gZero_v__car = { { 0 } }; // suffix added to avoid duplicate symbol
tU32 gSwitch_time = 0;
@ -981,7 +981,7 @@ void FinishCars(tU32 pLast_frame_time, tU32 pTime) {
if (car->driver >= eDriver_oppo) {
car->speedo_speed = BrVector3Dot(&minus_k, &car->v) / (WORLD_SCALE * 1000.0f);
car->steering_angle = d180_OVER_PI * atanf((car->wpos[0].v[2] - car->wpos[2].v[2]) * car->curvature);
car->steering_angle = BrRadianToDegree(atanf((car->wpos[0].v[2] - car->wpos[2].v[2]) * car->curvature));
car->lr_sus_position = (car->ride_height - car->oldd[0]) / WORLD_SCALE;
car->rr_sus_position = (car->ride_height - car->oldd[1]) / WORLD_SCALE;
@ -4205,8 +4205,8 @@ void MungeCarGraphics(tU32 pFrame_period) {
} else if (!gOn_me_wheels_start) {
gOn_me_wheels_start = the_time;
} else if (the_time - gOn_me_wheels_start > 500
&& (the_car->last_special_volume == NULL
|| the_car->last_special_volume->gravity_multiplier == 1.0f)) {
&& (the_car->last_special_volume == NULL
|| the_car->last_special_volume->gravity_multiplier == 1.0f)) {
DoFancyHeadup(kFancyHeadupCunningStuntBonus);
EarnCredits(gCunning_stunt_bonus[gProgram_state.skill_level]);
gLast_cunning_stunt = PDGetTotalTime();
@ -4220,7 +4220,8 @@ void MungeCarGraphics(tU32 pFrame_period) {
}
if (the_car->driver != eDriver_local_human && the_car->car_model_variable) {
distance_from_camera = Vector3DistanceSquared(&the_car->car_master_actor->t.t.translate.t,
(br_vector3*)gCamera_to_world.m[3]) / gCar_simplification_factor[gGraf_spec_index][gCar_simplification_level];
(br_vector3*)gCamera_to_world.m[3])
/ gCar_simplification_factor[gGraf_spec_index][gCar_simplification_level];
if (gNet_mode != eNet_mode_none && gNet_players[gIt_or_fox].car == the_car) {
distance_from_camera = 0.f;
}
@ -4372,7 +4373,7 @@ void ViewOpponent() {
void ToggleCarToCarCollisions() {
LOG_TRACE("()");
gCar_car_collisions = !gCar_car_collisions;
gCar_car_collisions = !gCar_car_collisions;
if (gCar_car_collisions) {
NewTextHeadupSlot(4, 0, 3000, -4, "Car Car Collisions");
} else {

View File

@ -1093,6 +1093,7 @@ void ToggleMirror() {
}
// IDA: void __cdecl ConcussMe()
// dethrace: this is not referenced in the retail executables. Left over debug code.
void ConcussMe() {
LOG_TRACE("()");
@ -2349,7 +2350,7 @@ void CycleSoundDetailLevel() {
new_level = (gSound_detail_level + 1) % 3;
ReallySetSoundDetailLevel(new_level);
SetSoundDetailLevel(new_level);
switch(new_level) {
switch (new_level) {
case 0:
NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(116));
break;

View File

@ -1087,30 +1087,30 @@ void DoInstruments(tU32 pThe_time) {
the_angle = DEG_TO_RAD((double)gProgram_state.current_car.tacho_end_angle[gProgram_state.cockpit_on]);
}
if (the_angle >= 0.0) {
if (the_angle >= 6.283185307179586) {
the_angle = the_angle - 6.283185307179586;
if (the_angle >= TAU) {
the_angle -= TAU;
}
} else {
the_angle = the_angle + 6.283185307179586;
the_angle += TAU;
}
the_angle2 = 1.570796326794897 - the_angle;
the_angle2 = DR_PI_OVER_2 - the_angle;
if (the_angle2 < 0) {
the_angle2 = the_angle2 + 6.283185307179586;
the_angle2 += TAU;
}
if (the_angle2 > 4.71238898038469) {
cos_angle = gCosine_array[(unsigned int)((6.283185307179586 - the_angle2) / DR_PI * 128.0)];
if (the_angle2 > DR_3PI_OVER_2) {
cos_angle = gCosine_array[(unsigned int)((TAU - the_angle2) / DR_PI * 128.0)];
} else if (the_angle2 > DR_PI) {
cos_angle = -gCosine_array[(unsigned int)((the_angle2 - DR_PI) / DR_PI * 128.0)];
} else if (the_angle2 > 1.5707963267948966) {
} else if (the_angle2 > DR_PI_OVER_2) {
cos_angle = -gCosine_array[(unsigned int)((DR_PI - the_angle2) / DR_PI * 128.0)];
} else {
cos_angle = gCosine_array[(unsigned int)(the_angle2 / DR_PI * 128.0)];
}
if (the_angle > 4.71238898038469) {
sin_angle = gCosine_array[(unsigned int)((6.283185307179586 - the_angle) / DR_PI * 128.0)];
if (the_angle > DR_3PI_OVER_2) {
sin_angle = gCosine_array[(unsigned int)((TAU - the_angle) / DR_PI * 128.0)];
} else if (the_angle > DR_PI) {
sin_angle = -gCosine_array[(unsigned int)((the_angle - DR_PI) / DR_PI * 128.0)];
} else if (the_angle > 1.5707963267948966) {
} else if (the_angle > DR_PI_OVER_2) {
sin_angle = -gCosine_array[(unsigned int)((DR_PI - the_angle) / DR_PI * 128.0)];
} else {
sin_angle = gCosine_array[(unsigned int)(the_angle / DR_PI * 128.0)];
@ -1173,7 +1173,7 @@ void DoInstruments(tU32 pThe_time) {
#define GEAR_HEIGHT ((int)gProgram_state.current_car.gears_image->height / 8)
#define GEAR_HEIGHT_HIRES GEAR_HEIGHT
#endif
gear_height = gGraf_spec_index ? GEAR_HEIGHT_HIRES : GEAR_HEIGHT;
gear_height = gGraf_spec_index ? GEAR_HEIGHT_HIRES : GEAR_HEIGHT;
DRPixelmapRectangleMaskedCopy(
gBack_screen,
the_wobble_x + gProgram_state.current_car.gear_x[gProgram_state.cockpit_on],
@ -1203,32 +1203,30 @@ void DoInstruments(tU32 pThe_time) {
the_angle = DEG_TO_RAD((double)gProgram_state.current_car.speedo_end_angle[gProgram_state.cockpit_on]);
}
if (the_angle >= 0.0) {
if (the_angle >= 6.283185307179586) {
the_angle = the_angle - 6.283185307179586;
}
} else {
the_angle = the_angle + 6.283185307179586;
if (the_angle < 0.0) {
the_angle = the_angle + TAU;
} else if (the_angle >= TAU) {
the_angle -= TAU;
}
the_angle2 = 1.570796326794897 - the_angle;
the_angle2 = DR_PI_OVER_2 - the_angle;
if (the_angle2 < 0.0) {
the_angle2 = the_angle2 + 6.283185307179586;
the_angle2 += TAU;
}
if (the_angle2 > 4.71238898038469) {
cos_angle = gCosine_array[(unsigned int)((6.283185307179586 - the_angle2) / DR_PI * 128.0)];
if (the_angle2 > DR_3PI_OVER_2) {
cos_angle = gCosine_array[(unsigned int)((TAU - the_angle2) / DR_PI * 128.0)];
} else if (the_angle2 > DR_PI) {
cos_angle = -gCosine_array[(unsigned int)((the_angle2 - DR_PI) / DR_PI * 128.0)];
} else if (the_angle2 > 1.5707963267948966) {
} else if (the_angle2 > DR_PI_OVER_2) {
cos_angle = -gCosine_array[(unsigned int)((DR_PI - the_angle2) / DR_PI * 128.0)];
} else {
cos_angle = gCosine_array[(unsigned int)(the_angle2 / DR_PI * 128.0)];
}
if (the_angle > 4.71238898038469) {
sin_angle = gCosine_array[(unsigned int)((6.283185307179586 - the_angle) / DR_PI * 128.0)];
if (the_angle > DR_3PI_OVER_2) {
sin_angle = gCosine_array[(unsigned int)((TAU - the_angle) / DR_PI * 128.0)];
} else if (the_angle > DR_PI) {
sin_angle = -gCosine_array[(unsigned int)((the_angle - DR_PI) / DR_PI * 128.0)];
} else if (the_angle > 1.5707963267948966) {
} else if (the_angle > DR_PI_OVER_2) {
sin_angle = -gCosine_array[(unsigned int)((DR_PI - the_angle) / DR_PI * 128.0)];
} else {
sin_angle = gCosine_array[(unsigned int)(the_angle / DR_PI * 128.0)];

View File

@ -728,7 +728,7 @@ void ClearWobbles() {
int i;
LOG_TRACE("()");
for (i = 0; i < COUNT_OF(gWobble_array); ++i) {
for (i = 0; i < COUNT_OF(gWobble_array); i++) {
gWobble_array[i].time_started = 0;
}
}
@ -739,7 +739,7 @@ void InitWobbleStuff() {
ClearWobbles();
for (i = 0; i < COUNT_OF(gCosine_array); i++) {
gCosine_array[i] = cosf(i / 64.0f * 3.141592653589793f / 2.0f);
gCosine_array[i] = cosf(i / 64.0f * DR_PI / 2.0f);
}
}
@ -792,9 +792,44 @@ void CalculateWobblitude(tU32 pThe_time) {
double cosine_over_angle;
LOG_TRACE("(%d)", pThe_time);
if (gProgram_state.new_view != eView_undefined) {
return;
}
gScreen_wobble_x = 0;
gScreen_wobble_y = 0;
STUB_ONCE();
for (i = 0; i < COUNT_OF(gWobble_array); i++) {
if (gWobble_array[i].time_started != 0) {
time_going = pThe_time - gWobble_array[i].time_started;
if (time_going > 1000) {
gWobble_array[i].time_started = 0;
} else {
mod_angle = fmod(time_going / gWobble_array[i].period, TAU);
if (mod_angle > DR_3PI_OVER_2) {
cosine_over_angle = gCosine_array[(unsigned int)((TAU - mod_angle) / DR_PI * 128.0)];
} else if (mod_angle > DR_PI) {
cosine_over_angle = -gCosine_array[(unsigned int)((mod_angle - DR_PI) / DR_PI * 128.0)];
} else if (mod_angle > DR_PI_OVER_2) {
cosine_over_angle = -gCosine_array[(unsigned int)((DR_PI - mod_angle) / DR_PI * 128.0)];
} else {
cosine_over_angle = gCosine_array[(unsigned int)(mod_angle / DR_PI * 128.0)];
}
angle = cosine_over_angle / ((double)(pThe_time - gWobble_array[i].time_started) * 0.0035f + 1.0f);
gScreen_wobble_x = (gWobble_array[i].amplitude_x * angle + gScreen_wobble_x);
gScreen_wobble_y = (gWobble_array[i].amplitude_y * angle + gScreen_wobble_y);
}
}
}
if (gScreen_wobble_x > gCurrent_graf_data->cock_margin_x) {
gScreen_wobble_x = gCurrent_graf_data->cock_margin_x;
} else if (gScreen_wobble_x < -gCurrent_graf_data->cock_margin_x) {
gScreen_wobble_x = -gCurrent_graf_data->cock_margin_x;
}
if (gScreen_wobble_y > gCurrent_graf_data->cock_margin_y) {
gScreen_wobble_y = gCurrent_graf_data->cock_margin_y;
} else if (gScreen_wobble_y < -gCurrent_graf_data->cock_margin_y) {
gScreen_wobble_y = -gCurrent_graf_data->cock_margin_y;
}
PipeSingleScreenShake(gScreen_wobble_x, gScreen_wobble_y);
}
// IDA: void __usercall CalculateConcussion(tU32 pThe_time@<EAX>)
@ -808,8 +843,34 @@ void CalculateConcussion(tU32 pThe_time) {
float cosine_over_angle;
LOG_TRACE("(%d)", pThe_time);
gConcussion.concussed = 0;
STUB_ONCE();
if (!gConcussion.concussed) {
return;
}
time_difference = pThe_time - gConcussion.time_started;
if (pThe_time - gConcussion.time_started > 2000) {
gConcussion.concussed = 0;
} else {
for (i = 0; i < 3; ++i) {
for (j = 0; j < 3; ++j) {
the_amplitude = gConcussion.amplitudes.m[i][j];
if (the_amplitude != 0.0) {
mod_angle = fmodf(time_difference / gConcussion.periods.m[i][j], TAU);
if (mod_angle > DR_3PI_OVER_2) {
cosine_over_angle = gCosine_array[(unsigned int)((TAU - mod_angle) / DR_PI * 128.f)];
} else if (mod_angle > DR_PI) {
cosine_over_angle = -gCosine_array[(unsigned int)((mod_angle - DR_PI) / DR_PI * 128.f)];
} else if (mod_angle > DR_PI_OVER_2) {
cosine_over_angle = -gCosine_array[(unsigned int)((DR_PI - mod_angle) / DR_PI * 128.f)];
} else {
cosine_over_angle = gCosine_array[(unsigned int)(mod_angle / DR_PI * 128.f)];
}
angle = cosine_over_angle / ((double)time_difference * 0.02f + 1.0f);
gCamera->t.t.mat.m[i][j] = angle * the_amplitude + gCamera->t.t.mat.m[i][j];
gRearview_camera->t.t.mat.m[i][j] = angle * the_amplitude + gRearview_camera->t.t.mat.m[i][j];
}
}
}
}
}
// IDA: void __cdecl SufferFromConcussion(float pSeriousness)
@ -817,7 +878,15 @@ void SufferFromConcussion(float pSeriousness) {
int i;
int j;
LOG_TRACE("(%f)", pSeriousness);
NOT_IMPLEMENTED();
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
gConcussion.amplitudes.m[i][j] = FRandomPosNeg(pSeriousness);
gConcussion.periods.m[i][j] = FRandomBetween(20.f, 100.f);
}
}
gConcussion.concussed = 1;
gConcussion.time_started = GetTotalTime();
}
// IDA: void __usercall ProcessNonTrackActors(br_pixelmap *pRender_buffer@<EAX>, br_pixelmap *pDepth_buffer@<EDX>, br_actor *pCamera@<EBX>, br_matrix34 *pCamera_to_world@<ECX>, br_matrix34 *pOld_camera_matrix)
@ -1525,23 +1594,19 @@ void RenderAFrame(int pDepth_mask_on) {
CalculateWobblitude(the_time);
}
if (cockpit_on) {
if (-gScreen_wobble_x <= gX_offset) {
if (gScreen_wobble_x + gX_offset + gRender_screen->width <= gBack_screen->width) {
x_shift = gScreen_wobble_x;
} else {
x_shift = gBack_screen->width - gRender_screen->width - gX_offset;
}
} else {
if (-gScreen_wobble_x > gX_offset) {
x_shift = -gX_offset;
}
if (-gScreen_wobble_y <= gY_offset) {
if (gScreen_wobble_y + gY_offset + gRender_screen->height <= gBack_screen->height) {
y_shift = gScreen_wobble_y;
} else {
y_shift = gBack_screen->height - gRender_screen->height - gY_offset;
}
} else if (gScreen_wobble_x + gX_offset + gRender_screen->width > gBack_screen->width) {
x_shift = gBack_screen->width - gRender_screen->width - gX_offset;
} else {
x_shift = gScreen_wobble_x;
}
if (-gScreen_wobble_y > gY_offset) {
y_shift = -gY_offset;
} else if (gScreen_wobble_y + gY_offset + gRender_screen->height > gBack_screen->height) {
y_shift = gBack_screen->height - gRender_screen->height - gY_offset;
} else {
y_shift = gScreen_wobble_y;
}
} else {
x_shift = 0;
@ -1552,13 +1617,11 @@ void RenderAFrame(int pDepth_mask_on) {
BrMatrix34Copy(&old_mirror_cam_matrix, &gRearview_camera->t.t.mat);
}
if (cockpit_on) {
gSheer_mat.m[2][1] = (double)y_shift / (double)gRender_screen->height;
gSheer_mat.m[2][0] = (double)-x_shift / (double)gRender_screen->width;
gSheer_mat.m[2][1] = y_shift / (float)gRender_screen->height;
gSheer_mat.m[2][0] = -x_shift / (float)gRender_screen->width;
BrMatrix34Pre(&gCamera->t.t.mat, &gSheer_mat);
gCamera->t.t.mat.m[3][0] = gCamera->t.t.mat.m[3][0]
- (double)gScreen_wobble_x * 1.5 / (double)gRender_screen->width / 6.9000001;
gCamera->t.t.mat.m[3][1] = (double)gScreen_wobble_y * 1.5 / (double)gRender_screen->width / 6.9000001
+ gCamera->t.t.mat.m[3][1];
gCamera->t.t.translate.t.v[0] -= gScreen_wobble_x * 1.5f / gRender_screen->width / WORLD_SCALE;
gCamera->t.t.translate.t.v[1] += gScreen_wobble_y * 1.5f / gRender_screen->width / WORLD_SCALE;
}
gRender_screen->pixels = (char*)gRender_screen->pixels + x_shift + y_shift * gRender_screen->row_bytes;
CalculateConcussion(the_time);

View File

@ -842,7 +842,7 @@ tS8* ConvertPixToStripMap(br_pixelmap* pThe_br_map) {
temp_strip_image = BrMemAllocate(pThe_br_map->row_bytes * pThe_br_map->height, kMem_strip_image);
current_size = 2;
*(br_uint_16 *)temp_strip_image = pThe_br_map->height;
*(br_uint_16*)temp_strip_image = pThe_br_map->height;
current_strip_pointer = temp_strip_image;
for (i = 0; i < pThe_br_map->height; i++) {
@ -1245,8 +1245,8 @@ void ReadNonCarMechanicsData(FILE* pF, tNon_car_spec* non_car) {
GetThreeFloats(pF, &len, &wid, &het);
snap_angle = GetAFloat(pF);
non_car->snap_off_cosine = cosf(snap_angle * ONEEIGHTTWO * 0.00009587379924285257);
non_car->collision_info.break_off_radians_squared = snap_angle * 3.14 / 180.0 * (snap_angle * 3.14 / 180.0);
non_car->snap_off_cosine = cosf(BrAngleToRadian(BrDegreeToAngle(snap_angle)));
non_car->collision_info.break_off_radians_squared = snap_angle * 3.14f / 180.f * (snap_angle * 3.14f / 180.f);
ts = GetAFloat(pF);
non_car->min_torque_squared = ts * ts;
@ -1687,7 +1687,7 @@ void MungeWindscreen(br_model* pModel) {
void SetModelFlags(br_model* pModel, int pOwner) {
LOG_TRACE("(%p, %d)", pModel, pOwner);
if (pModel != NULL&& pModel->nfaces != 0) {
if (pModel != NULL && pModel->nfaces != 0) {
#if defined(DETHRACE_FIX_BUGS) /* Show Squad Car in the wreck gallery. */
if (gAusterity_mode) {
#else
@ -2224,11 +2224,11 @@ void LoadCar(char* pCar_name, tDriver pDriver, tCar_spec* pCar_spec, int pOwner,
GetALineAndDontArgue(f, s);
str = strtok(s, "\t ,/");
sscanf(str, "%f", &temp_float);
pCar_spec->driven_wheels_circum = temp_float * 2.0 * 3.141592653589793;
pCar_spec->driven_wheels_circum = temp_float * 2.f * DR_PI;
GetALineAndDontArgue(f, s);
str = strtok(s, "\t ,/");
sscanf(str, "%f", &temp_float);
pCar_spec->non_driven_wheels_circum = temp_float * 2.0 * 3.141592653589793;
pCar_spec->non_driven_wheels_circum = temp_float * 2.f * DR_PI;
pCar_spec->car_model_variable = pDriver != eDriver_local_human;
PossibleService();
GetALineAndDontArgue(f, s);
@ -2299,14 +2299,14 @@ void LoadCar(char* pCar_name, tDriver pDriver, tCar_spec* pCar_spec, int pOwner,
fclose(g);
#if DETHRACE_FIX_BUGS
#define CHECK_BINDING_INDEX(IDX) \
do { \
if ((IDX) >= 0) { \
if (IDX >= COUNT_OF(gGroove_funk_bindings) || gGroove_funk_bindings[IDX] == NULL) { \
LOG_WARN("Disabling invalid groove binding for " #IDX "=%d (%d)", IDX, IDX-gGroove_funk_offset); \
IDX = -1; \
} \
} \
#define CHECK_BINDING_INDEX(IDX) \
do { \
if ((IDX) >= 0) { \
if (IDX >= COUNT_OF(gGroove_funk_bindings) || gGroove_funk_bindings[IDX] == NULL) { \
LOG_WARN("Disabling invalid groove binding for " #IDX "=%d (%d)", IDX, IDX - gGroove_funk_offset); \
IDX = -1; \
} \
} \
} while (0)
for (i = 0; i < pCar_spec->number_of_steerable_wheels; i++) {
CHECK_BINDING_INDEX(pCar_spec->steering_ref[i]);

View File

@ -485,15 +485,13 @@ enum {
#define NONCAR_UNUSED_SLOTS 5
#define ONEEIGHTTWO 182.0444444444444
#define d180_OVER_PI 57.29577951308232 // (180 / PI)
#define DR_PI 3.141592653589793
#define DR_PI_OVER_2 1.570796326794897
#define DR_3PI_OVER_2 4.71238898038469
#define TIME_CONV_THING 0.0005f
#define OPPONENT_COUNT 5
#define OPPONENT_COUNT 0
#define WORLD_SCALE 6.9f