Files
Descent3/physics/newstyle_fi.cpp
Kevin Bentley df209742fc Initial import
2024-04-15 21:43:29 -06:00

476 lines
12 KiB
C++

#include "pserror.h"
#include "pstypes.h"
#include "vecmat.h"
#include "polymodel.h"
#include "findintersection.h"
#include "game.h"
#include <stdlib.h>
#include <search.h>
#include <string.h>
#ifndef NED_PHYSICS
#include "multi.h"
#endif
extern matrix View_matrix;
extern vector View_position;
vector Original_pos;
matrix Original_orient;
vector fvi_move_fvec;
vector fvi_move_uvec;
bool fvi_do_orient;
bool Fvi_f_normal;
#define MAX_INSTANCE_DEPTH 30
struct instance_context {
matrix m;
vector p;
vector p0;
vector p1;
vector fvec;
vector uvec;
};
static struct instance_context instance_stack[MAX_INSTANCE_DEPTH];
static int instance_depth = 0;
static void BuildModelAngleMatrix( matrix *mat, angle ang,vector *axis)
{
float x,y,z;
float s,c,t;
x = axis->x;
y = axis->y;
z = axis->z;
s = (float)FixSin(ang);
c = (float)FixCos(ang);
t = 1.0f - c;
mat->rvec.x = t*x*x + c;
mat->rvec.y = t*x*y + s*z;
mat->rvec.z = t*x*z - s*y;
mat->uvec.x = t*x*y - s*z;
mat->uvec.y = t*y*y + c;
mat->uvec.z = t*y*z + s*x;
mat->fvec.x = t*x*z + s*y;
mat->fvec.y = t*y*z - s*x;
mat->fvec.z = t*z*z + c;
}
////rotates a point. returns codes. does not check if already rotated
//static inline void collide_RotatePoint(g3Point *dest,vector *src)
//{
// vector tempv;
//
// tempv = *src - View_position;
//
// dest->p3_vec = tempv * View_matrix;
//
//}
float fvi_hit_param;
bool fvi_check_param;
static vector ns_min_xyz;
static vector ns_max_xyz;
inline void ns_compute_movement_AABB(void)
{
vector delta_movement = *fvi_query_ptr->p1 - *fvi_query_ptr->p0;
vector offset_vec;
offset_vec.x = fvi_query_ptr->rad;
offset_vec.y = fvi_query_ptr->rad;
offset_vec.z = fvi_query_ptr->rad;
ns_min_xyz = ns_max_xyz = *fvi_query_ptr->p0;
ns_min_xyz -= offset_vec;
ns_max_xyz += offset_vec;
if(delta_movement.x > 0.0f)
ns_max_xyz.x += delta_movement.x;
else
ns_min_xyz.x += delta_movement.x;
if(delta_movement.y > 0.0f)
ns_max_xyz.y += delta_movement.y;
else
ns_min_xyz.y += delta_movement.y;
if(delta_movement.z > 0.0f)
ns_max_xyz.z += delta_movement.z;
else
ns_min_xyz.z += delta_movement.z;
}
inline bool ns_movement_manual_AABB(vector *min_xyz, vector *max_xyz)
{
bool overlap = true;
if(max_xyz->y < ns_min_xyz.y ||
ns_max_xyz.y < min_xyz->y ||
max_xyz->x < ns_min_xyz.x ||
ns_max_xyz.x < min_xyz->x ||
max_xyz->z < ns_min_xyz.z ||
ns_max_xyz.z < min_xyz->z) overlap = false;
return overlap;
}
//collide with a submodel
//Parameters: nv - the number of verts in the poly
// pointlist - a pointer to a list of pointers to points
// bm - the bitmap handle if texturing. ignored if flat shading
static void CollideSubmodelFacesUnsorted (poly_model *pm,bsp_info *sm)
{
int i;
int j;
vector colp;
vector newp;
float col_dist; // distance to hit point
vector *vertex_list[32];
vector wall_norm;
int face_hit_type;
// (For this reference frame)
ns_compute_movement_AABB();
if(ns_movement_manual_AABB(&sm->min, &sm->max))
{
for (i=0;i<sm->num_faces;i++)
{
if(ns_movement_manual_AABB(&sm->face_min[i], &sm->face_max[i]))
{
polyface *fp=&sm->faces[i];
if ((GameTextures[pm->textures[fp->texnum]].flags & (TF_FLY_THRU | TF_PASS_THRU)) == 0)
{
ASSERT(fp->nverts <= 32);
for (j=0;j<fp->nverts;j++)
{
vertex_list[j] = &sm->verts[fp->vertnums[j]];
}
face_hit_type = check_line_to_face(&newp, &colp, &col_dist, &wall_norm, fvi_query_ptr->p0, fvi_query_ptr->p1, &fp->normal, vertex_list, fp->nverts, fvi_query_ptr->rad);
if ((fvi_query_ptr->flags & FQ_OBJ_BACKFACE) && (!face_hit_type))
{
vector face_normal = fp->normal;
int count;
face_normal *= -1.0f;
for (count = 0; count < fp->nverts; count++)
{
vertex_list[fp->nverts - count - 1] = &sm->verts[fp->vertnums[count]];
}
face_hit_type = check_line_to_face(&newp, &colp, &col_dist, &wall_norm, fvi_query_ptr->p0, fvi_query_ptr->p1, &face_normal, vertex_list, fp->nverts, fvi_query_ptr->rad);
}
if(face_hit_type)
{
if (col_dist < fvi_collision_dist)
{
vector x;
fvi_check_param = true;
x = *fvi_query_ptr->p1 - *fvi_query_ptr->p0;
vm_NormalizeVector(&x);
fvi_hit_param = (newp - *fvi_query_ptr->p0) * x;
if(!(fvi_hit_param > -10000000.0 && fvi_hit_param < 10000000.0))
{
mprintf((0, "FVI Warning: fvi_hit_param seems yucky!\n"));
}
fvi_collision_dist = col_dist;
fvi_hit_data_ptr->num_hits = 1;
fvi_hit_data_ptr->hit_object[0] = fvi_curobj;
fvi_hit_data_ptr->hit_subobject[0] = sm - pm->submodel;
fvi_hit_data_ptr->hit_type[0] = HIT_SPHERE_2_POLY_OBJECT;
fvi_hit_data_ptr->hit_wallnorm[0] = wall_norm;
fvi_hit_data_ptr->hit_face_pnt[0] = colp;
fvi_hit_data_ptr->hit_face[0] = i;
Fvi_f_normal = true;
if(fvi_do_orient)
{
fvi_hit_data_ptr->hit_subobj_fvec = fvi_move_fvec;
fvi_hit_data_ptr->hit_subobj_uvec = fvi_move_uvec;
fvi_hit_data_ptr->hit_subobj_pos = newp;
}
}
}
}
}
}
}
}
//instance at specified point with specified orientation
//if matrix==NULL, don't modify matrix. This will be like doing an offset
void newstyle_StartInstanceMatrix(vector *pos,matrix *orient)
{
vector tempv, temp0, temp1;
matrix tempm,tempm2;
ASSERT(instance_depth<MAX_INSTANCE_DEPTH);
instance_stack[instance_depth].m = View_matrix;
instance_stack[instance_depth].p = View_position;
instance_stack[instance_depth].p0 = *fvi_query_ptr->p0;
instance_stack[instance_depth].p1 = *fvi_query_ptr->p1;
if(fvi_do_orient)
{
instance_stack[instance_depth].fvec = fvi_move_fvec;
instance_stack[instance_depth].uvec = fvi_move_uvec;
}
instance_depth++;
//step 1: subtract object position from view position
tempv = View_position - *pos;
temp0 = *fvi_query_ptr->p0 - *pos;
temp1 = *fvi_query_ptr->p1 - *pos;
if (orient)
{
//step 2: rotate view vector through object matrix
View_position = tempv * *orient;
*fvi_query_ptr->p0 = temp0 * *orient;
*fvi_query_ptr->p1 = temp1 * *orient;
if(fvi_do_orient)
{
fvi_move_fvec = fvi_move_fvec * *orient;
fvi_move_uvec = fvi_move_uvec * *orient;
}
//step 3: rotate object matrix through view_matrix (vm = ob * vm)
tempm2 = ~*orient;
tempm = tempm2 * View_matrix;
View_matrix = tempm;
}
}
//instance at specified point with specified orientation
//if angles==NULL, don't modify matrix. This will be like doing an offset
static void newstyle_StartInstanceAngles(vector *pos,angvec *angles)
{
matrix tm;
if (angles==NULL) {
newstyle_StartInstanceMatrix(pos,NULL);
return;
}
vm_AnglesToMatrix(&tm,angles->p,angles->h,angles->b);
newstyle_StartInstanceMatrix(pos,&tm);
}
//pops the old context
static void newstyle_DoneInstance()
{
instance_depth--;
ASSERT(instance_depth >= 0);
View_position = instance_stack[instance_depth].p;
View_matrix = instance_stack[instance_depth].m;
*fvi_query_ptr->p0 = instance_stack[instance_depth].p0;
*fvi_query_ptr->p1 = instance_stack[instance_depth].p1;
if(fvi_do_orient)
{
fvi_move_fvec = instance_stack[instance_depth].fvec;
fvi_move_uvec = instance_stack[instance_depth].uvec;
}
}
void CollideSubmodel (poly_model *pm,bsp_info *sm, uint f_render_sub)
{
// Don't collide with door housings (That is the 'room' portion of the door)
if ((sm->flags & SOF_SHELL) || (sm->flags & SOF_FRONTFACE))
return;
StartPolyModelPosInstance(&sm->mod_pos);
vector temp_vec=sm->mod_pos+sm->offset;
newstyle_StartInstanceAngles(&temp_vec,&sm->angs );
// Check my bit to see if I get collided with. :)
if(f_render_sub & (0x00000001 << (sm - pm->submodel))) CollideSubmodelFacesUnsorted (pm, sm);
for (int i=0;i<sm->num_children;i++)
{
CollideSubmodel(pm,&pm->submodel[sm->children[i]], f_render_sub);
}
newstyle_DoneInstance();
DonePolyModelPosInstance();
}
void CollidePolygonModel(vector *pos,matrix *orient,int model_num,float *normalized_time, uint f_render_sub)
{
poly_model *po;
ASSERT (Poly_models[model_num].used);
ASSERT (Poly_models[model_num].new_style);
fvi_check_param = false;
po=&Poly_models[model_num];
newstyle_StartInstanceMatrix(pos,orient);
SetModelAnglesAndPos (po,normalized_time);
for (int i=0;i<po->n_models;i++)
{
bsp_info *sm=&po->submodel[i];
if (sm->parent==-1)
CollideSubmodel (po, sm, f_render_sub);
}
newstyle_DoneInstance();
}
#define MULTI_ADD_SPHERE_MIN 1.4f
#define MULTI_ADD_SPHERE_MAX 2.5f
bool PolyCollideObject(object *obj)
{
#ifndef NED_PHYSICS
float normalized_time[MAX_SUBOBJECTS];
#endif
vector temp_pos = Original_pos = View_position;
matrix temp_orient = Original_orient = View_matrix;
bool f_use_big_sphere=false;
float addition;
ASSERT(obj >= Objects && obj <= &Objects[Highest_object_index]);
#ifndef NED_PHYSICS
if ((Game_mode & GM_MULTI) && !(Netgame.flags & NF_USE_ACC_WEAP) && Objects[fvi_moveobj].type == OBJ_WEAPON && obj->type == OBJ_PLAYER)
f_use_big_sphere=true;
#endif
fvi_do_orient = (Objects[fvi_moveobj].type == OBJ_WEAPON);
#ifndef NED_PHYSICS
if(f_use_big_sphere)
{
addition = fvi_query_ptr->rad;
if(addition < MULTI_ADD_SPHERE_MIN)
{
addition = MULTI_ADD_SPHERE_MIN;
if (Objects[fvi_moveobj].mtype.phys_info.flags & PF_NEVER_USE_BIG_SPHERE)
addition/=2;
}
else if(addition > MULTI_ADD_SPHERE_MAX)
addition = MULTI_ADD_SPHERE_MAX;
fvi_query_ptr->rad += addition;
}
#endif
if(fvi_do_orient)
{
fvi_move_fvec = Objects[fvi_moveobj].orient.fvec;
fvi_move_uvec = Objects[fvi_moveobj].orient.uvec;
}
Fvi_f_normal = false;
View_position = obj->pos;
View_matrix = obj->orient;
ASSERT(obj->flags & OF_POLYGON_OBJECT);
#ifndef NED_PHYSICS
if(obj->type == OBJ_PLAYER || obj->type == OBJ_ROBOT || obj->type == OBJ_DEBRIS || obj->type==OBJ_DOOR || obj->type == OBJ_BUILDING || obj->type == OBJ_CLUTTER || obj->type == OBJ_BUILDING)
{
SetNormalizedTimeObj(obj, normalized_time);
CollidePolygonModel (&obj->pos, &obj->orient, obj->rtype.pobj_info.model_num, normalized_time, obj->rtype.pobj_info.subobj_flags);
}
else
{
CollidePolygonModel (&obj->pos, &obj->orient, obj->rtype.pobj_info.model_num, NULL, obj->rtype.pobj_info.subobj_flags);
}
#else
CollidePolygonModel (&obj->pos, &obj->orient, obj->rtype.pobj_info.model_num, NULL, obj->rtype.pobj_info.subobj_flags);
#endif
View_position = temp_pos;
View_matrix = temp_orient;
// Converts everything into world coordinates from submodel space
if(fvi_check_param)
{
vector pnt = fvi_hit_data_ptr->hit_face_pnt[0];
int mn = fvi_hit_data_ptr->hit_subobject[0];
matrix m;
poly_model *pm = &Poly_models[obj->rtype.pobj_info.model_num];
while (mn != -1)
{
vector tpnt;
vm_AnglesToMatrix(&m, pm->submodel[mn].angs.p,pm->submodel[mn].angs.h, pm->submodel[mn].angs.b);
vm_TransposeMatrix(&m);
tpnt = pnt * m;
fvi_hit_data_ptr->hit_wallnorm[0] = fvi_hit_data_ptr->hit_wallnorm[0] * m;
pnt = tpnt + pm->submodel[mn].offset + pm->submodel[mn].mod_pos;
mn = pm->submodel[mn].parent;
}
fvi_hit_data_ptr->hit_face_pnt[0] = pnt;
m = obj->orient;
vm_TransposeMatrix(&m);
fvi_hit_data_ptr->hit_wallnorm[0] = fvi_hit_data_ptr->hit_wallnorm[0] * m;
//now instance for the entire object
fvi_hit_data_ptr->hit_face_pnt[0] = fvi_hit_data_ptr->hit_face_pnt[0] * m;
fvi_hit_data_ptr->hit_face_pnt[0] += obj->pos;
// Now get the hit point
vector x = *fvi_query_ptr->p1 - *fvi_query_ptr->p0;
vm_NormalizeVector(&x);
fvi_hit_data_ptr->hit_pnt = *fvi_query_ptr->p0 + x * fvi_hit_param;
}
if(f_use_big_sphere)
{
fvi_query_ptr->rad -= addition;
}
return Fvi_f_normal;
}