Puppycam raycasts moved to engine segment

Also no longer need puppycam enabled to use.
This commit is contained in:
Fazana
2021-08-24 13:53:04 +01:00
parent 710256e9f1
commit 435e8c74fa
5 changed files with 241 additions and 243 deletions

View File

@@ -6,9 +6,14 @@
#include "surface_collision.h"
#include "extended_bounds.h"
#include "trig_tables.inc.c"
#include "surface_load.h"
#include "game/puppyprint.h"
#include "config.h"
#define RAY_OFFSET 30.0f /*How many units to extrapolate surfaces when testing for a raycast*/
#define RAY_STEPS 4 /*How many steps to do when casting rays, default to quartersteps.*/
// Variables for a spline curve animation (used for the flight path in the grand star cutscene)
Vec4s *gSplineKeyframe;
float gSplineKeyframeFraction;
@@ -874,3 +879,231 @@ s32 anim_spline_poll(Vec3f result) {
return hasEnded;
}
/// Multiply vector 'dest' by a
void *vec3f_mul(Vec3f dest, f32 a)
{
dest[0] *= a;
dest[1] *= a;
dest[2] *= a;
return dest; //! warning: function returns address of local variable
}
/// Get length of vector 'a'
f32 vec3f_length(Vec3f a)
{
return sqrtf(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
}
/// Get dot product of vectors 'a' and 'b'
f32 vec3f_dot(Vec3f a, Vec3f b)
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
/// Make 'dest' the difference of vectors a and b.
void *vec3f_dif(Vec3f dest, Vec3f a, Vec3f b) {
dest[0] = a[0] - b[0];
dest[1] = a[1] - b[1];
dest[2] = a[2] - b[2];
return dest; //! warning: function returns address of local variable
}
//Raycasting
s32 ray_surface_intersect(Vec3f orig, Vec3f dir, f32 dir_length, struct Surface *surface, Vec3f hit_pos, f32 *length)
{
Vec3f v0, v1, v2, e1, e2, h, s, q;
f32 a, f, u, v;
Vec3f add_dir;
Vec3f norm;
//Ignore certain surface types.
if (surface->type == SURFACE_INTANGIBLE || surface->flags & SURFACE_FLAG_NO_CAM_COLLISION)
return FALSE;
// Get surface normal and some other stuff
norm[0] = 0;
norm[1] = surface->normal.y;
norm[2] = 0;
vec3f_mul(norm,RAY_OFFSET);
vec3s_to_vec3f(v0, surface->vertex1);
vec3s_to_vec3f(v1, surface->vertex2);
vec3s_to_vec3f(v2, surface->vertex3);
vec3f_add(v0, norm);
vec3f_add(v1, norm);
vec3f_add(v2, norm);
vec3f_dif(e1, v1, v0);
vec3f_dif(e2, v2, v0);
vec3f_cross(h, dir, e2);
// Check if we're perpendicular from the surface
a = vec3f_dot(e1, h);
if (a > -0.00001f && a < 0.00001f)
return FALSE;
// Check if we're making contact with the surface
f = 1.0f / a;
vec3f_dif(s, orig, v0);
u = f * vec3f_dot(s, h);
if (u < 0.0f || u > 1.0f)
return FALSE;
vec3f_cross(q, s, e1);
v = f * vec3f_dot(dir, q);
if (v < 0.0f || u + v > 1.0f)
return FALSE;
// Get the length between our origin and the surface contact point
*length = f * vec3f_dot(e2, q);
if (*length <= 0.00001 || *length > dir_length)
return FALSE;
// Successful contact
vec3f_copy(add_dir, dir);
vec3f_mul(add_dir, *length);
vec3f_sum(hit_pos, orig, add_dir);
return TRUE;
}
void find_surface_on_ray_list(struct SurfaceNode *list, Vec3f orig, Vec3f dir, f32 dir_length, struct Surface **hit_surface, Vec3f hit_pos, f32 *max_length)
{
s32 hit;
f32 length;
Vec3f chk_hit_pos;
f32 top, bottom;
#ifdef PUPPYPRINT
OSTime first = osGetTime();
#endif
// Get upper and lower bounds of ray
if (dir[1] >= 0.0f)
{
top = orig[1] + dir[1] * dir_length;
bottom = orig[1];
}
else
{
top = orig[1];
bottom = orig[1] + dir[1] * dir_length;
}
// Iterate through every surface of the list
for (; list != NULL; list = list->next)
{
// Reject surface if out of vertical bounds
if (list->surface->lowerY > top || list->surface->upperY < bottom)
continue;
// Check intersection between the ray and this surface
if ((hit = ray_surface_intersect(orig, dir, dir_length, list->surface, chk_hit_pos, &length)) != 0)
{
if (length <= *max_length)
{
*hit_surface = list->surface;
vec3f_copy(hit_pos, chk_hit_pos);
*max_length = length;
}
}
}
#ifdef PUPPYPRINT
collisionTime[perfIteration] += osGetTime()-first;
#endif
}
void find_surface_on_ray_cell(s16 cellX, s16 cellZ, Vec3f orig, Vec3f normalized_dir, f32 dir_length, struct Surface **hit_surface, Vec3f hit_pos, f32 *max_length, s32 flags)
{
// Skip if OOB
if (cellX >= 0 && cellX <= (NUM_CELLS - 1) && cellZ >= 0 && cellZ <= (NUM_CELLS - 1))
{
// Iterate through each surface in this partition
if (normalized_dir[1] > -0.99999f && flags & RAYCAST_FIND_CEIL)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
if (normalized_dir[1] < 0.99999f && flags & RAYCAST_FIND_FLOOR)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
if (flags & RAYCAST_FIND_WALL)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
if (flags & RAYCAST_FIND_WATER)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
}
}
void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos, s32 flags)
{
f32 max_length;
s32 cellZ, cellX, cellPrevX, cellPrevZ;
f32 fCellZ, fCellX;
f32 dir_length;
Vec3f normalized_dir;
f32 step, dx, dz;
s32 i;
// Set that no surface has been hit
*hit_surface = NULL;
vec3f_sum(hit_pos, orig, dir);
// Get normalized direction
dir_length = vec3f_length(dir);
max_length = dir_length;
vec3f_copy(normalized_dir, dir);
vec3f_normalize(normalized_dir);
// Get our cell coordinate
fCellX = (orig[0] + LEVEL_BOUNDARY_MAX) / CELL_SIZE;
fCellZ = (orig[2] + LEVEL_BOUNDARY_MAX) / CELL_SIZE;
cellX = fCellX;
cellZ = fCellZ;
cellPrevX = cellX;
cellPrevZ = cellZ;
// Don't do DDA if straight down
if (normalized_dir[1] >= 0.99999f || normalized_dir[1] <= -0.99999f)
{
find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
return;
}
// Get cells we cross using DDA
if (ABS(dir[0]) >= ABS(dir[2]))
step = RAY_STEPS*ABS(dir[0]) / CELL_SIZE;
else
step = RAY_STEPS*ABS(dir[2]) / CELL_SIZE;
dx = dir[0] / step / CELL_SIZE;
dz = dir[2] / step / CELL_SIZE;
for (i = 0; i < step && *hit_surface == NULL; i++)
{
find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
// Move cell coordinate
fCellX += dx;
fCellZ += dz;
cellPrevX = cellX;
cellPrevZ = cellZ;
cellX = fCellX;
cellZ = fCellZ;
if ((cellPrevX != cellX) && (cellPrevZ != cellZ))
{
find_surface_on_ray_cell(cellX, cellPrevZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
find_surface_on_ray_cell(cellPrevX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
}
}
}

View File

@@ -32,9 +32,16 @@ extern f32 gCosineTable[];
#define min(a, b) ((a) <= (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
#define ABS(x) ((x) > 0.f ? (x) : -(x))
#define sqr(x) ((x) * (x))
#define RAYCAST_FIND_FLOOR (0x1)
#define RAYCAST_FIND_WALL (0x2)
#define RAYCAST_FIND_CEIL (0x4)
#define RAYCAST_FIND_WATER (0x8)
#define RAYCAST_FIND_ALL (0xFFFFFFFF)
void *vec3f_copy(Vec3f dest, Vec3f src);
void *vec3f_set(Vec3f dest, f32 x, f32 y, f32 z);
void *vec3f_add(Vec3f dest, Vec3f a);
@@ -73,5 +80,6 @@ f32 atan2f(f32 a, f32 b);
void spline_get_weights(Vec4f result, f32 t, UNUSED s32 c);
void anim_spline_init(Vec4s *keyFrames);
s32 anim_spline_poll(Vec3f result);
extern void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos, s32 flags);
#endif // MATH_UTIL_H

View File

@@ -17,7 +17,6 @@
* @see camera.c
*/
#define ABS(x) ((x) > 0.f ? (x) : -(x))
#define ABS2(x) ((x) >= 0.f ? (x) : -(x))
/**

View File

@@ -27,8 +27,6 @@
#ifdef PUPPYCAM
#define OFFSET 30.0f
#define STEPS 4
#define DECELERATION 0.66f
#define DEADZONE 20
#define SCRIPT_MEMORY_POOL 0x1000
@@ -901,234 +899,6 @@ void puppycam_terrain_angle(void)
gPuppyCam.terrainPitch = approach_f32_asymptotic(gPuppyCam.terrainPitch, gPuppyCam.intendedTerrainPitch, adjustSpeed);
}
/// Multiply vector 'dest' by a
void *vec3f_mul(Vec3f dest, f32 a)
{
dest[0] *= a;
dest[1] *= a;
dest[2] *= a;
return dest; //! warning: function returns address of local variable
}
/// Get length of vector 'a'
f32 vec3f_length(Vec3f a)
{
return sqrtf(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
}
/// Get dot product of vectors 'a' and 'b'
f32 vec3f_dot(Vec3f a, Vec3f b)
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
/// Make 'dest' the difference of vectors a and b.
void *vec3f_dif(Vec3f dest, Vec3f a, Vec3f b) {
dest[0] = a[0] - b[0];
dest[1] = a[1] - b[1];
dest[2] = a[2] - b[2];
return dest; //! warning: function returns address of local variable
}
//Raycasting
s32 ray_surface_intersect(Vec3f orig, Vec3f dir, f32 dir_length, struct Surface *surface, Vec3f hit_pos, f32 *length)
{
Vec3f v0, v1, v2, e1, e2, h, s, q;
f32 a, f, u, v;
Vec3f add_dir;
Vec3f norm;
//Ignore certain surface types.
if (surface->type == SURFACE_INTANGIBLE || surface->flags & SURFACE_FLAG_NO_CAM_COLLISION)
return FALSE;
// Get surface normal and some other stuff
norm[0] = 0;
norm[1] = surface->normal.y;
norm[2] = 0;
vec3f_mul(norm,OFFSET);
vec3s_to_vec3f(v0, surface->vertex1);
vec3s_to_vec3f(v1, surface->vertex2);
vec3s_to_vec3f(v2, surface->vertex3);
vec3f_add(v0, norm);
vec3f_add(v1, norm);
vec3f_add(v2, norm);
vec3f_dif(e1, v1, v0);
vec3f_dif(e2, v2, v0);
vec3f_cross(h, dir, e2);
// Check if we're perpendicular from the surface
a = vec3f_dot(e1, h);
if (a > -0.00001f && a < 0.00001f)
return FALSE;
// Check if we're making contact with the surface
f = 1.0f / a;
vec3f_dif(s, orig, v0);
u = f * vec3f_dot(s, h);
if (u < 0.0f || u > 1.0f)
return FALSE;
vec3f_cross(q, s, e1);
v = f * vec3f_dot(dir, q);
if (v < 0.0f || u + v > 1.0f)
return FALSE;
// Get the length between our origin and the surface contact point
*length = f * vec3f_dot(e2, q);
if (*length <= 0.00001 || *length > dir_length)
return FALSE;
// Successful contact
vec3f_copy(add_dir, dir);
vec3f_mul(add_dir, *length);
vec3f_sum(hit_pos, orig, add_dir);
return TRUE;
}
void find_surface_on_ray_list(struct SurfaceNode *list, Vec3f orig, Vec3f dir, f32 dir_length, struct Surface **hit_surface, Vec3f hit_pos, f32 *max_length)
{
s32 hit;
f32 length;
Vec3f chk_hit_pos;
f32 top, bottom;
#ifdef PUPPYPRINT
OSTime first = osGetTime();
#endif
// Get upper and lower bounds of ray
if (dir[1] >= 0.0f)
{
top = orig[1] + dir[1] * dir_length;
bottom = orig[1];
}
else
{
top = orig[1];
bottom = orig[1] + dir[1] * dir_length;
}
// Iterate through every surface of the list
for (; list != NULL; list = list->next)
{
// Reject surface if out of vertical bounds
if (list->surface->lowerY > top || list->surface->upperY < bottom)
continue;
// Check intersection between the ray and this surface
if ((hit = ray_surface_intersect(orig, dir, dir_length, list->surface, chk_hit_pos, &length)) != 0)
{
if (length <= *max_length)
{
*hit_surface = list->surface;
vec3f_copy(hit_pos, chk_hit_pos);
*max_length = length;
}
}
}
#ifdef PUPPYPRINT
collisionTime[perfIteration] += osGetTime()-first;
#endif
}
void find_surface_on_ray_cell(s16 cellX, s16 cellZ, Vec3f orig, Vec3f normalized_dir, f32 dir_length, struct Surface **hit_surface, Vec3f hit_pos, f32 *max_length, s32 flags)
{
// Skip if OOB
if (cellX >= 0 && cellX <= (NUM_CELLS - 1) && cellZ >= 0 && cellZ <= (NUM_CELLS - 1))
{
// Iterate through each surface in this partition
if (normalized_dir[1] > -0.99999f && flags & RAYCAST_FIND_CEIL)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
if (normalized_dir[1] < 0.99999f && flags & RAYCAST_FIND_FLOOR)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
if (flags & RAYCAST_FIND_WALL)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
if (flags & RAYCAST_FIND_WATER)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
}
}
void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos, s32 flags)
{
f32 max_length;
s32 cellZ, cellX, cellPrevX, cellPrevZ;
f32 fCellZ, fCellX;
f32 dir_length;
Vec3f normalized_dir;
f32 step, dx, dz;
s32 i;
// Set that no surface has been hit
*hit_surface = NULL;
vec3f_sum(hit_pos, orig, dir);
// Get normalized direction
dir_length = vec3f_length(dir);
max_length = dir_length;
vec3f_copy(normalized_dir, dir);
vec3f_normalize(normalized_dir);
// Get our cell coordinate
fCellX = (orig[0] + LEVEL_BOUNDARY_MAX) / CELL_SIZE;
fCellZ = (orig[2] + LEVEL_BOUNDARY_MAX) / CELL_SIZE;
cellX = fCellX;
cellZ = fCellZ;
cellPrevX = cellX;
cellPrevZ = cellZ;
// Don't do DDA if straight down
if (normalized_dir[1] >= 0.99999f || normalized_dir[1] <= -0.99999f)
{
find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
return;
}
// Get cells we cross using DDA
if (ABS(dir[0]) >= ABS(dir[2]))
step = STEPS*ABS(dir[0]) / CELL_SIZE;
else
step = STEPS*ABS(dir[2]) / CELL_SIZE;
dx = dir[0] / step / CELL_SIZE;
dz = dir[2] / step / CELL_SIZE;
for (i = 0; i < step && *hit_surface == NULL; i++)
{
find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
// Move cell coordinate
fCellX += dx;
fCellZ += dz;
cellPrevX = cellX;
cellPrevZ = cellZ;
cellX = fCellX;
cellZ = fCellZ;
if ((cellPrevX != cellX) && (cellPrevZ != cellZ))
{
find_surface_on_ray_cell(cellX, cellPrevZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
find_surface_on_ray_cell(cellPrevX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
}
}
}
const struct sPuppyAngles puppyAnglesNull =
{
{PUPPY_NULL, PUPPY_NULL, PUPPY_NULL},

View File

@@ -25,13 +25,6 @@
#define PUPPYCAM_MODE3_ZOOMED_OUT 0x4
#define PUPPYCAM_MODE3_ENTER_FIRST_PERSON 0x8
#define RAYCAST_FIND_FLOOR (0x1)
#define RAYCAST_FIND_WALL (0x2)
#define RAYCAST_FIND_CEIL (0x4)
#define RAYCAST_FIND_WATER (0x8)
#define RAYCAST_FIND_ALL (0xFFFFFFFF)
#include "include/command_macros_base.h"
#define PUPPYVOLUME(x, y, z, length, height, width, yaw, functionptr, anglesptr, addflags, removeflags, flagpersistance, room, shape) \
@@ -43,10 +36,6 @@
CMD_W(removeflags), \
CMD_BBH(flagpersistance, shape, room)
//Some macros for the sake of basic human sanity.
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
#define ABS(x) ((x) > 0.f ? (x) : -(x))
struct gPuppyOptions
{
s16 analogue;
@@ -174,7 +163,6 @@ extern void puppycam_boot(void);
extern void puppycam_init(void);
extern void puppycam_loop(void);
extern void puppycam_shake(s16 x, s16 y, s16 z);
extern void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos, s32 flags);
extern f32 approach_f32_asymptotic(f32 current, f32 target, f32 multiplier);
extern void puppycam_default_config(void);
extern s16 LENCOS(s16 length, s16 direction);