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++; } } } }
// ------------------------------------------------------------------------------------- // Texture map current scanline in perspective. // ------------------------------------------------------------------------------------- void ntmap_scanline_lighted(grs_bitmap *srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix zleft, fix zright, fix lleft, fix lright) { fix dx,recip_dx; fx_xright = f2i(xright); //edited 06/27/99 Matt Mueller - moved these tests up from within the switch so as not to do a bunch of needless calculations when we are just gonna return anyway. Slight fps boost? if (fx_xright < Window_clip_left) return; fx_xleft = f2i(xleft); if (fx_xleft > Window_clip_right) return; //end edit -MM dx = fx_xright - fx_xleft; if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers return; // setup to call assembler scanline renderer if (dx < FIX_RECIP_TABLE_SIZE) recip_dx = fix_recip[dx]; else recip_dx = F1_0/dx; fx_u = uleft; fx_v = vleft; fx_z = zleft; fx_du_dx = fixmul(uright - uleft,recip_dx); fx_dv_dx = fixmul(vright - vleft,recip_dx); fx_dz_dx = fixmul(zright - zleft,recip_dx); fx_y = y; pixptr = srcb->bm_data; switch (Lighting_enabled) { case 0: //added 05/17/99 Matt Mueller - prevent writing before the buffer if ((fx_y == 0) && (fx_xleft < 0)) fx_xleft = 0; //end addition -MM if (fx_xright > Window_clip_right) fx_xright = Window_clip_right; cur_tmap_scanline_per(); break; case 1: { fix mul_thing; if (lleft < 0) lleft = 0; if (lright < 0) lright = 0; if (lleft > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lleft = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2); if (lright > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lright = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2); fx_l = lleft; fx_dl_dx = fixmul(lright - lleft,recip_dx); // This is a pretty ugly hack to prevent lighting overflows. mul_thing = dx * fx_dl_dx; if (lleft + mul_thing < 0) fx_dl_dx += 12; else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) fx_dl_dx -= 12; //added 05/17/99 Matt Mueller - prevent writing before the buffer if ((fx_y == 0) && (fx_xleft < 0)) fx_xleft = 0; //end addition -MM if (fx_xright > Window_clip_right) fx_xright = Window_clip_right; cur_tmap_scanline_per(); break; } case 2: #ifdef EDITOR_TMAP fx_xright = f2i(xright); fx_xleft = f2i(xleft); tmap_flat_color = 1; cur_tmap_scanline_flat(); #else Int3(); // Illegal, called an editor only routine! #endif break; } }
// ------------------------------------------------------------------------------------- // Texture map current scanline using linear interpolation. // ------------------------------------------------------------------------------------- void ntmap_scanline_lighted_linear(grs_bitmap *srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix lleft, fix lright) { fix u,v,l; fix dx,recip_dx; fix du_dx,dv_dx,dl_dx; u = uleft; v = vleft; l = lleft; dx = f2i(xright) - f2i(xleft); if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers return; // setup to call assembler scanline renderer if (dx < FIX_RECIP_TABLE_SIZE) recip_dx = fix_recip[dx]; else recip_dx = F1_0/dx; du_dx = fixmul(uright - uleft,recip_dx); dv_dx = fixmul(vright - vleft,recip_dx); fx_u = uleft; fx_v = vleft; fx_du_dx = du_dx; fx_dv_dx = dv_dx; fx_y = y; fx_xright = f2i(xright); fx_xleft = f2i(xleft); pixptr = srcb->bm_data; switch (Lighting_enabled) { case 0: //added 07/11/99 adb - prevent writing before the buffer if (fx_xleft < 0) fx_xleft = 0; //end addition -adb cur_tmap_scanline_lin_nolight(); break; case 1: if (lleft < F1_0/2) lleft = F1_0/2; if (lright < F1_0/2) lright = F1_0/2; if (lleft > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS) lleft = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS; if (lright > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS) lright = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS; //added 07/11/99 adb - prevent writing before the buffer if (fx_xleft < 0) fx_xleft = 0; //end addition -adb { fix mul_thing; fx_l = lleft; fx_dl_dx = fixmul(lright - lleft,recip_dx); // This is a pretty ugly hack to prevent lighting overflows. mul_thing = dx * fx_dl_dx; if (lleft + mul_thing < 0) fx_dl_dx += 12; else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) fx_dl_dx -= 12; } fx_l = lleft; dl_dx = fixmul(lright - lleft,recip_dx); fx_dl_dx = dl_dx; cur_tmap_scanline_lin(); break; case 2: #ifdef EDITOR_TMAP fx_xright = f2i(xright); fx_xleft = f2i(xleft); tmap_flat_color = 1; cur_tmap_scanline_flat(); #else Int3(); // Illegal, called an editor only routine! #endif break; } }
//compute the corners of a rod. fills in vertbuf. static int calc_rod_corners(g3s_point *bot_point,fix bot_width,g3s_point *top_point,fix top_width) { vms_vector delta_vec,top,tempv,rod_norm; ubyte codes_and; int i; //compute vector from one point to other, do cross product with vector //from eye to get perpendiclar vm_vec_sub(&delta_vec,&bot_point->p3_vec,&top_point->p3_vec); //unscale for aspect delta_vec.x = fixdiv(delta_vec.x,Matrix_scale.x); delta_vec.y = fixdiv(delta_vec.y,Matrix_scale.y); //calc perp vector //do lots of normalizing to prevent overflowing. When this code works, //it should be optimized vm_vec_normalize(&delta_vec); vm_vec_copy_normalize(&top,&top_point->p3_vec); vm_vec_cross(&rod_norm,&delta_vec,&top); vm_vec_normalize(&rod_norm); //scale for aspect rod_norm.x = fixmul(rod_norm.x,Matrix_scale.x); rod_norm.y = fixmul(rod_norm.y,Matrix_scale.y); //now we have the usable edge. generate four points //top points vm_vec_copy_scale(&tempv,&rod_norm,top_width); tempv.z = 0; vm_vec_add(&rod_points[0].p3_vec,&top_point->p3_vec,&tempv); vm_vec_sub(&rod_points[1].p3_vec,&top_point->p3_vec,&tempv); vm_vec_copy_scale(&tempv,&rod_norm,bot_width); tempv.z = 0; vm_vec_sub(&rod_points[2].p3_vec,&bot_point->p3_vec,&tempv); vm_vec_add(&rod_points[3].p3_vec,&bot_point->p3_vec,&tempv); //now code the four points for (i=0,codes_and=0xff;i<4;i++) codes_and &= g3_code_point(&rod_points[i]); if (codes_and) return 1; //1 means off screen //clear flags for new points (not projected) for (i=0;i<4;i++) rod_points[i].p3_flags = 0; return 0; }
fix compute_dv_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy) { return fixmul(fixmul(t->verts[bottom_vertex].v,t->verts[bottom_vertex].z) - fixmul(t->verts[top_vertex].v,t->verts[top_vertex].z), recip_dy); }
//clips an edge against one plane. g3s_point *clip_edge(int plane_flag,g3s_point *on_pnt,g3s_point *off_pnt) { fix psx_ratio; fix a,b,kn,kd; g3s_point *tmp; //compute clipping value k = (xs-zs) / (xs-xe-zs+ze) //use x or y as appropriate, and negate x/y value as appropriate if (plane_flag & (CC_OFF_RIGHT | CC_OFF_LEFT)) { a = on_pnt->p3_x; b = off_pnt->p3_x; } else { a = on_pnt->p3_y; b = off_pnt->p3_y; } if (plane_flag & (CC_OFF_LEFT | CC_OFF_BOT)) { a = -a; b = -b; } kn = a - on_pnt->p3_z; //xs-zs kd = kn - b + off_pnt->p3_z; //xs-zs-xe+ze tmp = get_temp_point(); psx_ratio = fixdiv( kn, kd ); // PSX_HACK!!!! // tmp->p3_x = on_pnt->p3_x + fixmuldiv(off_pnt->p3_x-on_pnt->p3_x,kn,kd); // tmp->p3_y = on_pnt->p3_y + fixmuldiv(off_pnt->p3_y-on_pnt->p3_y,kn,kd); tmp->p3_x = on_pnt->p3_x + fixmul( (off_pnt->p3_x-on_pnt->p3_x), psx_ratio); tmp->p3_y = on_pnt->p3_y + fixmul( (off_pnt->p3_y-on_pnt->p3_y), psx_ratio); if (plane_flag & (CC_OFF_TOP|CC_OFF_BOT)) tmp->p3_z = tmp->p3_y; else tmp->p3_z = tmp->p3_x; if (plane_flag & (CC_OFF_LEFT|CC_OFF_BOT)) tmp->p3_z = -tmp->p3_z; if (on_pnt->p3_flags & PF_UVS) { // PSX_HACK!!!! // tmp->p3_u = on_pnt->p3_u + fixmuldiv(off_pnt->p3_u-on_pnt->p3_u,kn,kd); // tmp->p3_v = on_pnt->p3_v + fixmuldiv(off_pnt->p3_v-on_pnt->p3_v,kn,kd); tmp->p3_u = on_pnt->p3_u + fixmul((off_pnt->p3_u-on_pnt->p3_u), psx_ratio); tmp->p3_v = on_pnt->p3_v + fixmul((off_pnt->p3_v-on_pnt->p3_v), psx_ratio); tmp->p3_flags |= PF_UVS; } if (on_pnt->p3_flags & PF_LS) { // PSX_HACK // tmp->p3_r = on_pnt->p3_r + fixmuldiv(off_pnt->p3_r-on_pnt->p3_r,kn,kd); // tmp->p3_g = on_pnt->p3_g + fixmuldiv(off_pnt->p3_g-on_pnt->p3_g,kn,kd); // tmp->p3_b = on_pnt->p3_b + fixmuldiv(off_pnt->p3_b-on_pnt->p3_b,kn,kd); tmp->p3_l = on_pnt->p3_l + fixmul((off_pnt->p3_l-on_pnt->p3_l), psx_ratio); tmp->p3_flags |= PF_LS; } G3EncodePoint(tmp); return tmp; }
int GameZoomIn() { Render_zoom = fixmul(Render_zoom,62259); Update_flags |= UF_GAME_VIEW_CHANGED; return 1; }
void timer_delay(fix seconds) { SDL_Delay(f2i(fixmul(seconds, i2f(1000)))); }
void do_robot_window() { int i; fix DeltaTime, Temp; int first_object_index; if ( MainWindow == NULL ) return; first_object_index = Cur_object_index; while (!is_legal_type_for_this_window(Cur_object_index)) { LocalObjectSelectNextinMine(); if (first_object_index == Cur_object_index) { break; } } //------------------------------------------------------------ // Call the ui code.. //------------------------------------------------------------ ui_button_any_drawn = 0; ui_window_do_gadgets(MainWindow); //------------------------------------------------------------ // If we change objects, we need to reset the ui code for all // of the radio buttons that control the ai mode. Also makes // the current AI mode button be flagged as pressed down. //------------------------------------------------------------ if (old_object != Cur_object_index ) { for ( i=0; i < NUM_BOXES; i++ ) { InitialMode[i]->flag = 0; // Tells ui that this button isn't checked InitialMode[i]->status = 1; // Tells ui to redraw button } if ( Cur_object_index > -1 ) { int behavior = Objects[Cur_object_index].ctype.ai_info.behavior; if ( !((behavior >= MIN_BEHAVIOR) && (behavior <= MAX_BEHAVIOR))) { mprintf((0, "Object #%i behavior id (%i) out of bounds, setting to AIB_NORMAL.\n", Cur_object_index, behavior)); Objects[Cur_object_index].ctype.ai_info.behavior = AIB_NORMAL; behavior = AIB_NORMAL; } InitialMode[behavior - MIN_BEHAVIOR]->flag = 1; // Mark this button as checked } } //------------------------------------------------------------ // If any of the radio buttons that control the mode are set, then // update the cooresponding AI state. //------------------------------------------------------------ for ( i=0; i < NUM_BOXES; i++ ) { if ( InitialMode[i]->flag == 1 ) if (Objects[Cur_object_index].ctype.ai_info.behavior != MIN_BEHAVIOR+i) { Objects[Cur_object_index].ctype.ai_info.behavior = MIN_BEHAVIOR+i; // Set the ai_state to the cooresponding radio button call_init_ai_object(&Objects[Cur_object_index], MIN_BEHAVIOR+i); } } //------------------------------------------------------------ // A simple frame time counter for spinning the objects... //------------------------------------------------------------ Temp = timer_get_fixed_seconds(); DeltaTime = Temp - Time; Time = Temp; //------------------------------------------------------------ // Redraw the object in the little 64x64 box //------------------------------------------------------------ if (Cur_object_index > -1 ) { int id; gr_set_current_canvas( RobotViewBox->canvas ); id = get_object_id(&Objects[Cur_object_index]); if ( id > -1 ) draw_robot_picture(id, &angles, -1 ); else gr_clear_canvas( CGREY ); angles.h += fixmul(0x1000, DeltaTime ); } else { // no object, so just blank out gr_set_current_canvas( RobotViewBox->canvas ); gr_clear_canvas( CGREY ); // LocalObjectSelectNextInMine(); } //------------------------------------------------------------ // Redraw the contained object in the other little box //------------------------------------------------------------ if ((Cur_object_index > -1 ) && (Cur_goody_count > 0)) { int id; gr_set_current_canvas( ContainsViewBox->canvas ); id = Cur_goody_id; if ( id > -1 ) { int ol_type; if (Cur_goody_type == OBJ_ROBOT) ol_type = OL_ROBOT; else if (Cur_goody_type == OBJ_POWERUP) ol_type = OL_POWERUP; else Int3(); // Error? Unknown goody type! draw_robot_picture(id, &goody_angles, ol_type ); } else gr_clear_canvas( CGREY ); goody_angles.h += fixmul(0x1000, DeltaTime ); } else { // no object, so just blank out gr_set_current_canvas( ContainsViewBox->canvas ); gr_clear_canvas( CGREY ); // LocalObjectSelectNextInMine(); } //------------------------------------------------------------ // If anything changes in the ui system, redraw all the text that // identifies this robot. //------------------------------------------------------------ if (ui_button_any_drawn || (old_object != Cur_object_index) ) { int i; char type_text[STRING_LENGTH+1],id_text[STRING_LENGTH+1]; if (Cur_object_index != -1) { Cur_goody_type = Objects[Cur_object_index].contains_type; Cur_goody_id = Objects[Cur_object_index].contains_id; if (Objects[Cur_object_index].contains_count < 0) Objects[Cur_object_index].contains_count = 0; Cur_goody_count = Objects[Cur_object_index].contains_count; } ui_wprintf_at( MainWindow, GOODY_X, GOODY_Y, " Type:"); ui_wprintf_at( MainWindow, GOODY_X, GOODY_Y+24, " ID:"); ui_wprintf_at( MainWindow, GOODY_X, GOODY_Y+48, "Count:"); for (i=0; i<STRING_LENGTH; i++) id_text[i] = ' '; id_text[i] = 0; switch (Cur_goody_type) { case OBJ_ROBOT: strcpy(type_text, "Robot "); strncpy(id_text, Robot_names[Cur_goody_id], strlen(Robot_names[Cur_goody_id])); break; case OBJ_POWERUP: strcpy(type_text, "Powerup"); strncpy(id_text, Powerup_names[Cur_goody_id], strlen(Powerup_names[Cur_goody_id])); break; default: editor_status("Illegal contained object type (%i), changing to powerup.", Cur_goody_type); Cur_goody_type = OBJ_POWERUP; Cur_goody_id = 0; strcpy(type_text, "Powerup"); strncpy(id_text, Powerup_names[Cur_goody_id], strlen(Powerup_names[Cur_goody_id])); break; } ui_wprintf_at( MainWindow, GOODY_X+108, GOODY_Y, type_text); ui_wprintf_at( MainWindow, GOODY_X+108, GOODY_Y+24, id_text); ui_wprintf_at( MainWindow, GOODY_X+108, GOODY_Y+48, "%i", Cur_goody_count); if ( Cur_object_index > -1 ) { int id = Objects[Cur_object_index].id; char id_text[12]; int i; for (i=0; i<STRING_LENGTH; i++) id_text[i] = ' '; id_text[i] = 0; strncpy(id_text, Robot_names[id], strlen(Robot_names[id])); ui_wprintf_at( MainWindow, 12, 6, "Robot: %3d ", Cur_object_index ); ui_wprintf_at( MainWindow, 12, 22, " Id: %3d", id); ui_wprintf_at( MainWindow, 12, 38, " Name: %8s", id_text); } else { ui_wprintf_at( MainWindow, 12, 6, "Robot: none" ); ui_wprintf_at( MainWindow, 12, 22, " Type: ? " ); ui_wprintf_at( MainWindow, 12, 38, " Name: ________" ); } Update_flags |= UF_WORLD_CHANGED; } if ( QuitButton->pressed || (last_keypress==KEY_ESC)) { robot_close_window(); return; } old_object = Cur_object_index; }
// ----------------------------------------------------------------------------------------------------------- //Simulate a physics object for this frame void do_physics_sim(object *obj) { int ignore_obj_list[MAX_IGNORE_OBJS],n_ignore_objs; int iseg; int try_again; int fate; vms_vector frame_vec; //movement in this frame vms_vector new_pos,ipos; //position after this frame int count=0; int objnum; int WallHitSeg, WallHitSide; fvi_info hit_info; fvi_query fq; vms_vector save_pos; int save_seg; fix drag; fix sim_time,old_sim_time; vms_vector start_pos; int obj_stopped=0; fix moved_time; //how long objected moved before hit something vms_vector save_p0,save_p1; physics_info *pi; int orig_segnum = obj->segnum; int bounced=0; Assert(obj->type != OBJ_NONE); Assert(obj->movement_type == MT_PHYSICS); #ifndef NDEBUG if (Dont_move_ai_objects) if (obj->control_type == CT_AI) return; #endif pi = &obj->mtype.phys_info; do_physics_sim_rot(obj); if (!(pi->velocity.x || pi->velocity.y || pi->velocity.z || pi->thrust.x || pi->thrust.y || pi->thrust.z)) return; objnum = obj-Objects; n_phys_segs = 0; disable_new_fvi_stuff = (obj->type != OBJ_PLAYER); sim_time = FrameTime; //debug_obj = obj; #ifdef EXTRA_DEBUG if (obj == debug_obj) { printf("object %d:\n start pos = %x %x %x\n",objnum,XYZ(&obj->pos)); printf(" thrust = %x %x %x\n",XYZ(&obj->mtype.phys_info.thrust)); printf(" sim_time = %x\n",sim_time); } //check for correct object segment if(!get_seg_masks(&obj->pos,obj->segnum,0).centermask==0) { #ifndef NDEBUG mprintf((0,"Warning: object %d not in given seg!\n",objnum)); #endif //Int3(); Removed by Rob 10/5/94 if (!update_object_seg(obj)) { #ifndef NDEBUG mprintf((0,"Warning: can't find seg for object %d - moving\n",objnum)); #endif if (!(Game_mode & GM_MULTI)) Int3(); compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } } #endif start_pos = obj->pos; n_ignore_objs = 0; Assert(obj->mtype.phys_info.brakes==0); //brakes not used anymore? //if uses thrust, cannot have zero drag Assert(!(obj->mtype.phys_info.flags&PF_USES_THRUST) || obj->mtype.phys_info.drag!=0); //mprintf((0,"thrust=%x speed=%x\n",vm_vec_mag(&obj->mtype.phys_info.thrust),vm_vec_mag(&obj->mtype.phys_info.velocity))); //do thrust & drag if ((drag = obj->mtype.phys_info.drag) != 0) { int count; vms_vector accel; fix r,k; count = sim_time / FT; r = sim_time % FT; k = fixdiv(r,FT); if (obj->mtype.phys_info.flags & PF_USES_THRUST) { vm_vec_copy_scale(&accel,&obj->mtype.phys_info.thrust,fixdiv(f1_0,obj->mtype.phys_info.mass)); while (count--) { vm_vec_add2(&obj->mtype.phys_info.velocity,&accel); vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-drag); } //do linear scale on remaining bit of time vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&accel,k); vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-fixmul(k,drag)); } else { fix total_drag=f1_0; while (count--) total_drag = fixmul(total_drag,f1_0-drag); //do linear scale on remaining bit of time total_drag = fixmul(total_drag,f1_0-fixmul(k,drag)); vm_vec_scale(&obj->mtype.phys_info.velocity,total_drag); } } #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" velocity = %x %x %x\n",XYZ(&obj->mtype.phys_info.velocity)); #endif do { try_again = 0; //Move the object vm_vec_copy_scale(&frame_vec, &obj->mtype.phys_info.velocity, sim_time); #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" pass %d, frame_vec = %x %x %x\n",count,XYZ(&frame_vec)); #endif if ( (frame_vec.x==0) && (frame_vec.y==0) && (frame_vec.z==0) ) break; count++; // If retry count is getting large, then we are trying to do something stupid. if ( count > 3) { if (obj->type == OBJ_PLAYER) { if (count > 8) break; } else break; } vm_vec_add(&new_pos,&obj->pos,&frame_vec); #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" desired_pos = %x %x %x\n",XYZ(&new_pos)); #endif ignore_obj_list[n_ignore_objs] = -1; #ifdef EXTRA_DEBUG if (obj == debug_obj) { printf(" FVI parms: p0 = %8x %8x %8x, segnum=%x, size=%x\n",XYZ(&obj->pos),obj->segnum,obj->size); printf(" p1 = %8x %8x %8x\n",XYZ(&new_pos)); } #endif fq.p0 = &obj->pos; fq.startseg = obj->segnum; fq.p1 = &new_pos; fq.rad = obj->size; fq.thisobjnum = objnum; fq.ignore_obj_list = ignore_obj_list; fq.flags = FQ_CHECK_OBJS; if (obj->type == OBJ_WEAPON) fq.flags |= FQ_TRANSPOINT; if (obj->type == OBJ_PLAYER) fq.flags |= FQ_GET_SEGLIST; //@@ if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0) //@@ Int3(); save_p0 = *fq.p0; save_p1 = *fq.p1; fate = find_vector_intersection(&fq,&hit_info); // Matt: Mike's hack. if (fate == HIT_OBJECT) { object *objp = &Objects[hit_info.hit_object]; if ((objp->type == OBJ_WEAPON) && ((objp->id == PROXIMITY_ID) || (objp->id == SUPERPROX_ID))) count--; } #ifndef NDEBUG if (fate == HIT_BAD_P0) { mprintf((0,"Warning: Bad p0 in physics! Object = %i, type = %i [%s]\n", obj-Objects, obj->type, Object_type_names[obj->type])); Int3(); } #endif if (obj->type == OBJ_PLAYER) { int i; if (n_phys_segs && phys_seglist[n_phys_segs-1]==hit_info.seglist[0]) n_phys_segs--; for (i=0;(i<hit_info.n_segs) && (n_phys_segs<MAX_FVI_SEGS-1); ) phys_seglist[n_phys_segs++] = hit_info.seglist[i++]; } #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" fate = %d, hit_pnt = %8x %8x %8x\n",fate,XYZ(&hit_info.hit_pnt));; #endif ipos = hit_info.hit_pnt; iseg = hit_info.hit_seg; WallHitSide = hit_info.hit_side; WallHitSeg = hit_info.hit_side_seg; if (iseg==-1) { //some sort of horrible error #ifndef NDEBUG mprintf((1,"iseg==-1 in physics! Object = %i, type = %i (%s)\n", obj-Objects, obj->type, Object_type_names[obj->type])); #endif //Int3(); //compute_segment_center(&ipos,&Segments[obj->segnum]); //ipos.x += objnum; //iseg = obj->segnum; //fate = HIT_NONE; if (obj->type == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; break; } Assert(!((fate==HIT_WALL) && ((WallHitSeg == -1) || (WallHitSeg > Highest_segment_index)))); //if(!get_seg_masks(&hit_info.hit_pnt,hit_info.hit_seg,0).centermask==0) // Int3(); save_pos = obj->pos; //save the object's position save_seg = obj->segnum; // update object's position and segment number obj->pos = ipos; #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" new pos = %x %x %x\n",XYZ(&obj->pos)); #endif if ( iseg != obj->segnum ) obj_relink(objnum, iseg ); //if start point not in segment, move object to center of segment if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0) { int n; if ((n=find_object_seg(obj))==-1) { //Int3(); if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) { obj->pos = obj->last_pos; obj_relink(objnum, n ); } else { compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } if (obj->type == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; } return; } //calulate new sim time { //vms_vector moved_vec; vms_vector moved_vec_n; fix attempted_dist,actual_dist; old_sim_time = sim_time; actual_dist = vm_vec_normalized_dir(&moved_vec_n,&obj->pos,&save_pos); if (fate==HIT_WALL && vm_vec_dot(&moved_vec_n,&frame_vec) < 0) { //moved backwards //don't change position or sim_time //******* mprintf((0,"Obj %d moved backwards\n",obj-Objects)); #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" Warning: moved backwards!\n"); #endif obj->pos = save_pos; //iseg = obj->segnum; //don't change segment obj_relink(objnum, save_seg ); moved_time = 0; } else { //if (obj == debug_obj) // printf(" moved_vec = %x %x %x\n",XYZ(&moved_vec)); attempted_dist = vm_vec_mag(&frame_vec); sim_time = fixmuldiv(sim_time,attempted_dist-actual_dist,attempted_dist); moved_time = old_sim_time - sim_time; if (sim_time < 0 || sim_time>old_sim_time) { #ifndef NDEBUG mprintf((0,"Bogus sim_time = %x, old = %x\n",sim_time,old_sim_time)); if (obj == debug_obj) printf(" Bogus sim_time = %x, old = %x, attempted_dist = %x, actual_dist = %x\n",sim_time,old_sim_time,attempted_dist,actual_dist); //Int3(); Removed by Rob #endif sim_time = old_sim_time; //WHY DOES THIS HAPPEN?? moved_time = 0; } } #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" new sim_time = %x\n",sim_time); #endif } switch( fate ) { case HIT_WALL: { vms_vector moved_v; //@@fix total_d,moved_d; fix hit_speed,wall_part; // Find hit speed vm_vec_sub(&moved_v,&obj->pos,&save_pos); wall_part = vm_vec_dot(&moved_v,&hit_info.hit_wallnorm); if (wall_part != 0 && moved_time>0 && (hit_speed=-fixdiv(wall_part,moved_time))>0) collide_object_with_wall( obj, hit_speed, WallHitSeg, WallHitSide, &hit_info.hit_pnt ); else scrape_object_on_wall(obj, WallHitSeg, WallHitSide, &hit_info.hit_pnt ); Assert( WallHitSeg > -1 ); Assert( WallHitSide > -1 ); if ( !(obj->flags&OF_SHOULD_BE_DEAD) ) { int forcefield_bounce; //bounce off a forcefield Assert(BounceCheat || !(obj->mtype.phys_info.flags & PF_STICK && obj->mtype.phys_info.flags & PF_BOUNCE)); //can't be bounce and stick forcefield_bounce = (TmapInfo[Segments[WallHitSeg].sides[WallHitSide].tmap_num].flags & TMI_FORCE_FIELD); if (!forcefield_bounce && (obj->mtype.phys_info.flags & PF_STICK)) { //stop moving // mprintf((0, "Object %i stuck at %i:%i\n", obj-Objects, WallHitSeg, WallHitSide)); add_stuck_object(obj, WallHitSeg, WallHitSide); vm_vec_zero(&obj->mtype.phys_info.velocity); obj_stopped = 1; try_again = 0; } else { // Slide object along wall int check_vel=0; //We're constrained by wall, so subtract wall part from //velocity vector wall_part = vm_vec_dot(&hit_info.hit_wallnorm,&obj->mtype.phys_info.velocity); // mprintf((0, "%d", f2i(vm_vec_mag(&hit_info.hit_wallnorm)) )); if (forcefield_bounce || (obj->mtype.phys_info.flags & PF_BOUNCE)) { //bounce off wall wall_part *= 2; //Subtract out wall part twice to achieve bounce if (forcefield_bounce) { check_vel = 1; //check for max velocity if (obj->type == OBJ_PLAYER) wall_part *= 2; //player bounce twice as much } if ( obj->mtype.phys_info.flags & PF_BOUNCES_TWICE) { Assert(obj->mtype.phys_info.flags & PF_BOUNCE); if (obj->mtype.phys_info.flags & PF_BOUNCED_ONCE) obj->mtype.phys_info.flags &= ~(PF_BOUNCE+PF_BOUNCED_ONCE+PF_BOUNCES_TWICE); else obj->mtype.phys_info.flags |= PF_BOUNCED_ONCE; } bounced = 1; //this object bounced } vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&hit_info.hit_wallnorm,-wall_part); // mprintf((0, "Velocity at bounce time = %d\n", f2i(vm_vec_mag(&obj->mtype.phys_info.velocity)))); //if (obj==ConsoleObject) // mprintf((0,"player vel = %x\n",vm_vec_mag_quick(&obj->mtype.phys_info.velocity))); if (check_vel) { fix vel = vm_vec_mag_quick(&obj->mtype.phys_info.velocity); if (vel > MAX_OBJECT_VEL) vm_vec_scale(&obj->mtype.phys_info.velocity,fixdiv(MAX_OBJECT_VEL,vel)); } if (bounced && obj->type == OBJ_WEAPON) vm_vector_2_matrix(&obj->orient,&obj->mtype.phys_info.velocity,&obj->orient.uvec,NULL); #ifdef EXTRA_DEBUG if (obj == debug_obj) { printf(" sliding - wall_norm %x %x %x %x\n",wall_part,XYZ(&hit_info.hit_wallnorm)); printf(" wall_part %x, new velocity = %x %x %x\n",wall_part,XYZ(&obj->mtype.phys_info.velocity)); } #endif try_again = 1; } } break; } case HIT_OBJECT: { vms_vector old_vel; // Mark the hit object so that on a retry the fvi code // ignores this object. Assert(hit_info.hit_object != -1); // Calculcate the hit point between the two objects. { vms_vector *ppos0, *ppos1, pos_hit; fix size0, size1; ppos0 = &Objects[hit_info.hit_object].pos; ppos1 = &obj->pos; size0 = Objects[hit_info.hit_object].size; size1 = obj->size; Assert(size0+size1 != 0); // Error, both sizes are 0, so how did they collide, anyway?!? //vm_vec_scale(vm_vec_sub(&pos_hit, ppos1, ppos0), fixdiv(size0, size0 + size1)); //vm_vec_add2(&pos_hit, ppos0); vm_vec_sub(&pos_hit, ppos1, ppos0); vm_vec_scale_add(&pos_hit,ppos0,&pos_hit,fixdiv(size0, size0 + size1)); old_vel = obj->mtype.phys_info.velocity; collide_two_objects( obj, &Objects[hit_info.hit_object], &pos_hit); } // Let object continue its movement if ( !(obj->flags&OF_SHOULD_BE_DEAD) ) { //obj->pos = save_pos; if (obj->mtype.phys_info.flags&PF_PERSISTENT || (old_vel.x == obj->mtype.phys_info.velocity.x && old_vel.y == obj->mtype.phys_info.velocity.y && old_vel.z == obj->mtype.phys_info.velocity.z)) { //if (Objects[hit_info.hit_object].type == OBJ_POWERUP) ignore_obj_list[n_ignore_objs++] = hit_info.hit_object; try_again = 1; } } break; } case HIT_NONE: #ifdef TACTILE if (TactileStick && obj==ConsoleObject && !(FrameCount & 15)) Tactile_Xvibrate_clear (); #endif break; #ifndef NDEBUG case HIT_BAD_P0: Int3(); // Unexpected collision type: start point not in specified segment. mprintf((0,"Warning: Bad p0 in physics!!!\n")); break; default: // Unknown collision type returned from find_vector_intersection!! Int3(); break; #endif } } while ( try_again ); // Pass retry count info to AI. if (obj->control_type == CT_AI) { if (count > 0) { Ai_local_info[objnum].retry_count = count-1; #ifndef NDEBUG Total_retries += count-1; Total_sims++; #endif } } //I'm not sure why we do this. I wish there were a comment that //explained it. I think maybe it only needs to be done if the object //is sliding, but I don't know if (!obj_stopped && !bounced) { //Set velocity from actual movement vms_vector moved_vec; vm_vec_sub(&moved_vec,&obj->pos,&start_pos); vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&moved_vec,fixdiv(f1_0,FrameTime)); #ifdef BUMP_HACK if (obj==ConsoleObject && (obj->mtype.phys_info.velocity.x==0 && obj->mtype.phys_info.velocity.y==0 && obj->mtype.phys_info.velocity.z==0) && !(obj->mtype.phys_info.thrust.x==0 && obj->mtype.phys_info.thrust.y==0 && obj->mtype.phys_info.thrust.z==0)) { vms_vector center,bump_vec; //bump player a little towards center of segment to unstick compute_segment_center(¢er,&Segments[obj->segnum]); vm_vec_normalized_dir_quick(&bump_vec,¢er,&obj->pos); //don't bump player toward center of reactor segment if (Segment2s[obj->segnum].special == SEGMENT_IS_CONTROLCEN) vm_vec_negate(&bump_vec); vm_vec_scale_add2(&obj->pos,&bump_vec,obj->size/5); //if moving away from seg, might move out of seg, so update if (Segment2s[obj->segnum].special == SEGMENT_IS_CONTROLCEN) update_object_seg(obj); } #endif } //Assert(check_point_in_seg(&obj->pos,obj->segnum,0).centermask==0); //if (obj->control_type == CT_FLYING) if (obj->mtype.phys_info.flags & PF_LEVELLING) do_physics_align_object( obj ); //hack to keep player from going through closed doors if (obj->type==OBJ_PLAYER && obj->segnum!=orig_segnum && (Physics_cheat_flag!=0xBADA55) ) { int sidenum; sidenum = find_connect_side(&Segments[obj->segnum],&Segments[orig_segnum]); if (sidenum != -1) { if (! (WALL_IS_DOORWAY(&Segments[orig_segnum],sidenum) & WID_FLY_FLAG)) { side *s; int vertnum,num_faces,i; fix dist; int vertex_list[6]; //bump object back s = &Segments[orig_segnum].sides[sidenum]; if (orig_segnum==-1) Error("orig_segnum == -1 in physics"); create_abs_vertex_lists( &num_faces, vertex_list, orig_segnum, sidenum); //let's pretend this wall is not triangulated vertnum = vertex_list[0]; for (i=1;i<4;i++) if (vertex_list[i] < vertnum) vertnum = vertex_list[i]; #ifdef COMPACT_SEGS { vms_vector _vn; get_side_normal(&Segments[orig_segnum], sidenum, 0, &_vn ); dist = vm_dist_to_plane(&start_pos, &_vn, &Vertices[vertnum]); vm_vec_scale_add(&obj->pos,&start_pos,&_vn,obj->size-dist); } #else dist = vm_dist_to_plane(&start_pos, &s->normals[0], &Vertices[vertnum]); vm_vec_scale_add(&obj->pos,&start_pos,&s->normals[0],obj->size-dist); #endif update_object_seg(obj); } } } //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #ifndef NDEBUG //if end point not in segment, move object to last pos, or segment center if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0) { if (find_object_seg(obj)==-1) { int n; //Int3(); if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) { obj->pos = obj->last_pos; obj_relink(objnum, n ); } else { compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } if (obj->type == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; } } //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #endif }
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) { fixang save_delta_ang; vms_angvec tangles; vm_vector_2_matrix(&temp_matrix,&obj->orient.fvec,&desired_upvec,NULL); save_delta_ang = 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; } }
// ----------------------------------------------------------------------------------------------------------- // add rotational velocity & acceleration void do_physics_sim_rot(object *obj) { vms_angvec tangles; vms_matrix rotmat,new_orient; //fix rotdrag_scale; physics_info *pi; Assert(FrameTime > 0); //Get MATT if hit this! pi = &obj->mtype.phys_info; if (!(pi->rotvel.x || pi->rotvel.y || pi->rotvel.z || pi->rotthrust.x || pi->rotthrust.y || pi->rotthrust.z)) return; if (obj->mtype.phys_info.drag) { int count; vms_vector accel; fix drag,r,k; count = FrameTime / FT; r = FrameTime % FT; k = fixdiv(r,FT); drag = (obj->mtype.phys_info.drag*5)/2; if (obj->mtype.phys_info.flags & PF_USES_THRUST) { vm_vec_copy_scale(&accel,&obj->mtype.phys_info.rotthrust,fixdiv(f1_0,obj->mtype.phys_info.mass)); while (count--) { vm_vec_add2(&obj->mtype.phys_info.rotvel,&accel); vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-drag); } //do linear scale on remaining bit of time vm_vec_scale_add2(&obj->mtype.phys_info.rotvel,&accel,k); vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-fixmul(k,drag)); } else if (! (obj->mtype.phys_info.flags & PF_FREE_SPINNING)) { fix total_drag=f1_0; while (count--) total_drag = fixmul(total_drag,f1_0-drag); //do linear scale on remaining bit of time total_drag = fixmul(total_drag,f1_0-fixmul(k,drag)); vm_vec_scale(&obj->mtype.phys_info.rotvel,total_drag); } } //mprintf( (0, "Rot vel = %.3f,%.3f,%.3f\n", f2fl(obj->mtype.phys_info.rotvel.x),f2fl(obj->mtype.phys_info.rotvel.y), f2fl(obj->mtype.phys_info.rotvel.z) )); //now rotate object //unrotate object for bank caused by turn if (obj->mtype.phys_info.turnroll) { vms_matrix new_pm; tangles.p = tangles.h = 0; tangles.b = -obj->mtype.phys_info.turnroll; vm_angles_2_matrix(&rotmat,&tangles); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; } tangles.p = fixmul(obj->mtype.phys_info.rotvel.x,FrameTime); tangles.h = fixmul(obj->mtype.phys_info.rotvel.y,FrameTime); tangles.b = fixmul(obj->mtype.phys_info.rotvel.z,FrameTime); vm_angles_2_matrix(&rotmat,&tangles); vm_matrix_x_matrix(&new_orient,&obj->orient,&rotmat); obj->orient = new_orient; if (obj->mtype.phys_info.flags & PF_TURNROLL) set_object_turnroll(obj); //re-rotate object for bank caused by turn if (obj->mtype.phys_info.turnroll) { vms_matrix new_pm; tangles.p = tangles.h = 0; tangles.b = obj->mtype.phys_info.turnroll; vm_angles_2_matrix(&rotmat,&tangles); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; } check_and_fix_matrix(&obj->orient); }
vms_vector evaluate_curve(vms_equation *coeffs, int degree, fix t) { fix t2, t3; vms_vector coord; if (degree != 3) con_puts(CON_CRITICAL," for Hermite Curves degree must be 3"); t2 = fixmul(t,t); t3 = fixmul(t2,t); coord.x = fixmul(coeffs->n.x3,t3) + fixmul(coeffs->n.x2,t2) + fixmul(coeffs->n.x1,t) + coeffs->n.x0; coord.y = fixmul(coeffs->n.y3,t3) + fixmul(coeffs->n.y2,t2) + fixmul(coeffs->n.y1,t) + coeffs->n.y0; coord.z = fixmul(coeffs->n.z3,t3) + fixmul(coeffs->n.z2,t2) + fixmul(coeffs->n.z1,t) + coeffs->n.z0; return coord; }
static void create_curve(vms_vector &p1, vms_vector &p4, vms_vector &r1, vms_vector &r4, vms_equation &coeffs) { // Q(t) = (2t^3 - 3t^2 + 1) p1 + (-2t^3 + 3t^2) p4 + (t~3 - 2t^2 + t) r1 + (t^3 - t^2 ) r4 coeffs.n.x3 = fixmul(2*F1_0,p1.x) - fixmul(2*F1_0,p4.x) + r1.x + r4.x; coeffs.n.x2 = fixmul(-3*F1_0,p1.x) + fixmul(3*F1_0,p4.x) - fixmul(2*F1_0,r1.x) - fixmul(1*F1_0,r4.x); coeffs.n.x1 = r1.x; coeffs.n.x0 = p1.x; coeffs.n.y3 = fixmul(2*F1_0,p1.y) - fixmul(2*F1_0,p4.y) + r1.y + r4.y; coeffs.n.y2 = fixmul(-3*F1_0,p1.y) + fixmul(3*F1_0,p4.y) - fixmul(2*F1_0,r1.y) - fixmul(1*F1_0,r4.y); coeffs.n.y1 = r1.y; coeffs.n.y0 = p1.y; coeffs.n.z3 = fixmul(2*F1_0,p1.z) - fixmul(2*F1_0,p4.z) + r1.z + r4.z; coeffs.n.z2 = fixmul(-3*F1_0,p1.z) + fixmul(3*F1_0,p4.z) - fixmul(2*F1_0,r1.z) - fixmul(1*F1_0,r4.z); coeffs.n.z1 = r1.z; coeffs.n.z0 = p1.z; }
// ------------------------------------------------------------------------------------- // Texture map current scanline in perspective. // ------------------------------------------------------------------------------------- void ntmap_scanline_lighted(grs_bitmap *srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix zleft, fix zright, fix lleft, fix lright) { fix u,v,l; fix dx,recip_dx; fix du_dx,dv_dx,dz_dx,z; u = uleft; v = vleft; l = lleft; fx_xright = f2i(xright); fx_xleft = f2i(xleft); dx = fx_xright - fx_xleft; if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers return; // setup to call assembler scanline renderer if (dx < FIX_RECIP_TABLE_SIZE) recip_dx = fix_recip[dx]; else recip_dx = F1_0/dx; du_dx = fixmul(uright - uleft,recip_dx); dv_dx = fixmul(vright - vleft,recip_dx); dz_dx = fixmul(zright - zleft,recip_dx); z = zleft; fx_u = uleft; fx_v = vleft; fx_z = zleft; fx_du_dx = du_dx; fx_dv_dx = dv_dx; fx_dz_dx = dz_dx; fx_y = y; pixptr = srcb->bm_data; switch (Lighting_enabled) { case 0: if (fx_xleft > Window_clip_right) return; if (fx_xright < Window_clip_left) return; if (fx_xright > Window_clip_right) fx_xright = Window_clip_right; #ifdef NASM c_tmap_scanline_per_nolight(); #else asm_tmap_scanline_per(); #endif break; case 1: { fix mul_thing; if (lleft < 0) lleft = 0; if (lright < 0) lright = 0; if (lleft > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lleft = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2); if (lright > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lright = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2); fx_l = lleft; fx_dl_dx = fixmul(lright - lleft,recip_dx); // This is a pretty ugly hack to prevent lighting overflows. mul_thing = dx * fx_dl_dx; if (lleft + mul_thing < 0) fx_dl_dx += 12; else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) fx_dl_dx -= 12; if (fx_xleft > Window_clip_right) return; if (fx_xright < Window_clip_left) return; if (fx_xright > Window_clip_right) fx_xright = Window_clip_right; #ifdef NASM c_tmap_scanline_per(); #else asm_tmap_scanline_per(); #endif break; } case 2: #ifdef EDITOR_TMAP fx_xright = f2i(xright); fx_xleft = f2i(xleft); asm_tmap_scanline_matt(); #else Int3(); // Illegal, called an editor only routine! #endif break; } }
int do_slew_movement(object *obj, int check_keys, int check_joy ) { int moved = 0; vms_vector svel, movement; //scaled velocity (per this frame) vms_matrix rotmat,new_pm; int joy_x,joy_y,btns; int joyx_moved,joyy_moved; vms_angvec rotang; if (!slew_obj || slew_obj->control_type!=CT_SLEW) return 0; if (check_keys) { if (Function_mode == FMODE_EDITOR) { obj->mtype.phys_info.velocity.x += VEL_SPEED * (key_down_time(KEY_PAD9) - key_down_time(KEY_PAD7)); obj->mtype.phys_info.velocity.y += VEL_SPEED * (key_down_time(KEY_PADMINUS) - key_down_time(KEY_PADPLUS)); obj->mtype.phys_info.velocity.z += VEL_SPEED * (key_down_time(KEY_PAD8) - key_down_time(KEY_PAD2)); rotang.p = (key_down_time(KEY_LBRACKET) - key_down_time(KEY_RBRACKET))/ROT_SPEED ; rotang.b = (key_down_time(KEY_PAD1) - key_down_time(KEY_PAD3))/ROT_SPEED; rotang.h = (key_down_time(KEY_PAD6) - key_down_time(KEY_PAD4))/ROT_SPEED; } else { obj->mtype.phys_info.velocity.x += VEL_SPEED * Controls.sideways_thrust_time; obj->mtype.phys_info.velocity.y += VEL_SPEED * Controls.vertical_thrust_time; obj->mtype.phys_info.velocity.z += VEL_SPEED * Controls.forward_thrust_time; rotang.p = Controls.pitch_time/ROT_SPEED ; rotang.b = Controls.bank_time/ROT_SPEED; rotang.h = Controls.heading_time/ROT_SPEED; } } else rotang.p = rotang.b = rotang.h = 0; //check for joystick movement if (check_joy && joy_present && (Function_mode == FMODE_EDITOR) ) { 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 (btns) if (!rotang.p) rotang.p = fixmul(-joy_y * 512,FrameTime); else; else if (joyy_moved) obj->mtype.phys_info.velocity.z = -joy_y * 8192; if (!rotang.h) rotang.h = fixmul(joy_x * 512,FrameTime); if (joyx_moved) old_joy_x = joy_x; if (joyy_moved) old_joy_y = joy_y; } moved = rotang.p | rotang.b | rotang.h; vm_angles_2_matrix(&rotmat,&rotang); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; vm_transpose_matrix(&new_pm); //make those columns rows moved |= obj->mtype.phys_info.velocity.x | obj->mtype.phys_info.velocity.y | obj->mtype.phys_info.velocity.z; svel = obj->mtype.phys_info.velocity; vm_vec_scale(&svel,FrameTime); //movement in this frame vm_vec_rotate(&movement,&svel,&new_pm); // obj->last_pos = obj->pos; vm_vec_add2(&obj->pos,&movement); moved |= (movement.x || movement.y || movement.z); if (moved) update_object_seg(obj); //update segment id return moved; }
// ------------------------------------------------------------------------------------- // Texture map current scanline using linear interpolation. // ------------------------------------------------------------------------------------- void ntmap_scanline_lighted_linear(grs_bitmap *srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix lleft, fix lright) { fix u,v,l; fix dx,recip_dx; fix du_dx,dv_dx,dl_dx; u = uleft; v = vleft; l = lleft; dx = f2i(xright) - f2i(xleft); if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers return; // setup to call assembler scanline renderer if (dx < FIX_RECIP_TABLE_SIZE) recip_dx = fix_recip[dx]; else recip_dx = F1_0/dx; du_dx = fixmul(uright - uleft,recip_dx); dv_dx = fixmul(vright - vleft,recip_dx); fx_u = uleft; fx_v = vleft; fx_du_dx = du_dx; fx_dv_dx = dv_dx; fx_y = y; fx_xright = f2i(xright); fx_xleft = f2i(xleft); pixptr = srcb->bm_data; switch (Lighting_enabled) { case 0: #ifdef NASM c_tmap_scanline_lin_nolight(); #else asm_tmap_scanline_lin(); #endif break; case 1: if (lleft < F1_0/2) lleft = F1_0/2; if (lright < F1_0/2) lright = F1_0/2; if (lleft > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS) lleft = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS; if (lright > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS) lright = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS; fx_l = lleft; dl_dx = fixmul(lright - lleft,recip_dx); fx_dl_dx = dl_dx; #ifdef NASM c_tmap_scanline_lin(); #else asm_tmap_scanline_lin_lighted(); #endif break; case 2: #ifdef EDITOR_TMAP fx_xright = f2i(xright); fx_xleft = f2i(xleft); asm_tmap_scanline_matt(); #else Int3(); // Illegal, called an editor only routine! #endif break; } }
void do_endlevel_flythrough(int n) { object *obj; segment *pseg; int old_player_seg; flydata = &fly_objects[n]; obj = flydata->obj; old_player_seg = obj->segnum; //move the player for this frame if (!flydata->first_time) { vm_vec_scale_add2(&obj->pos,&flydata->step,FrameTime); angvec_add2_scale(&flydata->angles,&flydata->angstep,FrameTime); vm_angles_2_matrix(&obj->orient,&flydata->angles); } //check new player seg update_object_seg(obj); pseg = &Segments[obj->segnum]; if (flydata->first_time || obj->segnum != old_player_seg) { //moved into new seg vms_vector curcenter,nextcenter; fix step_size,seg_time; short entry_side,exit_side = -1;//what sides we entry and leave through vms_vector dest_point; //where we are heading (center of exit_side) vms_angvec dest_angles; //where we want to be pointing vms_matrix dest_orient; int up_side=0; entry_side=0; //find new exit side if (!flydata->first_time) { entry_side = matt_find_connect_side(obj->segnum,old_player_seg); exit_side = Side_opposite[entry_side]; } if (flydata->first_time || entry_side==-1 || pseg->children[exit_side]==-1) exit_side = find_exit_side(obj); { //find closest side to align to fix d,largest_d=-f1_0; int i; for (i=0;i<6;i++) { #ifdef COMPACT_SEGS vms_vector v1; get_side_normal(pseg, i, 0, &v1 ); d = vm_vec_dot(&v1,&flydata->obj->orient.uvec); #else d = vm_vec_dot(&pseg->sides[i].normals[0],&flydata->obj->orient.uvec); #endif if (d > largest_d) {largest_d = d; up_side=i;} } } //update target point & angles compute_center_point_on_side(&dest_point,pseg,exit_side); //update target point and movement points //offset object sideways if (flydata->offset_frac) { int s0=-1,s1=0,i; vms_vector s0p,s1p; fix dist; for (i=0;i<6;i++) if (i!=entry_side && i!=exit_side && i!=up_side && i!=Side_opposite[up_side]) { if (s0==-1) s0 = i; else s1 = i; } compute_center_point_on_side(&s0p,pseg,s0); compute_center_point_on_side(&s1p,pseg,s1); dist = fixmul(vm_vec_dist(&s0p,&s1p),flydata->offset_frac); if (dist-flydata->offset_dist > MAX_SLIDE_PER_SEGMENT) dist = flydata->offset_dist + MAX_SLIDE_PER_SEGMENT; flydata->offset_dist = dist; vm_vec_scale_add2(&dest_point,&obj->orient.rvec,dist); } vm_vec_sub(&flydata->step,&dest_point,&obj->pos); step_size = vm_vec_normalize_quick(&flydata->step); vm_vec_scale(&flydata->step,flydata->speed); compute_segment_center(&curcenter,pseg); compute_segment_center(&nextcenter,&Segments[pseg->children[exit_side]]); vm_vec_sub(&flydata->headvec,&nextcenter,&curcenter); #ifdef COMPACT_SEGS { vms_vector _v1; get_side_normal(pseg, up_side, 0, &_v1 ); vm_vector_2_matrix(&dest_orient,&flydata->headvec,&_v1,NULL); } #else vm_vector_2_matrix(&dest_orient,&flydata->headvec,&pseg->sides[up_side].normals[0],NULL); #endif vm_extract_angles_matrix(&dest_angles,&dest_orient); if (flydata->first_time) vm_extract_angles_matrix(&flydata->angles,&obj->orient); seg_time = fixdiv(step_size,flydata->speed); //how long through seg if (seg_time) { flydata->angstep.x = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.p,dest_angles.p),seg_time))); flydata->angstep.z = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.b,dest_angles.b),seg_time))); flydata->angstep.y = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.h,dest_angles.h),seg_time))); } else { flydata->angles = dest_angles; flydata->angstep.x = flydata->angstep.y = flydata->angstep.z = 0; } } flydata->first_time=0; }
int GameZoomOut() { Render_zoom = fixmul(Render_zoom,68985); Update_flags |= UF_GAME_VIEW_CHANGED; return 1; }
int _do_slew_movement(object *obj, int check_keys, int check_joy ) { int moved = 0; vms_vector svel, movement; //scaled velocity (per this frame) vms_matrix rotmat,new_pm; int joy_x,joy_y,btns; int joyx_moved,joyy_moved; vms_angvec rotang; if (keyd_pressed[KEY_PAD5]) vm_vec_zero(&obj->phys_info.velocity); if (check_keys) { obj->phys_info.velocity.x += VEL_SPEED * (key_down_time(KEY_PAD9) - key_down_time(KEY_PAD7)); obj->phys_info.velocity.y += VEL_SPEED * (key_down_time(KEY_PADMINUS) - key_down_time(KEY_PADPLUS)); obj->phys_info.velocity.z += VEL_SPEED * (key_down_time(KEY_PAD8) - key_down_time(KEY_PAD2)); rotang.pitch = (key_down_time(KEY_LBRACKET) - key_down_time(KEY_RBRACKET))/ROT_SPEED; rotang.bank = (key_down_time(KEY_PAD1) - key_down_time(KEY_PAD3))/ROT_SPEED; rotang.head = (key_down_time(KEY_PAD6) - key_down_time(KEY_PAD4))/ROT_SPEED; } else rotang.pitch = rotang.bank = rotang.head = 0; //check for joystick movement if (check_joy && joy_present) { 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 (btns) if (!rotang.pitch) rotang.pitch = fixmul(-joy_y * 512,FrameTime); else; else if (joyy_moved) obj->phys_info.velocity.z = -joy_y * 8192; if (!rotang.head) rotang.head = fixmul(joy_x * 512,FrameTime); if (joyx_moved) old_joy_x = joy_x; if (joyy_moved) old_joy_y = joy_y; } moved = rotang.pitch | rotang.bank | rotang.head; vm_angles_2_matrix(&rotmat,&rotang); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; vm_transpose_matrix(&new_pm); //make those columns rows moved |= obj->phys_info.velocity.x | obj->phys_info.velocity.y | obj->phys_info.velocity.z; svel = obj->phys_info.velocity; vm_vec_scale(&svel,FrameTime); //movement in this frame vm_vec_rotate(&movement,&svel,&new_pm); vm_vec_add2(&obj->pos,&movement); moved |= (movement.x || movement.y || movement.z); return moved; }
//draws a bitmap with the specified 3d width & height //returns 1 if off screen, 0 if drew bool g3_draw_bitmap(vms_vector *pos,fix width,fix height,grs_bitmap *bm) { #ifndef __powerc g3s_point pnt; fix t,w,h; if (g3_rotate_point(&pnt,pos) & CC_BEHIND) return 1; g3_project_point(&pnt); if (pnt.p3_flags & PF_OVERFLOW) return 1; if (checkmuldiv(&t,width,Canv_w2,pnt.p3_z)) w = fixmul(t,Matrix_scale.x); else return 1; if (checkmuldiv(&t,height,Canv_h2,pnt.p3_z)) h = fixmul(t,Matrix_scale.y); else return 1; blob_vertices[0].x = pnt.p3_sx - w; blob_vertices[0].y = blob_vertices[1].y = pnt.p3_sy - h; blob_vertices[1].x = blob_vertices[2].x = pnt.p3_sx + w; blob_vertices[2].y = pnt.p3_sy + h; scale_bitmap(bm,blob_vertices,0); return 0; #else g3s_point pnt; fix w,h; double fz; if (g3_rotate_point(&pnt,pos) & CC_BEHIND) return 1; g3_project_point(&pnt); if (pnt.p3_flags & PF_OVERFLOW) return 1; if (pnt.p3_z == 0) return 1; fz = f2fl(pnt.p3_z); w = fixmul(fl2f(((f2fl(width)*fCanv_w2) / fz)), Matrix_scale.x); h = fixmul(fl2f(((f2fl(height)*fCanv_h2) / fz)), Matrix_scale.y); blob_vertices[0].x = pnt.p3_sx - w; blob_vertices[0].y = blob_vertices[1].y = pnt.p3_sy - h; blob_vertices[1].x = blob_vertices[2].x = pnt.p3_sx + w; blob_vertices[2].y = pnt.p3_sy + h; scale_bitmap(bm, blob_vertices, 0); return 0; #endif }
//returns bitmask of which angles are at dest. bits 0,1,2 = p,b,h int chase_angles(vms_angvec *cur_angles,vms_angvec *desired_angles) { vms_angvec delta_angs,alt_angles,alt_delta_angs; fix total_delta,alt_total_delta; fix frame_turn; int mask=0; delta_angs.p = desired_angles->p - cur_angles->p; delta_angs.h = desired_angles->h - cur_angles->h; delta_angs.b = desired_angles->b - cur_angles->b; total_delta = abs(delta_angs.p) + abs(delta_angs.b) + abs(delta_angs.h); alt_angles.p = f1_0/2 - cur_angles->p; alt_angles.b = cur_angles->b + f1_0/2; alt_angles.h = cur_angles->h + f1_0/2; alt_delta_angs.p = desired_angles->p - alt_angles.p; alt_delta_angs.h = desired_angles->h - alt_angles.h; alt_delta_angs.b = desired_angles->b - alt_angles.b; alt_total_delta = abs(alt_delta_angs.p) + abs(alt_delta_angs.b) + abs(alt_delta_angs.h); if (alt_total_delta < total_delta) { *cur_angles = alt_angles; delta_angs = alt_delta_angs; } frame_turn = fixmul(FrameTime,CHASE_TURN_RATE); if (abs(delta_angs.p) < frame_turn) { cur_angles->p = desired_angles->p; mask |= 1; } else if (delta_angs.p > 0) cur_angles->p += frame_turn; else cur_angles->p -= frame_turn; if (abs(delta_angs.b) < frame_turn) { cur_angles->b = desired_angles->b; mask |= 2; } else if (delta_angs.b > 0) cur_angles->b += frame_turn; else cur_angles->b -= frame_turn; //cur_angles->b = 0; if (abs(delta_angs.h) < frame_turn) { cur_angles->h = desired_angles->h; mask |= 4; } else if (delta_angs.h > 0) cur_angles->h += frame_turn; else cur_angles->h -= frame_turn; return mask; }
fix compute_dl_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy) { return fixmul(t->verts[bottom_vertex].l - t->verts[top_vertex].l, recip_dy); }
void do_endlevel_frame() { static fix timer; vms_vector save_last_pos; static fix explosion_wait1=0; static fix explosion_wait2=0; static fix bank_rate; static fix ext_expl_halflife; save_last_pos = ConsoleObject->last_pos; //don't let move code change this object_move_all(); ConsoleObject->last_pos = save_last_pos; if (ext_expl_playing) { external_explosion.lifeleft -= FrameTime; do_explosion_sequence(&external_explosion); if (external_explosion.lifeleft < ext_expl_halflife) mine_destroyed = 1; if (external_explosion.flags & OF_SHOULD_BE_DEAD) ext_expl_playing = 0; } if (cur_fly_speed != desired_fly_speed) { fix delta = desired_fly_speed - cur_fly_speed; fix frame_accel = fixmul(FrameTime,FLY_ACCEL); if (abs(delta) < frame_accel) cur_fly_speed = desired_fly_speed; else if (delta > 0) cur_fly_speed += frame_accel; else cur_fly_speed -= frame_accel; } //do big explosions if (!outside_mine) { if (Endlevel_sequence==EL_OUTSIDE) { vms_vector tvec; vm_vec_sub(&tvec,&ConsoleObject->pos,&mine_side_exit_point); if (vm_vec_dot(&tvec,&mine_exit_orient.fvec) > 0) { object *tobj; outside_mine = 1; tobj = object_create_explosion(exit_segnum,&mine_side_exit_point,i2f(50),VCLIP_BIG_PLAYER_EXPLOSION); if (tobj) { external_explosion = *tobj; tobj->flags |= OF_SHOULD_BE_DEAD; flash_scale = 0; //kill lights in mine ext_expl_halflife = tobj->lifeleft; ext_expl_playing = 1; } digi_link_sound_to_pos( SOUND_BIG_ENDLEVEL_EXPLOSION, exit_segnum, 0, &mine_side_exit_point, 0, i2f(3)/4 ); } } //do explosions chasing player if ((explosion_wait1-=FrameTime) < 0) { vms_vector tpnt; int segnum; object *expl; static int sound_count; vm_vec_scale_add(&tpnt,&ConsoleObject->pos,&ConsoleObject->orient.fvec,-ConsoleObject->size*5); vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.rvec,(d_rand()-D_RAND_MAX/2)*15); vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(d_rand()-D_RAND_MAX/2)*15); segnum = find_point_seg(&tpnt,ConsoleObject->segnum); if (segnum != -1) { expl = object_create_explosion(segnum,&tpnt,i2f(20),VCLIP_BIG_PLAYER_EXPLOSION); if (d_rand()<10000 || ++sound_count==7) { //pseudo-random digi_link_sound_to_pos( SOUND_TUNNEL_EXPLOSION, segnum, 0, &tpnt, 0, F1_0 ); sound_count=0; } } explosion_wait1 = 0x2000 + d_rand()/4; } } //do little explosions on walls if (Endlevel_sequence >= EL_FLYTHROUGH && Endlevel_sequence < EL_OUTSIDE) if ((explosion_wait2-=FrameTime) < 0) { vms_vector tpnt; fvi_query fq; fvi_info hit_data; //create little explosion on wall vm_vec_copy_scale(&tpnt,&ConsoleObject->orient.rvec,(d_rand()-D_RAND_MAX/2)*100); vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(d_rand()-D_RAND_MAX/2)*100); vm_vec_add2(&tpnt,&ConsoleObject->pos); if (Endlevel_sequence == EL_FLYTHROUGH) vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,d_rand()*200); else vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,d_rand()*60); //find hit point on wall fq.p0 = &ConsoleObject->pos; fq.p1 = &tpnt; fq.startseg = ConsoleObject->segnum; fq.rad = 0; fq.thisobjnum = 0; fq.ignore_obj_list = NULL; fq.flags = 0; find_vector_intersection(&fq,&hit_data); if (hit_data.hit_type==HIT_WALL && hit_data.hit_seg!=-1) object_create_explosion(hit_data.hit_seg,&hit_data.hit_pnt,i2f(3)+d_rand()*6,VCLIP_SMALL_EXPLOSION); explosion_wait2 = (0xa00 + d_rand()/8)/2; } switch (Endlevel_sequence) { case EL_OFF: return; case EL_FLYTHROUGH: { do_endlevel_flythrough(0); if (ConsoleObject->segnum == transition_segnum) { int objnum; Endlevel_sequence = EL_LOOKBACK; objnum = obj_create(OBJ_CAMERA, 0, ConsoleObject->segnum,&ConsoleObject->pos,&ConsoleObject->orient,0, CT_NONE,MT_NONE,RT_NONE); if (objnum == -1) { //can't get object, so abort con_printf(CON_DEBUG, "Can't get object for endlevel sequence. Aborting endlevel sequence.\n"); stop_endlevel_sequence(); return; } Viewer = endlevel_camera = &Objects[objnum]; select_cockpit(CM_LETTERBOX); fly_objects[1] = fly_objects[0]; fly_objects[1].obj = endlevel_camera; fly_objects[1].speed = (5*cur_fly_speed)/4; fly_objects[1].offset_frac = 0x4000; vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,i2f(7)); timer=0x20000; } break; } case EL_LOOKBACK: { do_endlevel_flythrough(0); do_endlevel_flythrough(1); if (timer>0) { timer -= FrameTime; if (timer < 0) //reduce speed fly_objects[1].speed = fly_objects[0].speed; } if (endlevel_camera->segnum == exit_segnum) { vms_angvec cam_angles,exit_seg_angles; Endlevel_sequence = EL_OUTSIDE; timer = i2f(2); vm_vec_negate(&endlevel_camera->orient.fvec); vm_vec_negate(&endlevel_camera->orient.rvec); vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient); vm_extract_angles_matrix(&exit_seg_angles,&mine_exit_orient); bank_rate = (-exit_seg_angles.b - cam_angles.b)/2; ConsoleObject->control_type = endlevel_camera->control_type = CT_NONE; //_MARK_("Starting outside");//Commented out by KRB #ifdef SLEW_ON slew_obj = endlevel_camera; #endif } break; } case EL_OUTSIDE: { #ifndef SLEW_ON vms_angvec cam_angles; #endif vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); #ifndef SLEW_ON vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,-2*cur_fly_speed)); vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.uvec,fixmul(FrameTime,-cur_fly_speed/10)); vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient); cam_angles.b += fixmul(bank_rate,FrameTime); vm_angles_2_matrix(&endlevel_camera->orient,&cam_angles); #endif timer -= FrameTime; if (timer < 0) { Endlevel_sequence = EL_STOPPED; vm_extract_angles_matrix(&player_angles,&ConsoleObject->orient); timer = i2f(3); } break; } case EL_STOPPED: { get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos); chase_angles(&player_angles,&player_dest_angles); vm_angles_2_matrix(&ConsoleObject->orient,&player_angles); vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); timer -= FrameTime; if (timer < 0) { #ifdef SLEW_ON slew_obj = endlevel_camera; _do_slew_movement(endlevel_camera,1,1); timer += FrameTime; //make time stop break; #else #ifdef SHORT_SEQUENCE stop_endlevel_sequence(); #else Endlevel_sequence = EL_PANNING; vm_extract_angles_matrix(&camera_cur_angles,&endlevel_camera->orient); timer = i2f(3); if (Game_mode & GM_MULTI) { // try to skip part of the seq if multiplayer stop_endlevel_sequence(); return; } #endif //SHORT_SEQUENCE #endif //SLEW_ON } break; } #ifndef SHORT_SEQUENCE case EL_PANNING: { #ifndef SLEW_ON int mask; #endif get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos); chase_angles(&player_angles,&player_dest_angles); vm_angles_2_matrix(&ConsoleObject->orient,&player_angles); vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); #ifdef SLEW_ON _do_slew_movement(endlevel_camera,1,1); #else get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos); mask = chase_angles(&camera_cur_angles,&camera_desired_angles); vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles); if ((mask&5) == 5) { vms_vector tvec; Endlevel_sequence = EL_CHASING; //_MARK_("Done outside");//Commented out -KRB vm_vec_normalized_dir_quick(&tvec,&station_pos,&ConsoleObject->pos); vm_vector_2_matrix(&ConsoleObject->orient,&tvec,&surface_orient.uvec,NULL); desired_fly_speed *= 2; } #endif break; } case EL_CHASING: { fix d,speed_scale; #ifdef SLEW_ON _do_slew_movement(endlevel_camera,1,1); #endif get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos); chase_angles(&camera_cur_angles,&camera_desired_angles); #ifndef SLEW_ON vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles); #endif d = vm_vec_dist_quick(&ConsoleObject->pos,&endlevel_camera->pos); speed_scale = fixdiv(d,i2f(0x20)); if (d<f1_0) d=f1_0; get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos); chase_angles(&player_angles,&player_dest_angles); vm_angles_2_matrix(&ConsoleObject->orient,&player_angles); vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); #ifndef SLEW_ON vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,fixmul(speed_scale,cur_fly_speed))); if (vm_vec_dist(&ConsoleObject->pos,&station_pos) < i2f(10)) stop_endlevel_sequence(); #endif break; } #endif //ifdef SHORT_SEQUENCE } }
fix compute_dz_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy) { return fixmul(t->verts[bottom_vertex].z - t->verts[top_vertex].z, recip_dy); }
void do_decloaking_wall_frame(int cloaking_wall_num) { cloaking_wall *d; wall *wfront,*wback; sbyte old_cloak; // for demo recording if ( Newdemo_state==ND_STATE_PLAYBACK ) return; d = &CloakingWalls[cloaking_wall_num]; wfront = &Walls[d->front_wallnum]; wback = (d->back_wallnum > -1) ? Walls + d->back_wallnum : NULL; old_cloak = wfront->cloak_value; d->time += FrameTime; if (d->time > CLOAKING_WALL_TIME) { int i; wfront->state = WALL_DOOR_CLOSED; if (wback) wback->state = WALL_DOOR_CLOSED; for (i=0;i<4;i++) { Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = d->front_ls[i]; if (wback) Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = d->back_ls[i]; } for (i=cloaking_wall_num;i<Num_cloaking_walls;i++) CloakingWalls[i] = CloakingWalls[i+1]; Num_cloaking_walls--; } else if (d->time > CLOAKING_WALL_TIME/2) { //fading in fix light_scale; int i; wfront->type = wback->type = WALL_CLOSED; light_scale = fixdiv(d->time-CLOAKING_WALL_TIME/2,CLOAKING_WALL_TIME/2); for (i=0;i<4;i++) { Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = fixmul(d->front_ls[i],light_scale); if (wback) Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = fixmul(d->back_ls[i],light_scale); } } else { //cloaking in wfront->cloak_value = ((CLOAKING_WALL_TIME/2 - d->time) * (GR_FADE_LEVELS-2)) / (CLOAKING_WALL_TIME/2); wfront->type = WALL_CLOAKED; if (wback) { wback->cloak_value = wfront->cloak_value; wback->type = WALL_CLOAKED; } } // check if the actual cloak_value changed in this frame to prevent redundant recordings and wasted bytes if ( Newdemo_state == ND_STATE_RECORDING && (wfront->cloak_value != old_cloak || d->time == FrameTime) ) newdemo_record_cloaking_wall(d->front_wallnum, d->back_wallnum, wfront->type, wfront->state, wfront->cloak_value, Segments[wfront->segnum].sides[wfront->sidenum].uvls[0].l, Segments[wfront->segnum].sides[wfront->sidenum].uvls[1].l, Segments[wfront->segnum].sides[wfront->sidenum].uvls[2].l, Segments[wfront->segnum].sides[wfront->sidenum].uvls[3].l); }
// ------------------------------------------------------------------------------------- // Render a texture map with lighting using perspective interpolation in inner and outer loops. // ------------------------------------------------------------------------------------- void ntexture_map_lighted(grs_bitmap *srcb, g3ds_tmap *t) { int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom int topy,boty,y, dy; fix dx_dy_left,dx_dy_right; fix du_dy_left,du_dy_right; fix dv_dy_left,dv_dy_right; fix dz_dy_left,dz_dy_right; fix dl_dy_left,dl_dy_right; fix recip_dyl, recip_dyr; int max_y_vertex; fix xleft,xright,uleft,vleft,uright,vright,zleft,zright,lleft,lright; int next_break_left, next_break_right; g3ds_vertex *v3d; //remove stupid warnings in compile dl_dy_left = F1_0; dl_dy_right = F1_0; lleft = F1_0; lright = F1_0; v3d = t->verts; // Determine top and bottom y coords. compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex); // Set top and bottom (of entire texture map) y coordinates. topy = f2i(v3d[vlt].y2d); boty = f2i(v3d[max_y_vertex].y2d); if (topy > Window_clip_bot) return; if (boty > Window_clip_bot) boty = Window_clip_bot; // Set amount to change x coordinate for each advance to next scanline. dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dyl = fix_recip[dy]; else recip_dyl = F1_0/dy; dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl); du_dy_left = compute_du_dy(t,vlt,vlb, recip_dyl); dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dyl); dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dyl); dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dyr = fix_recip[dy]; else recip_dyr = F1_0/dy; du_dy_right = compute_du_dy(t,vrt,vrb, recip_dyr); dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr); dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dyr); dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dyr); if (Lighting_enabled) { dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl); dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr); lleft = v3d[vlt].l; lright = v3d[vrt].l; } // Set initial values for x, u, v xleft = v3d[vlt].x2d; xright = v3d[vrt].x2d; zleft = v3d[vlt].z; zright = v3d[vrt].z; uleft = fixmul(v3d[vlt].u,zleft); uright = fixmul(v3d[vrt].u,zright); vleft = fixmul(v3d[vlt].v,zleft); vright = fixmul(v3d[vrt].v,zright); // scan all rows in texture map from top through first break. next_break_left = f2i(v3d[vlb].y2d); next_break_right = f2i(v3d[vrb].y2d); for (y = topy; y < boty; y++) { // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x,u,v if (y == next_break_left) { fix recip_dy; // Handle problem of double points. Search until y coord is different. Cannot get // hung in an infinite loop because we know there is a vertex with a lower y coordinate // because in the for loop, we don't scan all spanlines. while (y == f2i(v3d[vlb].y2d)) { vlt = vlb; vlb = prevmod(vlb,t->nv); } next_break_left = f2i(v3d[vlb].y2d); dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy); xleft = v3d[vlt].x2d; zleft = v3d[vlt].z; uleft = fixmul(v3d[vlt].u,zleft); vleft = fixmul(v3d[vlt].v,zleft); lleft = v3d[vlt].l; du_dy_left = compute_du_dy(t,vlt,vlb, recip_dy); dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dy); dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dy); if (Lighting_enabled) { dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy); lleft = v3d[vlt].l; } } // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x. Not necessary to set new values for u,v. if (y == next_break_right) { fix recip_dy; while (y == f2i(v3d[vrb].y2d)) { vrt = vrb; vrb = succmod(vrb,t->nv); } next_break_right = f2i(v3d[vrb].y2d); dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy); xright = v3d[vrt].x2d; zright = v3d[vrt].z; uright = fixmul(v3d[vrt].u,zright); vright = fixmul(v3d[vrt].v,zright); du_dy_right = compute_du_dy(t,vrt,vrb, recip_dy); dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dy); dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dy); if (Lighting_enabled) { dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy); lright = v3d[vrt].l; } } if (Lighting_enabled) { if (y >= Window_clip_top) ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright); lleft += dl_dy_left; lright += dl_dy_right; } else if (y >= Window_clip_top) ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright); uleft += du_dy_left; vleft += dv_dy_left; uright += du_dy_right; vright += dv_dy_right; xleft += dx_dy_left; xright += dx_dy_right; zleft += dz_dy_left; zright += dz_dy_right; } // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values, // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta. ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright); }
// Volume 0-F1_0 int digi_audio_start_sound(short soundnum, fix volume, int pan, int looping, int, int, int soundobj) { int i, starting_channel; if (!digi_initialised) return -1; if (soundnum < 0) return -1; SDL_LockAudio(); Assert(GameSounds[soundnum].data != (void *)-1); starting_channel = next_channel; while(1) { if (!SoundSlots[next_channel].playing) break; if (!SoundSlots[next_channel].persistent) break; // use this channel! next_channel++; if (next_channel >= digi_max_channels) next_channel = 0; if (next_channel == starting_channel) { SDL_UnlockAudio(); return -1; } } if (SoundSlots[next_channel].playing) { SoundSlots[next_channel].playing = 0; if (SoundSlots[next_channel].soundobj > -1) { digi_end_soundobj(SoundSlots[next_channel].soundobj); } if (SoundQ_channel == next_channel) SoundQ_end(); } #ifndef NDEBUG verify_sound_channel_free(next_channel); #endif SoundSlots[next_channel].soundno = soundnum; SoundSlots[next_channel].samples = GameSounds[soundnum].data; SoundSlots[next_channel].length = GameSounds[soundnum].length; SoundSlots[next_channel].volume = fixmul(digi_volume, volume); SoundSlots[next_channel].pan = pan; SoundSlots[next_channel].position = 0; SoundSlots[next_channel].looped = looping; SoundSlots[next_channel].playing = 1; SoundSlots[next_channel].soundobj = soundobj; SoundSlots[next_channel].persistent = 0; if ((soundobj > -1) || (looping) || (volume > F1_0)) SoundSlots[next_channel].persistent = 1; i = next_channel; next_channel++; if (next_channel >= digi_max_channels) next_channel = 0; SDL_UnlockAudio(); return i; }
void CODE_IN_IWRAM matrix_rotate_world(matrx_t m, int alp, int bet, int gam) { int cosalp = fixcos(alp); int sinalp = fixsin(alp); int cosbet = fixcos(bet); int sinbet = fixsin(bet); int cosgam = fixcos(gam); int singam = fixsin(gam); m[0][0] = fixmul(singam, fixmul(sinbet, sinalp)) + fixmul(cosgam, cosalp); m[0][1] = fixmul(cosbet, sinalp); m[0][2] = fixmul(singam, cosalp) - fixmul(cosgam, fixmul(sinbet, sinalp)); m[1][0] = fixmul(singam, fixmul(sinbet, cosalp)) - fixmul(cosgam, sinalp); m[1][1] = fixmul(cosbet, cosalp); m[1][2] = -fixmul(cosgam, fixmul(sinbet, cosalp)) - fixmul(singam, sinalp); m[2][0] = -fixmul(singam, cosbet); m[2][1] = sinbet; m[2][2] = fixmul(cosgam, cosbet); }
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; }