diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 209d8f668..a80f1ae8c 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -977,11 +977,14 @@ void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Ve return; } + // increase collision checking precision (normally 1) + f32 precision = 2; + // Get cells we cross using DDA if (absx(dir[0]) >= absx(dir[2])) - step = absx(dir[0]) / CELL_SIZE; + step = precision * absx(dir[0]) / CELL_SIZE; else - step = absx(dir[2]) / CELL_SIZE; + step = precision * absx(dir[2]) / CELL_SIZE; dx = dir[0] / step / CELL_SIZE; dz = dir[2] / step / CELL_SIZE; diff --git a/src/game/bettercamera.inc.h b/src/game/bettercamera.inc.h index 60c5b6a80..c15ce0c1c 100644 --- a/src/game/bettercamera.inc.h +++ b/src/game/bettercamera.inc.h @@ -16,6 +16,9 @@ #include #endif +#define NEW_CAM_BOUNDING_BOX_RAYS 4 +#define NEW_CAM_BOUNDING_BOX_HRADIUS 250 +#define NEW_CAM_BOUNDING_BOX_VRADIUS 50 /** Quick explanation of the camera modes @@ -473,6 +476,47 @@ static void newcam_update_values(void) { } } +static void newcam_bounding_box(void) { + Vec3f camdirs[NEW_CAM_BOUNDING_BOX_RAYS] = { 0 }; + Vec3f raypos[NEW_CAM_BOUNDING_BOX_RAYS] = { 0 }; + s16 antiYaw = newcam_yaw - 0x4000; + + // sideways ray 1 + camdirs[0][0] = coss(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS; + camdirs[0][2] = sins(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS; + + // sideways ray 2 + camdirs[1][0] = -coss(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS; + camdirs[1][2] = -sins(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS; + + // vertical rays + camdirs[2][1] = -NEW_CAM_BOUNDING_BOX_VRADIUS; + camdirs[3][1] = NEW_CAM_BOUNDING_BOX_VRADIUS; + + for (int i = 0; i < NEW_CAM_BOUNDING_BOX_RAYS; i++) { + struct Surface* surf; + Vec3f offset = { 0 }; + + Vec3f startpos = { 0 }; + vec3f_copy(startpos, newcam_pos); + vec3f_add(startpos, offset); + + find_surface_on_ray(startpos, camdirs[i], &surf, raypos[i]); + if (!surf) { + vec3f_copy(raypos[i], startpos); + vec3f_add(raypos[i], camdirs[i]); + } + } + + Vec3f avg = { 0 }; + for (int i = 0; i < NEW_CAM_BOUNDING_BOX_RAYS; i++) { + vec3f_add(avg, raypos[i]); + } + vec3f_mul(avg, 1.0f / ((f32)NEW_CAM_BOUNDING_BOX_RAYS)); + + vec3f_copy(newcam_pos, avg); +} + static void newcam_collision(void) { struct Surface *surf; Vec3f camdir; @@ -486,8 +530,16 @@ static void newcam_collision(void) { newcam_coldist = sqrtf((newcam_pos_target[0] - hitpos[0]) * (newcam_pos_target[0] - hitpos[0]) + (newcam_pos_target[1] - hitpos[1]) * (newcam_pos_target[1] - hitpos[1]) + (newcam_pos_target[2] - hitpos[2]) * (newcam_pos_target[2] - hitpos[2])); if (surf) { + // offset the hit pos by the hit normal + Vec3f offset = { 0 }; + offset[0] = surf->normal.x; + offset[1] = surf->normal.y; + offset[2] = surf->normal.z; + vec3f_mul(offset, 5.0f); + vec3f_add(hitpos, offset); + newcam_pos[0] = hitpos[0]; - newcam_pos[1] = approach_f32(hitpos[1],newcam_pos[1],25,-25); + newcam_pos[1] = hitpos[1]; newcam_pos[2] = hitpos[2]; newcam_pan_x = 0; newcam_pan_z = 0; @@ -541,8 +593,10 @@ static void newcam_position_cam(void) { if (newcam_modeflags & NC_FLAG_FOCUSZ) newcam_lookat[2] = newcam_pos_target[2]-newcam_pan_z; - if (newcam_modeflags & NC_FLAG_COLLISION) - newcam_collision(); + if (newcam_modeflags & NC_FLAG_COLLISION) { + newcam_collision(); + newcam_bounding_box(); + } }