void do_object_physics( object * obj ) { vms_angvec rotang; vms_vector frame_vec; //movement in this frame vms_vector new_pos,ipos; //position after this frame int iseg; int hit; vms_matrix rotmat,new_pm; int count=0; short joy_x,joy_y,btns; int joyx_moved,joyy_moved; fix speed; vms_vector *desired_upvec; fixang delta_ang,roll_ang; vms_vector forvec = {0,0,f1_0}; vms_matrix temp_matrix; //check keys rotang.pitch = ROT_SPEED * (key_down_time(KEY_UP) - key_down_time(KEY_DOWN)); rotang.head = ROT_SPEED * (key_down_time(KEY_RIGHT) - key_down_time(KEY_LEFT)); rotang.bank = 0; //check for joystick movement joy_get_pos(&joy_x,&joy_y); btns=joy_get_btns(); joyx_moved = (abs(joy_x - _old_joy_x)>JOY_NULL); joyy_moved = (abs(joy_y - _old_joy_y)>JOY_NULL); if (abs(joy_x) < JOY_NULL) joy_x = 0; if (abs(joy_y) < JOY_NULL) joy_y = 0; if (!rotang.pitch) rotang.pitch = fixmul(-joy_y * 128,FrameTime); if (!rotang.head) rotang.head = fixmul(joy_x * 128,FrameTime); if (joyx_moved) _old_joy_x = joy_x; if (joyy_moved) _old_joy_y = joy_y; speed = ((btns&2) || keyd_pressed[KEY_A])?SLOW_SPEED*3:(keyd_pressed[KEY_Z]?SLOW_SPEED/2:SLOW_SPEED); //now build matrices, do rotations, etc., etc. vm_angles_2_matrix(&rotmat,&rotang); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; //move player vm_vec_copy_scale(&obj->velocity,&obj->orient.fvec,speed); vm_vec_copy_scale(&frame_vec,&obj->velocity,FrameTime); do { fix wall_part; vms_vector tvec; count++; vm_vec_add(&new_pos,&obj->pos,&frame_vec); hit = find_vector_intersection(&ipos,&iseg,&obj->pos,obj->seg_id,&new_pos,obj->size,-1); obj->seg_id = iseg; obj->pos = ipos; //-FIXJOHN-if (hit==HIT_OBJECT) ExplodeObject(hit_objnum); if (hit==HIT_WALL) { vm_vec_sub(&frame_vec,&new_pos,&obj->pos); //part through wall wall_part = vm_vec_dot(wall_norm,&frame_vec); vm_vec_copy_scale(&tvec,wall_norm,wall_part); if ((wall_part == 0) || (vm_vec_mag(&tvec) < 5)) Int3(); vm_vec_sub2(&frame_vec,&tvec); } } while (hit == HIT_WALL); Assert(check_point_in_seg(&obj->pos,obj->seg_id,0).centermask==0); //now bank player according to segment orientation desired_upvec = &Segments[obj->seg_id].sides[3].faces[0].normal; if (labs(vm_vec_dot(desired_upvec,&obj->orient.fvec)) < f1_0/2) { vm_vector_2_matrix(&temp_matrix,&obj->orient.fvec,desired_upvec,NULL); delta_ang = vm_vec_delta_ang(&obj->orient.uvec,&temp_matrix.uvec,&obj->orient.fvec); if (rotang.head) delta_ang += (rotang.head<0)?TURNROLL_ANG:-TURNROLL_ANG; if (abs(delta_ang) > DAMP_ANG) { roll_ang = fixmul(FrameTime,ROLL_RATE); if (abs(delta_ang) < roll_ang) roll_ang = delta_ang; else if (delta_ang<0) roll_ang = -roll_ang; vm_vec_ang_2_matrix(&rotmat,&forvec,roll_ang); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; } } }
void generate_banked_curve(fix maxscale, vms_equation coeffs) { vms_vector vec_dir, tvec, b4r4t; vms_vector coord,prev_point; fix enddist, nextdist; int firstsegflag; fixang rangle, uangle, angle, scaled_ang=0; fix t; if (CurveNumSegs) { const vcsegptr_t cursegp = Cursegp; extract_up_vector_from_segment(cursegp, b4r4t); uangle = vm_vec_delta_ang( b4r4t, r4t, r4 ); if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; extract_right_vector_from_segment(cursegp, b4r4t); rangle = vm_vec_delta_ang( b4r4t, r4t, r4 ); if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; angle = uangle; if (abs(rangle) < abs(uangle)) angle = rangle; delete_curve(); coord = prev_point = p1; #define MAGIC_NUM 0.707*F1_0 if (maxscale) scaled_ang = fixdiv(angle,fixmul(maxscale,MAGIC_NUM)); t=0; tvec = r1save; firstsegflag = 1; enddist = F1_0; nextdist = 0; while ( enddist > fixmul( nextdist, 1.5*F1_0 )) { vms_matrix rotmat; if (firstsegflag==1) firstsegflag=0; else extract_forward_vector_from_segment(cursegp, tvec); nextdist = vm_vec_mag(tvec); // nextdist := distance to next point t = curve_dist(&coeffs, 3, t, prev_point, nextdist); // t = argument at which function is forward vector magnitude units away from prev_point (in 3-space, not along curve) coord = evaluate_curve(&coeffs, 3, t); // coord := point about forward vector magnitude units away from prev_point enddist = vm_vec_dist(coord, p4); // enddist := distance from current to end point, vec_dir used as a temporary variable //vm_vec_normalize(vm_vec_sub(&vec_dir, &coord, &prev_point)); vm_vec_normalized_dir(vec_dir, coord, prev_point); if (!med_attach_segment(Cursegp, vmsegptr(&New_segment), Curside, AttachSide)) { med_extract_matrix_from_segment(cursegp, &rotmat); // rotmat := matrix describing orientation of Cursegp const auto tdest = vm_vec_rotate(vec_dir,rotmat); // tdest := vec_dir in reference frame of Cursegp vec_dir = tdest; const auto rotmat2 = vm_vec_ang_2_matrix(vec_dir,scaled_ang); med_rotate_segment( Cursegp, rotmat2 ); prev_point = coord; Curside = Side_opposite[AttachSide]; CurveSegs[CurveNumSegs]=Cursegp; CurveNumSegs++; } } } }
void do_physics_align_object( object * obj ) { vms_vector desired_upvec; fixang delta_ang,roll_ang; //vms_vector forvec = {0,0,f1_0}; vms_matrix temp_matrix; fix d,largest_d=-f1_0; int i,best_side; best_side=0; // bank player according to segment orientation //find side of segment that player is most alligned with for (i=0;i<6;i++) { #ifdef COMPACT_SEGS vms_vector _tv1; get_side_normal( &Segments[obj->segnum], i, 0, &_tv1 ); d = vm_vec_dot(&_tv1,&obj->orient.uvec); #else d = vm_vec_dot(&Segments[obj->segnum].sides[i].normals[0],&obj->orient.uvec); #endif if (d > largest_d) {largest_d = d; best_side=i;} } if (floor_levelling) { // old way: used floor's normal as upvec #ifdef COMPACT_SEGS get_side_normal(&Segments[obj->segnum], 3, 0, &desired_upvec ); #else desired_upvec = Segments[obj->segnum].sides[3].normals[0]; #endif } else // new player leveling code: use normal of side closest to our up vec if (get_num_faces(&Segments[obj->segnum].sides[best_side])==2) { #ifdef COMPACT_SEGS vms_vector normals[2]; get_side_normals(&Segments[obj->segnum], best_side, &normals[0], &normals[1] ); desired_upvec.x = (normals[0].x + normals[1].x) / 2; desired_upvec.y = (normals[0].y + normals[1].y) / 2; desired_upvec.z = (normals[0].z + normals[1].z) / 2; vm_vec_normalize(&desired_upvec); #else side *s = &Segments[obj->segnum].sides[best_side]; desired_upvec.x = (s->normals[0].x + s->normals[1].x) / 2; desired_upvec.y = (s->normals[0].y + s->normals[1].y) / 2; desired_upvec.z = (s->normals[0].z + s->normals[1].z) / 2; vm_vec_normalize(&desired_upvec); #endif } else #ifdef COMPACT_SEGS get_side_normal(&Segments[obj->segnum], best_side, 0, &desired_upvec ); #else desired_upvec = Segments[obj->segnum].sides[best_side].normals[0]; #endif if (labs(vm_vec_dot(&desired_upvec,&obj->orient.fvec)) < f1_0/2) { vms_angvec tangles; vm_vector_2_matrix(&temp_matrix,&obj->orient.fvec,&desired_upvec,NULL); delta_ang = vm_vec_delta_ang(&obj->orient.uvec,&temp_matrix.uvec,&obj->orient.fvec); delta_ang += obj->mtype.phys_info.turnroll; if (abs(delta_ang) > DAMP_ANG) { vms_matrix rotmat, new_pm; roll_ang = fixmul(FrameTime,ROLL_RATE); if (abs(delta_ang) < roll_ang) roll_ang = delta_ang; else if (delta_ang<0) roll_ang = -roll_ang; tangles.p = tangles.h = 0; tangles.b = roll_ang; vm_angles_2_matrix(&rotmat,&tangles); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; } else floor_levelling=0; } }
int generate_curve( fix r1scale, fix r4scale ) { vms_vector vec_dir, tvec; vms_vector coord,prev_point; vms_equation coeffs; fix enddist, nextdist; int firstsegflag; fix t, maxscale; fixang rangle, uangle; const vcsegptr_t cursegp = Cursegp; compute_center_point_on_side(p1, cursegp, Curside); switch( Curside ) { case WLEFT: extract_right_vector_from_segment(cursegp, r1); vm_vec_scale(r1, -F1_0 ); break; case WTOP: extract_up_vector_from_segment(cursegp, r1); break; case WRIGHT: extract_right_vector_from_segment(cursegp, r1); break; case WBOTTOM: extract_up_vector_from_segment(cursegp, r1); vm_vec_scale(r1, -F1_0 ); break; case WBACK: extract_forward_vector_from_segment(cursegp, r1); break; case WFRONT: extract_forward_vector_from_segment(cursegp, r1); vm_vec_scale(r1, -F1_0 ); break; } const vcsegptr_t markedsegp = Markedsegp; compute_center_point_on_side(p4, markedsegp, Markedside); switch( Markedside ) { case WLEFT: extract_right_vector_from_segment(markedsegp, r4); extract_up_vector_from_segment(markedsegp, r4t); break; case WTOP: extract_up_vector_from_segment(markedsegp, r4); vm_vec_scale(r4, -F1_0 ); extract_forward_vector_from_segment(markedsegp, r4t); vm_vec_scale(r4t, -F1_0 ); break; case WRIGHT: extract_right_vector_from_segment(markedsegp, r4); vm_vec_scale(r4, -F1_0 ); extract_up_vector_from_segment(markedsegp, r4t); break; case WBOTTOM: extract_up_vector_from_segment(markedsegp, r4); extract_forward_vector_from_segment(markedsegp, r4t); break; case WBACK: extract_forward_vector_from_segment(markedsegp, r4); vm_vec_scale(r4, -F1_0 ); extract_up_vector_from_segment(markedsegp, r4t); break; case WFRONT: extract_forward_vector_from_segment(markedsegp, r4); extract_up_vector_from_segment(markedsegp, r4t); break; } r1save = r1; tvec = r1; vm_vec_scale(r1,r1scale); vm_vec_scale(r4,r4scale); create_curve( p1, p4, r1, r4, coeffs ); OriginalSeg = Cursegp; OriginalMarkedSeg = Markedsegp; OriginalSide = Curside; OriginalMarkedSide = Markedside; CurveNumSegs = 0; coord = prev_point = p1; t=0; firstsegflag = 1; enddist = F1_0; nextdist = 0; while ( enddist > fixmul( nextdist, 1.5*F1_0 )) { vms_matrix rotmat; if (firstsegflag==1) firstsegflag=0; else extract_forward_vector_from_segment(cursegp, tvec); nextdist = vm_vec_mag(tvec); // nextdist := distance to next point t = curve_dist(&coeffs, 3, t, prev_point, nextdist); // t = argument at which function is forward vector magnitude units away from prev_point (in 3-space, not along curve) coord = evaluate_curve(&coeffs, 3, t); // coord := point about forward vector magnitude units away from prev_point enddist = vm_vec_dist(coord, p4); // enddist := distance from current to end point, vec_dir used as a temporary variable //vm_vec_normalize(vm_vec_sub(&vec_dir, &coord, &prev_point)); vm_vec_normalized_dir(vec_dir, coord, prev_point); if (!med_attach_segment(Cursegp, vmsegptr(&New_segment), Curside, AttachSide)) { med_extract_matrix_from_segment(cursegp, &rotmat); // rotmat := matrix describing orientation of Cursegp const auto tdest = vm_vec_rotate(vec_dir,rotmat); // tdest := vec_dir in reference frame of Cursegp vec_dir = tdest; const auto rotmat2 = vm_vector_2_matrix(vec_dir,nullptr,nullptr); med_rotate_segment( Cursegp, rotmat2 ); prev_point = coord; Curside = Side_opposite[AttachSide]; CurveSegs[CurveNumSegs]=Cursegp; CurveNumSegs++; } else return 0; } extract_up_vector_from_segment(cursegp, tvec); uangle = vm_vec_delta_ang( tvec, r4t, r4 ); if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; extract_right_vector_from_segment(cursegp, tvec); rangle = vm_vec_delta_ang( tvec, r4t, r4 ); if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; if ((uangle != 0) && (rangle != 0)) { maxscale = CurveNumSegs*F1_0; generate_banked_curve(maxscale, coeffs); } if (CurveNumSegs) { med_form_bridge_segment( Cursegp, Side_opposite[AttachSide], Markedsegp, Markedside ); CurveSegs[CurveNumSegs] = vmsegptr(Markedsegp->children[Markedside]); CurveNumSegs++; } Cursegp = OriginalSeg; Curside = OriginalSide; med_create_new_segment_from_cursegp(); //warn_if_concave_segments(); if (CurveNumSegs) return 1; else return 0; }