int rotate_object(short objnum, int p, int b, int h) { object *obj = &Objects[objnum]; vms_angvec ang; vms_matrix rotmat,tempm; // vm_extract_angles_matrix( &ang,&obj->orient); // ang.p += p; // ang.b += b; // ang.h += h; ang.p = p; ang.b = b; ang.h = h; vm_angles_2_matrix(&rotmat, &ang); vm_matrix_x_matrix(&tempm, &obj->orient, &rotmat); obj->orient = tempm; // vm_angles_2_matrix(&obj->orient, &ang); Update_flags |= UF_WORLD_CHANGED; return 1; }
//instance at specified point with specified orientation //if matrix==NULL, don't modify matrix. This will be like doing an offset void g3_start_instance_matrix(vms_vector *pos, vms_matrix *orient) { vms_vector tempv; vms_matrix tempm, tempm2; Assert(instance_depth<MAX_INSTANCE_DEPTH); instance_stack[instance_depth].m = View_matrix; instance_stack[instance_depth].p = View_position; instance_depth++; //step 1: subtract object position from view position vm_vec_sub(&tempv, &View_position, pos); if (orient) { //step 2: rotate view vector through object matrix vm_vec_rotate(&View_position, &tempv, orient); //step 3: rotate object matrix through view_matrix (vm = ob * vm) vm_copy_transpose_matrix(&tempm2, orient); vm_matrix_x_matrix(&tempm, &tempm2, &View_matrix); View_matrix = tempm; } }
void model_collide_preprocess_subobj(vec3d *pos, matrix *orient, polymodel *pm, polymodel_instance *pmi, int subobj_num) { submodel_instance *smi = &pmi->submodel[subobj_num]; smi->mc_base = *pos; smi->mc_orient = *orient; int i = pm->submodel[subobj_num].first_child; while ( i >= 0 ) { angles angs = pmi->submodel[i].angs; bsp_info * csm = &pm->submodel[i]; matrix tm = IDENTITY_MATRIX; vm_vec_unrotate(pos, &csm->offset, &smi->mc_orient ); vm_vec_add2(pos, &smi->mc_base); if( vm_matrix_same(&tm, &csm->orientation)) { // if submodel orientation matrix is identity matrix then don't bother with matrix ops vm_angles_2_matrix(&tm, &angs); } else { matrix rotation_matrix = csm->orientation; vm_rotate_matrix_by_angles(&rotation_matrix, &angs); matrix inv_orientation; vm_copy_transpose(&inv_orientation, &csm->orientation); vm_matrix_x_matrix(&tm, &rotation_matrix, &inv_orientation); } vm_matrix_x_matrix(orient, &smi->mc_orient, &tm); model_collide_preprocess_subobj(pos, orient, pm, pmi, i); i = csm->next_sibling; } }
void physics_sim_rot_editor(matrix * orient, physics_info * pi, float sim_time) { angles tangles; vec3d new_vel; matrix tmp; angles t1, t2; apply_physics( pi->rotdamp, pi->desired_rotvel.xyz.x, pi->rotvel.xyz.x, sim_time, &new_vel.xyz.x, NULL ); apply_physics( pi->rotdamp, pi->desired_rotvel.xyz.y, pi->rotvel.xyz.y, sim_time, &new_vel.xyz.y, NULL ); apply_physics( pi->rotdamp, pi->desired_rotvel.xyz.z, pi->rotvel.xyz.z, sim_time, &new_vel.xyz.z, NULL ); pi->rotvel = new_vel; tangles.p = pi->rotvel.xyz.x*sim_time; tangles.h = pi->rotvel.xyz.y*sim_time; tangles.b = pi->rotvel.xyz.z*sim_time; t1 = t2 = tangles; t1.h = 0.0f; t1.b = 0.0f; t2.p = 0.0f; t2.b = 0.0f; // put in p & b like normal vm_angles_2_matrix(&pi->last_rotmat, &t1 ); vm_matrix_x_matrix( &tmp, orient, &pi->last_rotmat ); // Put in heading separately vm_angles_2_matrix(&pi->last_rotmat, &t2 ); vm_matrix_x_matrix( orient, &pi->last_rotmat, &tmp ); vm_orthogonalize_matrix(orient); }
endlevel_render_mine(fix eye_offset) { int start_seg_num; Viewer_eye = Viewer->pos; if (Viewer->type == OBJ_PLAYER ) vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.fvec,(Viewer->size*3)/4); if (eye_offset) vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset); #ifdef EDITOR if (Function_mode==FMODE_EDITOR) Viewer_eye = Viewer->pos; #endif if (Endlevel_sequence >= EL_OUTSIDE) { start_seg_num = exit_segnum; } else { start_seg_num = find_point_seg(&Viewer_eye,Viewer->segnum); if (start_seg_num==-1) start_seg_num = Viewer->segnum; } if (Endlevel_sequence == EL_LOOKBACK) { vms_matrix headm,viewm; vms_angvec angles = {0,0,0x7fff}; vm_angles_2_matrix(&headm,&angles); vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm); g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom); } else g3_set_view_matrix(&Viewer_eye,&Viewer->orient,Render_zoom); render_mine(start_seg_num,eye_offset); }
static int rotate_object(const vobjptridx_t obj, int p, int b, int h) { vms_angvec ang; // vm_extract_angles_matrix( &ang,&obj->orient); // ang.p += p; // ang.b += b; // ang.h += h; ang.p = p; ang.b = b; ang.h = h; const auto rotmat = vm_angles_2_matrix(ang); obj->orient = vm_matrix_x_matrix(obj->orient, rotmat); // vm_angles_2_matrix(&obj->orient, &ang); Update_flags |= UF_WORLD_CHANGED; return 1; }
void camera::get_info(vec3d *position, matrix *orientation) { if(position == NULL && orientation == NULL) return; eye* eyep = NULL; vec3d host_normal; //POSITION if(!(flags & CAM_STATIONARY_POS) || object_host.IsValid()) { c_pos = vmd_zero_vector; vec3d pt; pos_x.get(&pt.xyz.x, NULL); pos_y.get(&pt.xyz.y, NULL); pos_z.get(&pt.xyz.z, NULL); if(object_host.IsValid()) { object *objp = object_host.objp; int model_num = object_get_model(objp); polymodel *pm = NULL; if(model_num > -1) { pm = model_get(model_num); } if(object_host_submodel < 0 || pm == NULL) { vm_vec_unrotate(&c_pos, &pt, &object_host.objp->orient); vm_vec_add2(&c_pos, &object_host.objp->pos); } else { eyep = get_submodel_eye(pm, object_host_submodel); if(eyep) { vec3d c_pos_in; find_submodel_instance_point_normal( &c_pos_in, &host_normal, objp, eyep->parent, &eyep->pnt, &eyep->norm); vm_vec_unrotate(&c_pos, &c_pos_in, &objp->orient); vm_vec_add2(&c_pos, &objp->pos); } else { model_find_world_point( &c_pos, &pt, pm->id, object_host_submodel, &objp->orient, &objp->pos ); } } } else { c_pos = pt; } //Do custom position stuff, if needed if(func_custom_position != NULL && !eyep) { func_custom_position(this, &c_pos); } } if(position != NULL) *position = c_pos; //ORIENTATION if(orientation != NULL) { bool target_set = false; if(!(flags & CAM_STATIONARY_ORI) || object_target.IsValid() || object_host.IsValid()) { if(object_target.IsValid()) { object *objp = object_target.objp; int model_num = object_get_model(objp); polymodel *pm = NULL; vec3d target_pos = vmd_zero_vector; //See if we can get the model if(model_num > -1) { pm = model_get(model_num); } //If we don't have a submodel or don't have the model use object pos //Otherwise, find the submodel pos as it is rotated if(object_target_submodel < 0 || pm == NULL) { target_pos = objp->pos; } else { model_find_world_point( &target_pos, &vmd_zero_vector, pm->id, object_target_submodel, &objp->orient, &objp->pos ); } vec3d targetvec; vm_vec_normalized_dir(&targetvec, &target_pos, &c_pos); vm_vector_2_matrix(&c_ori, &targetvec, NULL, NULL); target_set = true; } else if(object_host.IsValid()) { if(eyep) { vm_vector_2_matrix(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp->orient.vec.uvec)?NULL:&object_host.objp->orient.vec.uvec, NULL); target_set = true; } else { c_ori = object_host.objp->orient; } } else { c_ori = vmd_identity_matrix; } matrix mtxA = c_ori; matrix mtxB = IDENTITY_MATRIX; float pos = 0.0f; for(int i = 0; i < 9; i++) { ori[i].get(&pos, NULL); mtxB.a1d[i] = pos; } vm_matrix_x_matrix(&c_ori, &mtxA, &mtxB); vm_orthogonalize_matrix(&c_ori); } //Do custom orientation stuff, if needed if(func_custom_orientation != NULL && !target_set) { func_custom_orientation(this, &c_ori); } *orientation = c_ori; } }
void physics_sim_rot(matrix * orient, physics_info * pi, float sim_time ) { angles tangles; vec3d new_vel; matrix tmp; float shock_amplitude; float rotdamp; float shock_fraction_time_left; Assert(is_valid_matrix(orient)); Assert(is_valid_vec(&pi->rotvel)); Assert(is_valid_vec(&pi->desired_rotvel)); // Handle special case of shockwave shock_amplitude = 0.0f; if ( pi->flags & PF_IN_SHOCKWAVE ) { if ( timestamp_elapsed(pi->shockwave_decay) ) { pi->flags &= ~PF_IN_SHOCKWAVE; rotdamp = pi->rotdamp; } else { shock_fraction_time_left = timestamp_until( pi->shockwave_decay ) / (float) SW_BLAST_DURATION; rotdamp = pi->rotdamp + pi->rotdamp * (SW_ROT_FACTOR - 1) * shock_fraction_time_left; shock_amplitude = pi->shockwave_shake_amp * shock_fraction_time_left; } } else { rotdamp = pi->rotdamp; } // Do rotational physics with given damping apply_physics( rotdamp, pi->desired_rotvel.xyz.x, pi->rotvel.xyz.x, sim_time, &new_vel.xyz.x, NULL ); apply_physics( rotdamp, pi->desired_rotvel.xyz.y, pi->rotvel.xyz.y, sim_time, &new_vel.xyz.y, NULL ); apply_physics( rotdamp, pi->desired_rotvel.xyz.z, pi->rotvel.xyz.z, sim_time, &new_vel.xyz.z, NULL ); Assert(is_valid_vec(&new_vel)); pi->rotvel = new_vel; tangles.p = pi->rotvel.xyz.x*sim_time; tangles.h = pi->rotvel.xyz.y*sim_time; tangles.b = pi->rotvel.xyz.z*sim_time; /* // Make ship shake due to afterburner. if (pi->flags & PF_AFTERBURNER_ON || !timestamp_elapsed(pi->afterburner_decay) ) { float max_speed; max_speed = vm_vec_mag_quick(&pi->max_vel); tangles.p += (float) (rand()-RAND_MAX_2) * RAND_MAX_1f * pi->speed/max_speed/64.0f; tangles.h += (float) (rand()-RAND_MAX_2) * RAND_MAX_1f * pi->speed/max_speed/64.0f; if ( pi->flags & PF_AFTERBURNER_ON ) { pi->afterburner_decay = timestamp(ABURN_DECAY_TIME); } } */ // Make ship shake due to shockwave, decreasing in amplitude at the end of the shockwave if ( pi->flags & PF_IN_SHOCKWAVE ) { tangles.p += (float) (myrand()-RAND_MAX_2) * RAND_MAX_1f * shock_amplitude; tangles.h += (float) (myrand()-RAND_MAX_2) * RAND_MAX_1f * shock_amplitude; } vm_angles_2_matrix(&pi->last_rotmat, &tangles ); vm_matrix_x_matrix( &tmp, orient, &pi->last_rotmat ); *orient = tmp; vm_orthogonalize_matrix(orient); }
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 read_flying_controls( object * obj ) { //if ((Players[Player_num].spec_flags & PLAYER_FLAGS_SPECTATING) && (!in_free)) return; // jinx 02-01-13 spec fix forward_thrust_time; Assert(FrameTime > 0); //Get MATT if hit this! // this section commented and moved to the bottom by WraithX // if (Player_is_dead) { // vm_vec_zero(&obj->mtype.phys_info.rotthrust); // vm_vec_zero(&obj->mtype.phys_info.thrust); // return; // } // end of section to be moved. if (((obj->type!=OBJ_PLAYER) || (obj->id!=Player_num)) && (!(Players[Player_num].spec_flags & PLAYER_FLAGS_SPECTATING))) return; //references to player_ship require that this obj be the player // jinx 02-01-13 spec if (Guided_missile[Player_num] && Guided_missile[Player_num]->signature==Guided_missile_sig[Player_num]) { vms_angvec rotangs; vms_matrix rotmat,tempm; fix speed; //this is a horrible hack. guided missile stuff should not be //handled in the middle of a routine that is dealing with the player vm_vec_zero(&obj->mtype.phys_info.rotthrust); rotangs.p = Controls.pitch_time / 2 + Seismic_tremor_magnitude/64; rotangs.b = Controls.bank_time / 2 + Seismic_tremor_magnitude/16; rotangs.h = Controls.heading_time / 2 + Seismic_tremor_magnitude/64; vm_angles_2_matrix(&rotmat,&rotangs); vm_matrix_x_matrix(&tempm,&Guided_missile[Player_num]->orient,&rotmat); Guided_missile[Player_num]->orient = tempm; speed = Weapon_info[Guided_missile[Player_num]->id].speed[Difficulty_level]; vm_vec_copy_scale(&Guided_missile[Player_num]->mtype.phys_info.velocity,&Guided_missile[Player_num]->orient.fvec,speed); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_guided_info (Guided_missile[Player_num],0); #endif } else { obj->mtype.phys_info.rotthrust.x = Controls.pitch_time; obj->mtype.phys_info.rotthrust.y = Controls.heading_time; obj->mtype.phys_info.rotthrust.z = Controls.bank_time; } forward_thrust_time = Controls.forward_thrust_time; if ((Players[Player_num].flags & PLAYER_FLAGS_AFTERBURNER) || (Players[Player_num].spec_flags & PLAYER_FLAGS_SPECTATING)) // jinx 02-01-13 spec { if (Controls.afterburner_state) { //player has key down //if (forward_thrust_time >= 0) { //..and isn't moving backward { fix afterburner_scale; int old_count,new_count; //add in value from 0..1 afterburner_scale = f1_0 + min(f1_0/2,Afterburner_charge) * 2; forward_thrust_time = fixmul(FrameTime,afterburner_scale); //based on full thrust if (Players[Player_num].spec_flags & PLAYER_FLAGS_SPECTATING) forward_thrust_time *= 1.3; // jinx 01-25-13 spec old_count = (Afterburner_charge / (DROP_DELTA_TIME/AFTERBURNER_USE_SECS)); if (!(Players[Player_num].spec_flags & PLAYER_FLAGS_SPECTATING)) // jinx 01-25-13 spec Afterburner_charge -= FrameTime/AFTERBURNER_USE_SECS; if (Afterburner_charge < 0) Afterburner_charge = 0; new_count = (Afterburner_charge / (DROP_DELTA_TIME/AFTERBURNER_USE_SECS)); if (old_count != new_count) Drop_afterburner_blob_flag = 1; //drop blob (after physics called) } } else { fix cur_energy,charge_up; //charge up to full charge_up = min(FrameTime/8,f1_0 - Afterburner_charge); //recharge over 8 seconds cur_energy = max(Players[Player_num].energy-i2f(10),0); //don't drop below 10 //maybe limit charge up by energy charge_up = min(charge_up,cur_energy/10); Afterburner_charge += charge_up; if (!(Players[Player_num].spec_flags & PLAYER_FLAGS_SPECTATING)) // jinx 01-25-13 spec Players[Player_num].energy -= charge_up * 100 / 10; //full charge uses 10% of energy } } // Set object's thrust vector for forward/backward vm_vec_copy_scale(&obj->mtype.phys_info.thrust,&obj->orient.fvec, forward_thrust_time ); // slide left/right vm_vec_scale_add2(&obj->mtype.phys_info.thrust,&obj->orient.rvec, Controls.sideways_thrust_time ); // slide up/down vm_vec_scale_add2(&obj->mtype.phys_info.thrust,&obj->orient.uvec, Controls.vertical_thrust_time ); if (obj->mtype.phys_info.flags & PF_WIGGLE) { fix swiggle; fix_fastsincos(((fix)GameTime64), &swiggle, NULL); if (FrameTime < F1_0) // Only scale wiggle if getting at least 1 FPS, to avoid causing the opposite problem. swiggle = fixmul(swiggle*20, FrameTime); //make wiggle fps-independent (based on pre-scaled amount of wiggle at 20 FPS) vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&obj->orient.uvec,fixmul(swiggle,Player_ship->wiggle)); } // As of now, obj->mtype.phys_info.thrust & obj->mtype.phys_info.rotthrust are // in units of time... In other words, if thrust==FrameTime, that // means that the user was holding down the Max_thrust key for the // whole frame. So we just scale them up by the max, and divide by // FrameTime to make them independant of framerate // Prevent divide overflows on high frame rates. // In a signed divide, you get an overflow if num >= div<<15 { fix ft = FrameTime; // Note, you must check for ft < F1_0/2, else you can get an overflow on the << 15. if ((ft < F1_0/2) && (ft << 15 <= Player_ship->max_thrust)) { ft = (Player_ship->max_thrust >> 15) + 1; } vm_vec_scale( &obj->mtype.phys_info.thrust, fixdiv(Player_ship->max_thrust,ft) ); if ((ft < F1_0/2) && (ft << 15 <= Player_ship->max_rotthrust)) { ft = (Player_ship->max_thrust >> 15) + 1; }
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; } }
// ----------------------------------------------------------------------------------------------------------- // 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 { 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); } } //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); }
// Handler for the main editor dialog int editor_handler(UI_DIALOG *dlg, d_event *event, void *data) { editor_view *new_cv; int keypress = 0; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); else if (event->type == EVENT_WINDOW_CLOSE) { close_editor(); EditorWindow = NULL; return 0; } // Update the windows if (event->type == EVENT_UI_DIALOG_DRAW) { gr_set_curfont(editor_font); // Draw status box gr_set_current_canvas( NULL ); gr_setcolor( CGREY ); gr_rect(STATUS_X,STATUS_Y,STATUS_X+STATUS_W-1,STATUS_Y+STATUS_H-1); //0, 582, 799, 599 ); medlisp_update_screen(); calc_frame_time(); texpage_do(event); objpage_do(event); ui_pad_draw(EditorWindow, PAD_X, PAD_Y); print_status_bar(status_line); TimedAutosave(mine_filename); // shows the time, hence here set_editor_time_of_day(); return 1; } if ((selected_gadget == (UI_GADGET *)GameViewBox && !render_3d_in_big_window) || (selected_gadget == (UI_GADGET *)LargeViewBox && render_3d_in_big_window)) switch (event->type) { case EVENT_MOUSE_BUTTON_UP: case EVENT_MOUSE_BUTTON_DOWN: break; case EVENT_MOUSE_MOVED: if (!keyd_pressed[ KEY_LCTRL ] && !keyd_pressed[ KEY_RCTRL ]) break; case EVENT_JOYSTICK_BUTTON_UP: case EVENT_JOYSTICK_BUTTON_DOWN: case EVENT_JOYSTICK_MOVED: case EVENT_KEY_COMMAND: case EVENT_KEY_RELEASE: case EVENT_IDLE: kconfig_read_controls(event, 1); if (slew_frame(0)) { //do movement and check keys Update_flags |= UF_GAME_VIEW_CHANGED; if (Gameview_lockstep) { Cursegp = &Segments[ConsoleObject->segnum]; med_create_new_segment_from_cursegp(); Update_flags |= UF_ED_STATE_CHANGED; } rval = 1; } break; default: break; } //do non-essential stuff in idle event if (event->type == EVENT_IDLE) { check_wall_validity(); Assert(Num_walls>=0); if (Gameview_lockstep) { static segment *old_cursegp=NULL; static int old_curside=-1; if (old_cursegp!=Cursegp || old_curside!=Curside) { SetPlayerFromCursegMinusOne(); old_cursegp = Cursegp; old_curside = Curside; } } if ( event_get_idle_seconds() > COMPRESS_INTERVAL ) { med_compress_mine(); event_reset_idle_seconds(); } // Commented out because it occupies about 25% of time in twirling the mine. // Removes some Asserts.... // med_check_all_vertices(); clear_editor_status(); // if enough time elapsed, clear editor status message } gr_set_current_canvas( GameViewBox->canvas ); // Remove keys used for slew switch(keypress) { case KEY_PAD9: case KEY_PAD7: case KEY_PADPLUS: case KEY_PADMINUS: case KEY_PAD8: case KEY_PAD2: case KEY_LBRACKET: case KEY_RBRACKET: case KEY_PAD1: case KEY_PAD3: case KEY_PAD6: case KEY_PAD4: keypress = 0; } if ((keypress&0xff)==KEY_LSHIFT) keypress=0; if ((keypress&0xff)==KEY_RSHIFT) keypress=0; if ((keypress&0xff)==KEY_LCTRL) keypress=0; if ((keypress&0xff)==KEY_RCTRL) keypress=0; // if ((keypress&0xff)==KEY_LALT) keypress=0; // if ((keypress&0xff)==KEY_RALT) keypress=0; //=================== DO FUNCTIONS ==================== if ( KeyFunction[ keypress ] != NULL ) { KeyFunction[keypress](); keypress = 0; rval = 1; } switch (keypress) { case 0: case KEY_Z: case KEY_G: case KEY_LALT: case KEY_RALT: case KEY_LCTRL: case KEY_RCTRL: case KEY_LSHIFT: case KEY_RSHIFT: case KEY_LAPOSTRO: break; case KEY_SHIFTED + KEY_L: ToggleLighting(); rval = 1; break; case KEY_F1: render_3d_in_big_window = !render_3d_in_big_window; Update_flags |= UF_ALL; rval = 1; break; default: if (!rval) { char kdesc[100]; GetKeyDescription( kdesc, keypress ); editor_status_fmt("Error: %s isn't bound to anything.", kdesc ); } } //================================================================ if (ModeFlag) { ui_close_dialog(EditorWindow); return 0; } // if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)GameViewBox) current_view=NULL; // if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)GroupViewBox) current_view=NULL; new_cv = current_view; #if ORTHO_VIEWS if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)LargeViewBox) new_cv=&LargeView; if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)TopViewBox) new_cv=&TopView; if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)FrontViewBox) new_cv=&FrontView; if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)RightViewBox) new_cv=&RightView; #endif if (new_cv != current_view ) { current_view->ev_changed = 1; new_cv->ev_changed = 1; current_view = new_cv; } // DO TEXTURE STUFF if (texpage_do(event)) rval = 1; if (objpage_do(event)) rval = 1; // Process selection of Cursegp using mouse. if (GADGET_PRESSED(LargeViewBox) && !render_3d_in_big_window) { int xcrd,ycrd; xcrd = LargeViewBox->b1_drag_x1; ycrd = LargeViewBox->b1_drag_y1; find_segments(xcrd,ycrd,LargeViewBox->canvas,&LargeView,Cursegp,Big_depth); // Sets globals N_found_segs, Found_segs // If shift is down, then add segment to found list if (keyd_pressed[ KEY_LSHIFT ] || keyd_pressed[ KEY_RSHIFT ]) subtract_found_segments_from_selected_list(); else add_found_segments_to_selected_list(); Found_seg_index = 0; if (N_found_segs > 0) { sort_seg_list(N_found_segs,Found_segs,&ConsoleObject->pos); Cursegp = &Segments[Found_segs[0]]; med_create_new_segment_from_cursegp(); if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); } Update_flags |= UF_ED_STATE_CHANGED | UF_VIEWPOINT_MOVED; } if ((event->type == EVENT_UI_USERBOX_DRAGGED) && (ui_event_get_gadget(event) == (UI_GADGET *)GameViewBox)) { int x, y; x = GameViewBox->b1_drag_x2; y = GameViewBox->b1_drag_y2; gr_set_current_canvas( GameViewBox->canvas ); gr_setcolor( 15 ); gr_rect( x-1, y-1, x+1, y+1 ); } // Set current segment and side by clicking on a polygon in game window. // If ctrl pressed, also assign current texture map to that side. //if (GameViewBox->mouse_onme && (GameViewBox->b1_done_dragging || GameViewBox->b1_clicked)) { if ((GADGET_PRESSED(GameViewBox) && !render_3d_in_big_window) || (GADGET_PRESSED(LargeViewBox) && render_3d_in_big_window)) { int xcrd,ycrd; int seg,side,face,poly,tmap; if (render_3d_in_big_window) { xcrd = LargeViewBox->b1_drag_x1; ycrd = LargeViewBox->b1_drag_y1; } else { xcrd = GameViewBox->b1_drag_x1; ycrd = GameViewBox->b1_drag_y1; } //Int3(); if (find_seg_side_face(xcrd,ycrd,&seg,&side,&face,&poly)) { if (seg<0) { //found an object Cur_object_index = -seg-1; editor_status_fmt("Object %d selected.",Cur_object_index); Update_flags |= UF_ED_STATE_CHANGED; } else { // See if either shift key is down and, if so, assign texture map if (keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT]) { Cursegp = &Segments[seg]; Curside = side; AssignTexture(); med_create_new_segment_from_cursegp(); editor_status("Texture assigned"); } else if (keyd_pressed[KEY_G]) { tmap = Segments[seg].sides[side].tmap_num; texpage_grab_current(tmap); editor_status( "Texture grabbed." ); } else if (keyd_pressed[ KEY_LAPOSTRO] ) { move_object_to_mouse_click(); } else { Cursegp = &Segments[seg]; Curside = side; med_create_new_segment_from_cursegp(); editor_status("Curseg and curside selected"); } } Update_flags |= UF_ED_STATE_CHANGED; } else editor_status("Click on non-texture ingored"); } // Allow specification of LargeView using mouse if (event->type == EVENT_MOUSE_MOVED && (keyd_pressed[ KEY_LCTRL ] || keyd_pressed[ KEY_RCTRL ])) { int dx, dy, dz; event_mouse_get_delta(event, &dx, &dy, &dz); if ((dx != 0) && (dy != 0)) { vms_matrix MouseRotMat,tempm; GetMouseRotation( dx, dy, &MouseRotMat ); vm_matrix_x_matrix(&tempm,&LargeView.ev_matrix,&MouseRotMat); LargeView.ev_matrix = tempm; LargeView.ev_changed = 1; Large_view_index = -1; // say not one of the orthogonal views rval = 1; } } if (event->type == EVENT_MOUSE_MOVED) { int dx, dy, dz; event_mouse_get_delta(event, &dx, &dy, &dz); if (dz != 0) { current_view->ev_dist += dz*10000; current_view->ev_changed = 1; } } return rval; }
void HudGaugeReticle::getFirepointStatus() { //First, get the player ship ship_info* sip; ship* shipp; polymodel* pm; Assert(Objects[Player->objnum].type == OBJ_SHIP); if (Objects[Player->objnum].type == OBJ_SHIP) { shipp = &Ships[Objects[Player->objnum].instance]; sip = &Ship_info[shipp->ship_info_index]; //Get the player eyepoint pm = model_get(sip->model_num); if (pm->n_view_positions == 0) { mprintf(("Model %s does not have a defined eyepoint. Firepoint display could not be generated\n", pm->filename)); } else { if (pm->n_guns > 0) { eye eyepoint = pm->view_positions[shipp->current_viewpoint]; vec2d ep = { eyepoint.pnt.xyz.x, eyepoint.pnt.xyz.y }; for (int i = 0; i < pm->n_guns; i++) { int bankactive = 0; ship_weapon *swp = &shipp->weapons; if (!timestamp_elapsed(shipp->weapons.next_primary_fire_stamp[i])) bankactive = 1; else if (timestamp_elapsed(shipp->weapons.primary_animation_done_time[i])) bankactive = 1; else if (i == shipp->weapons.current_primary_bank || shipp->flags[Ship::Ship_Flags::Primary_linked]) bankactive = 2; int num_slots = pm->gun_banks[i].num_slots; for (int j = 0; j < num_slots; j++) { int fpactive = bankactive; if (sip->flags[Ship::Info_Flags::Dyn_primary_linking]) { // If this firepoint is not among the next shot(s) to be fired, dim it one step if ( !( (j >= (shipp->last_fired_point[i]+1) % num_slots) && (j <= (shipp->last_fired_point[i]+swp->primary_bank_slot_count[i]) % num_slots) ) ) { fpactive--; } } else if (Weapon_info[swp->primary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::Cycle]) { // If this firepoint is not the next one to be fired, dim it one step if (j != (shipp->last_fired_point[i]+1) % num_slots) { fpactive--; } } vec3d fpfromeye; matrix eye_orient, player_transpose; vm_copy_transpose(&player_transpose, &Objects[Player->objnum].orient); vm_matrix_x_matrix(&eye_orient, &player_transpose, &Eye_matrix); vm_vec_rotate(&fpfromeye, &pm->gun_banks[i].pnt[j], &eye_orient); firepoint tmp = { { fpfromeye.xyz.x - ep.x, ep.y - fpfromeye.xyz.y }, fpactive }; fp.push_back(tmp); } } } } } }
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; }
// function looks at the flying controls and the current velocity to determine a goal velocity // function determines velocity in object's reference frame and goal velocity in object's reference frame void physics_read_flying_controls( matrix * orient, physics_info * pi, control_info * ci, float sim_time, vec3d *wash_rot) { vec3d goal_vel; // goal velocity in local coords, *not* accounting for ramping of velcity float ramp_time_const; // time constant for velocity ramping // apply throttle, unless reverse thrusters are held down if (ci->forward != -1.0f) ci->forward += (ci->forward_cruise_percent / 100.0f); // give control input to cause rotation in engine wash extern int Wash_on; if ( wash_rot && Wash_on ) { ci->pitch += wash_rot->xyz.x; ci->bank += wash_rot->xyz.z; ci->heading += wash_rot->xyz.y; } if (ci->pitch > 1.0f ) ci->pitch = 1.0f; else if (ci->pitch < -1.0f ) ci->pitch = -1.0f; if (ci->vertical > 1.0f ) ci->vertical = 1.0f; else if (ci->vertical < -1.0f ) ci->vertical = -1.0f; if (ci->heading > 1.0f ) ci->heading = 1.0f; else if (ci->heading < -1.0f ) ci->heading = -1.0f; if (ci->sideways > 1.0f ) ci->sideways = 1.0f; else if (ci->sideways < -1.0f ) ci->sideways = -1.0f; if (ci->bank > 1.0f ) ci->bank = 1.0f; else if (ci->bank < -1.0f ) ci->bank = -1.0f; if ( pi->flags & PF_AFTERBURNER_ON ){ //SparK: modifield to accept reverse burners if (!(pi->afterburner_max_reverse_vel > 0.0f)){ ci->forward = 1.0f; } } if (ci->forward > 1.0f ) ci->forward = 1.0f; else if (ci->forward < -1.0f ) ci->forward = -1.0f; if (!Flight_controls_follow_eyepoint_orientation || (Player_obj == NULL) || (Player_obj->type != OBJ_SHIP)) { // Default behavior; eyepoint orientation has no effect on controls pi->desired_rotvel.xyz.x = ci->pitch * pi->max_rotvel.xyz.x; pi->desired_rotvel.xyz.y = ci->heading * pi->max_rotvel.xyz.y; } else { // Optional behavior; pitch and yaw are always relative to the eyepoint // orientation (excluding slew) vec3d tmp_vec, new_rotvel; matrix tmp_mat, eyemat, rotvelmat; ship_get_eye(&tmp_vec, &eyemat, Player_obj, false); vm_copy_transpose_matrix(&tmp_mat, &Player_obj->orient); vm_matrix_x_matrix(&rotvelmat, &tmp_mat, &eyemat); vm_vec_rotate(&new_rotvel, &pi->max_rotvel, &rotvelmat); vm_vec_unrotate(&tmp_vec, &pi->max_rotvel, &rotvelmat); new_rotvel.xyz.x = tmp_vec.xyz.x; new_rotvel.xyz.x = ci->pitch * new_rotvel.xyz.x; new_rotvel.xyz.y = ci->heading * new_rotvel.xyz.y; vm_vec_unrotate(&tmp_vec, &new_rotvel, &rotvelmat); pi->desired_rotvel = tmp_vec; } float delta_bank; #ifdef BANK_WHEN_TURN // To change direction of bank, negate the whole expression. // To increase magnitude of banking, decrease denominator. // Adam: The following statement is all the math for banking while turning. delta_bank = - (ci->heading * pi->max_rotvel.xyz.y) * pi->delta_bank_const; #else delta_bank = 0.0f; #endif pi->desired_rotvel.xyz.z = ci->bank * pi->max_rotvel.xyz.z + delta_bank; pi->forward_thrust = ci->forward; pi->vert_thrust = ci->vertical; //added these two in order to get side and forward thrusters pi->side_thrust = ci->sideways; //to glow brighter when the ship is moving in the right direction -Bobboau if ( pi->flags & PF_AFTERBURNER_ON ) { goal_vel.xyz.x = ci->sideways*pi->afterburner_max_vel.xyz.x; goal_vel.xyz.y = ci->vertical*pi->afterburner_max_vel.xyz.y; if(ci->forward < 0.0f) goal_vel.xyz.z = ci->forward* pi->afterburner_max_reverse_vel; else goal_vel.xyz.z = ci->forward* pi->afterburner_max_vel.xyz.z; } else if ( pi->flags & PF_BOOSTER_ON ) { goal_vel.xyz.x = ci->sideways*pi->booster_max_vel.xyz.x; goal_vel.xyz.y = ci->vertical*pi->booster_max_vel.xyz.y; goal_vel.xyz.z = ci->forward* pi->booster_max_vel.xyz.z; } else { goal_vel.xyz.x = ci->sideways*pi->max_vel.xyz.x; goal_vel.xyz.y = ci->vertical*pi->max_vel.xyz.y; goal_vel.xyz.z = ci->forward* pi->max_vel.xyz.z; } if ( goal_vel.xyz.z < -pi->max_rear_vel && !(pi->flags & PF_AFTERBURNER_ON) ) goal_vel.xyz.z = -pi->max_rear_vel; if ( pi->flags & PF_ACCELERATES ) { // // Determine *resultant* DESIRED VELOCITY (desired_vel) accounting for RAMPING of velocity // Use LOCAL coordinates // if slide_enabled, ramp velocity for x and y, otherwise set goal (0) // always ramp velocity for z // // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast. // Scale according to reduced_damp_time_expansion. float reduced_damp_ramp_time_expansion; if ( pi->flags & PF_REDUCED_DAMP && !timestamp_elapsed(pi->reduced_damp_decay) ) { float reduced_damp_fraction_time_left = timestamp_until( pi->reduced_damp_decay ) / (float) REDUCED_DAMP_TIME; reduced_damp_ramp_time_expansion = 1.0f + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left; } else { reduced_damp_ramp_time_expansion = 1.0f; } if (pi->flags & PF_SLIDE_ENABLED) { // determine the local velocity // deterimine whether accelerating or decleration toward goal for x if ( goal_vel.xyz.x > 0.0f ) { if ( goal_vel.xyz.x >= pi->prev_ramp_vel.xyz.x ) ramp_time_const = pi->slide_accel_time_const; else ramp_time_const = pi->slide_decel_time_const; } else if ( goal_vel.xyz.x < 0.0f ) { if ( goal_vel.xyz.x <= pi->prev_ramp_vel.xyz.x ) ramp_time_const = pi->slide_accel_time_const; else ramp_time_const = pi->slide_decel_time_const; } else { ramp_time_const = pi->slide_decel_time_const; } // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast if ( pi->flags & PF_REDUCED_DAMP ) { ramp_time_const *= reduced_damp_ramp_time_expansion; } pi->prev_ramp_vel.xyz.x = velocity_ramp(pi->prev_ramp_vel.xyz.x, goal_vel.xyz.x, ramp_time_const, sim_time); // deterimine whether accelerating or decleration toward goal for y if ( goal_vel.xyz.y > 0.0f ) { if ( goal_vel.xyz.y >= pi->prev_ramp_vel.xyz.y ) ramp_time_const = pi->slide_accel_time_const; else ramp_time_const = pi->slide_decel_time_const; } else if ( goal_vel.xyz.y < 0.0f ) { if ( goal_vel.xyz.y <= pi->prev_ramp_vel.xyz.y ) ramp_time_const = pi->slide_accel_time_const; else ramp_time_const = pi->slide_decel_time_const; } else { ramp_time_const = pi->slide_decel_time_const; } // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast if ( pi->flags & PF_REDUCED_DAMP ) { ramp_time_const *= reduced_damp_ramp_time_expansion; } pi->prev_ramp_vel.xyz.y = velocity_ramp( pi->prev_ramp_vel.xyz.y, goal_vel.xyz.y, ramp_time_const, sim_time); } else { // slide not enabled pi->prev_ramp_vel.xyz.x = 0.0f; pi->prev_ramp_vel.xyz.y = 0.0f; } // deterimine whether accelerating or decleration toward goal for z if ( goal_vel.xyz.z > 0.0f ) { if ( goal_vel.xyz.z >= pi->prev_ramp_vel.xyz.z ) { if ( pi->flags & PF_AFTERBURNER_ON ) ramp_time_const = pi->afterburner_forward_accel_time_const; else if (pi->flags & PF_BOOSTER_ON) ramp_time_const = pi->booster_forward_accel_time_const; else ramp_time_const = pi->forward_accel_time_const; } else { ramp_time_const = pi->forward_decel_time_const; } } else if ( goal_vel.xyz.z < 0.0f ) { if ( pi->flags & PF_AFTERBURNER_ON ) ramp_time_const = pi->afterburner_reverse_accel; else ramp_time_const = pi->forward_decel_time_const; } else { ramp_time_const = pi->forward_decel_time_const; } // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast if ( pi->flags & PF_REDUCED_DAMP ) { ramp_time_const *= reduced_damp_ramp_time_expansion; } pi->prev_ramp_vel.xyz.z = velocity_ramp(pi->prev_ramp_vel.xyz.z, goal_vel.xyz.z, ramp_time_const, sim_time); //Deternine the current dynamic glide cap, and ramp to it //This is outside the normal "glide" block since we want the cap to adjust whether or not the ship is in glide mode float dynamic_glide_cap_goal = 0.0; if (pi->flags & PF_AFTERBURNER_ON) { dynamic_glide_cap_goal = ( goal_vel.xyz.z >= 0.0f ) ? pi->afterburner_max_vel.xyz.z : pi->afterburner_max_reverse_vel; } else { //Use the maximum value in X, Y, and Z (including overclocking) dynamic_glide_cap_goal = MAX(MAX(pi->max_vel.xyz.x,pi->max_vel.xyz.y), pi->max_vel.xyz.z); } pi->cur_glide_cap = velocity_ramp(pi->cur_glide_cap, dynamic_glide_cap_goal, ramp_time_const, sim_time); if ( (pi->flags & PF_GLIDING) || (pi->flags & PF_FORCE_GLIDE ) ) { pi->desired_vel = pi->vel; //SUSHI: A (hopefully better) approach to dealing with accelerations in glide mode //Get *actual* current velocities along each axis and use those instead of ramped velocities vec3d local_vel; vm_vec_rotate(&local_vel, &pi->vel, orient); //Having pi->glide_cap == 0 means we're using a dynamic glide cap float curGlideCap = 0.0f; if (pi->glide_cap == 0.0f) curGlideCap = pi->cur_glide_cap; else curGlideCap = pi->glide_cap; //If we're near the (positive) glide cap, decay velocity where we aren't thrusting //This is a hack, but makes the flight feel a lot smoother //Don't do this if we aren't applying any thrust, we have no glide cap, or the accel multiplier is 0 (no thrust while gliding) float cap_decay_threshold = 0.95f; float cap_decay_amount = 0.2f; if (curGlideCap >= 0.0f && vm_vec_mag(&pi->desired_vel) >= cap_decay_threshold * curGlideCap && vm_vec_mag(&goal_vel) > 0.0f && pi->glide_accel_mult != 0.0f) { if (goal_vel.xyz.x == 0.0f) vm_vec_scale_add2(&pi->desired_vel, &orient->vec.rvec, -cap_decay_amount * local_vel.xyz.x); if (goal_vel.xyz.y == 0.0f) vm_vec_scale_add2(&pi->desired_vel, &orient->vec.uvec, -cap_decay_amount * local_vel.xyz.y); if (goal_vel.xyz.z == 0.0f) vm_vec_scale_add2(&pi->desired_vel, &orient->vec.fvec, -cap_decay_amount * local_vel.xyz.z); } //The glide_ramp function uses (basically) the same math as the velocity ramp so that thruster power is consistent //Only ramp if the glide cap is positive float xVal = glide_ramp(local_vel.xyz.x, goal_vel.xyz.x, pi->slide_accel_time_const, pi->glide_accel_mult, sim_time); float yVal = glide_ramp(local_vel.xyz.y, goal_vel.xyz.y, pi->slide_accel_time_const, pi->glide_accel_mult, sim_time); float zVal = 0.0; if (pi->flags & PF_AFTERBURNER_ON) zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->afterburner_forward_accel_time_const, pi->glide_accel_mult, sim_time); else { if (goal_vel.xyz.z >= 0.0f) zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->forward_accel_time_const, pi->glide_accel_mult, sim_time); else zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->forward_decel_time_const, pi->glide_accel_mult, sim_time); } //Compensate for effect of dampening: normal flight cheats here, so /we make up for it this way so glide acts the same way xVal *= pi->side_slip_time_const / sim_time; yVal *= pi->side_slip_time_const / sim_time; if (pi->use_newtonian_damp) zVal *= pi->side_slip_time_const / sim_time; vm_vec_scale_add2(&pi->desired_vel, &orient->vec.fvec, zVal); vm_vec_scale_add2(&pi->desired_vel, &orient->vec.rvec, xVal); vm_vec_scale_add2(&pi->desired_vel, &orient->vec.uvec, yVal); // Only do the glide cap if we have one and are actively thrusting in some direction. if ( curGlideCap >= 0.0f && (ci->forward != 0.0f || ci->sideways != 0.0f || ci->vertical != 0.0f) ) { float currentmag = vm_vec_mag(&pi->desired_vel); if ( currentmag > curGlideCap ) { vm_vec_scale( &pi->desired_vel, curGlideCap / currentmag ); } } } else { // this translates local desired velocities to world velocities vm_vec_zero(&pi->desired_vel); vm_vec_scale_add2( &pi->desired_vel, &orient->vec.rvec, pi->prev_ramp_vel.xyz.x ); vm_vec_scale_add2( &pi->desired_vel, &orient->vec.uvec, pi->prev_ramp_vel.xyz.y ); vm_vec_scale_add2( &pi->desired_vel, &orient->vec.fvec, pi->prev_ramp_vel.xyz.z ); } } else // object does not accelerate (PF_ACCELERATES not set) pi->desired_vel = pi->vel; }
// This function recursively checks a submodel and its children // for a collision with a vector. void mc_check_subobj( int mn ) { vec3d tempv; vec3d hitpt; // used in bounding box check bsp_info * sm; int i; Assert( mn >= 0 ); Assert( mn < Mc_pm->n_models ); if ( (mn < 0) || (mn>=Mc_pm->n_models) ) return; sm = &Mc_pm->submodel[mn]; if (sm->no_collisions) return; // don't do collisions if (sm->nocollide_this_only) goto NoHit; // Don't collide for this model, but keep checking others // Rotate the world check points into the current subobject's // frame of reference. // After this block, Mc_p0, Mc_p1, Mc_direction, and Mc_mag are correct // and relative to this subobjects' frame of reference. vm_vec_sub(&tempv, Mc->p0, &Mc_base); vm_vec_rotate(&Mc_p0, &tempv, &Mc_orient); vm_vec_sub(&tempv, Mc->p1, &Mc_base); vm_vec_rotate(&Mc_p1, &tempv, &Mc_orient); vm_vec_sub(&Mc_direction, &Mc_p1, &Mc_p0); // bail early if no ray exists if ( IS_VEC_NULL(&Mc_direction) ) { return; } if (Mc_pm->detail[0] == mn) { // Quickly bail if we aren't inside the full model bbox if (!mc_ray_boundingbox( &Mc_pm->mins, &Mc_pm->maxs, &Mc_p0, &Mc_direction, NULL)) { return; } // If we are checking the root submodel, then we might want to check // the shield at this point if ((Mc->flags & MC_CHECK_SHIELD) && (Mc_pm->shield.ntris > 0 )) { mc_check_shield(); return; } } if (!(Mc->flags & MC_CHECK_MODEL)) { return; } Mc_submodel = mn; // Check if the ray intersects this subobject's bounding box if ( mc_ray_boundingbox(&sm->min, &sm->max, &Mc_p0, &Mc_direction, &hitpt) ) { if (Mc->flags & MC_ONLY_BOUND_BOX) { float dist = vm_vec_dist( &Mc_p0, &hitpt ); // If the ray is behind the plane there is no collision if (dist < 0.0f) { goto NoHit; } // The ray isn't long enough to intersect the plane if ( !(Mc->flags & MC_CHECK_RAY) && (dist > Mc_mag) ) { goto NoHit; } // If the ray hits, but a closer intersection has already been found, return if ( Mc->num_hits && (dist >= Mc->hit_dist) ) { goto NoHit; } Mc->hit_dist = dist; Mc->hit_point = hitpt; Mc->hit_submodel = Mc_submodel; Mc->hit_bitmap = -1; Mc->num_hits++; } else { // The ray intersects this bounding box, so we have to check all the // polygons in this submodel. if ( Cmdline_old_collision_sys ) { model_collide_sub(sm->bsp_data); } else { if (Mc->lod > 0 && sm->num_details > 0) { bsp_info *lod_sm = sm; for (i = Mc->lod - 1; i >= 0; i--) { if (sm->details[i] != -1) { lod_sm = &Mc_pm->submodel[sm->details[i]]; //mprintf(("Checking %s collision for %s using %s instead\n", Mc_pm->filename, sm->name, lod_sm->name)); break; } } model_collide_bsp(model_get_bsp_collision_tree(lod_sm->collision_tree_index), 0); } else { model_collide_bsp(model_get_bsp_collision_tree(sm->collision_tree_index), 0); } } } } NoHit: // If we're only checking one submodel, return if (Mc->flags & MC_SUBMODEL) { return; } // If this subobject doesn't have any children, we're done checking it. if ( sm->num_children < 1 ) return; // Save instance (Mc_orient, Mc_base, Mc_point_base) matrix saved_orient = Mc_orient; vec3d saved_base = Mc_base; // Check all of this subobject's children i = sm->first_child; while ( i >= 0 ) { angles angs; bool blown_off; bool collision_checked; bsp_info * csm = &Mc_pm->submodel[i]; if ( Mc_pmi ) { angs = Mc_pmi->submodel[i].angs; blown_off = Mc_pmi->submodel[i].blown_off; collision_checked = Mc_pmi->submodel[i].collision_checked; } else { angs = csm->angs; blown_off = csm->blown_off ? true : false; collision_checked = false; } // Don't check it or its children if it is destroyed // or if it's set to no collision if ( !blown_off && !collision_checked && !csm->no_collisions ) { if ( Mc_pmi ) { Mc_orient = Mc_pmi->submodel[i].mc_orient; Mc_base = Mc_pmi->submodel[i].mc_base; vm_vec_add2(&Mc_base, Mc->pos); } else { //instance for this subobject matrix tm = IDENTITY_MATRIX; vm_vec_unrotate(&Mc_base, &csm->offset, &saved_orient ); vm_vec_add2(&Mc_base, &saved_base ); if( vm_matrix_same(&tm, &csm->orientation)) { // if submodel orientation matrix is identity matrix then don't bother with matrix ops vm_angles_2_matrix(&tm, &angs); } else { matrix rotation_matrix = csm->orientation; vm_rotate_matrix_by_angles(&rotation_matrix, &angs); matrix inv_orientation; vm_copy_transpose(&inv_orientation, &csm->orientation); vm_matrix_x_matrix(&tm, &rotation_matrix, &inv_orientation); } vm_matrix_x_matrix(&Mc_orient, &saved_orient, &tm); } mc_check_subobj( i ); } i = csm->next_sibling; } }
int do_slew_movement(object *obj, int check_keys ) { int moved = 0; vms_vector svel, movement; //scaled velocity (per this frame) vms_matrix rotmat,new_pm; vms_angvec rotang; if (!slew_obj || slew_obj->control_type!=CT_SLEW) return 0; if (check_keys) { #if 0 //def EDITOR // might be useful for people with playing keys set to modifiers or such, if (EditorWindow) // or just use a separate player file for the editor { obj->mtype.phys_info.velocity.x += SLIDE_SPEED * keyd_pressed[KEY_PAD9] * FrameTime; obj->mtype.phys_info.velocity.x -= SLIDE_SPEED * keyd_pressed[KEY_PAD7] * FrameTime; obj->mtype.phys_info.velocity.y += SLIDE_SPEED * keyd_pressed[KEY_PADMINUS] * FrameTime; obj->mtype.phys_info.velocity.y -= SLIDE_SPEED * keyd_pressed[KEY_PADPLUS] * FrameTime; obj->mtype.phys_info.velocity.z += ZOOM_SPEED_FACTOR * keyd_pressed[KEY_PAD8] * FrameTime; obj->mtype.phys_info.velocity.z -= ZOOM_SPEED_FACTOR * keyd_pressed[KEY_PAD2] * FrameTime; rotang.p = rotang.b = rotang.h = 0; rotang.p += keyd_pressed[KEY_LBRACKET] * FrameTime / ROT_SPEED; rotang.p -= keyd_pressed[KEY_RBRACKET] * FrameTime / ROT_SPEED; rotang.b += keyd_pressed[KEY_PAD1] * FrameTime / ROT_SPEED; rotang.b -= keyd_pressed[KEY_PAD3] * FrameTime / ROT_SPEED; rotang.h += keyd_pressed[KEY_PAD6] * FrameTime / ROT_SPEED; rotang.h -= keyd_pressed[KEY_PAD4] * FrameTime / ROT_SPEED; } else #endif { obj->mtype.phys_info.velocity.x = SLIDE_SPEED * Controls.sideways_thrust_time; obj->mtype.phys_info.velocity.y = SLIDE_SPEED * Controls.vertical_thrust_time; obj->mtype.phys_info.velocity.z = ZOOM_SPEED_FACTOR * 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; 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; }
void modex_print_message(int x, int y, char *str) { #ifndef AUTOMAP_DIRECT_RENDER #ifndef AUTOMAP_NO_PAGING int i; for (i=0; i<2; i++ ) { gr_set_current_canvas(&Pages[i]); #else { gr_set_current_canvas(OffscreenPage); #endif #endif modex_printf(x, y, str, GFONT_MEDIUM_1); #ifndef AUTOMAP_DIRECT_RENDER } gr_set_current_canvas(&DrawingPages[current_page]); #endif } extern void GameLoop(int, int ); extern int set_segment_depths(int start_seg, ubyte *segbuf); u_int32_t automap_mode = SM(640,480); int automap_width = 640; int automap_height = 480; int automap_use_game_res=0; int nice_automap=0; void do_automap( int key_code ) { int done=0; vms_matrix tempm; vms_angvec tangles; int leave_mode=0; int first_time=1; // int pcx_error; int c; // char filename[] = "MAP.PCX"; fix entry_time; int pause_game=1; // Set to 1 if everything is paused during automap...No pause during net. fix t1, t2; control_info saved_control_info; grs_bitmap Automap_background; int Max_segments_away = 0; int SegmentLimit = 1; //added on 10/28/98 by adb to fix compile versions #if !defined (NDEBUG) || (!defined(AUTOMAP_NO_PAGING) && !defined(AUTOMAP_DIRECT_RENDER)) int i; #endif key_code = key_code; // disable warning... if ((Game_mode & GM_MULTI) && (Function_mode == FMODE_GAME) && (!Endlevel_sequence)) pause_game = 0; if (pause_game) stop_time(); create_name_canv(); Max_edges = min(MAX_EDGES_FROM_VERTS(Num_vertices),MAX_EDGES); //make maybe smaller than max //Edges = malloc( sizeof(Edge_info)*Max_edges); //if ( Edges == NULL ) { // mprintf((0, "Couldn't get %dK for automap!", sizeof(Edge_info)*Max_edges/1024)); // return; //} //DrawingListBright = malloc( sizeof(short)*Max_edges); //if ( DrawingListBright == NULL ) { // mprintf((0, "Couldn't get %dK for automap!", sizeof(short)*Max_edges/1024)); // return; //} mprintf( (0, "Num_vertices=%d, Max_edges=%d, (MAX:%d)\n", Num_vertices, Max_edges, MAX_EDGES )); mprintf( (0, "Allocated %d K for automap edge list\n", (sizeof(Edge_info)+sizeof(short))*Max_edges/1024 )); //edit 4/23/99 Matt Mueller - don't switch res unless we need to if (grd_curscreen->sc_mode != AUTOMAP_MODE) gr_set_mode( AUTOMAP_MODE ); else gr_set_current_canvas(NULL); //end edit -MM automap_width=grd_curscreen->sc_canvas.cv_bitmap.bm_w; automap_height=grd_curscreen->sc_canvas.cv_bitmap.bm_h; gr_palette_clear(); #ifndef AUTOMAP_DIRECT_RENDER gr_init_sub_canvas(&Pages[0],grd_curcanv,0,0,automap_width,automap_height); #ifndef AUTOMAP_NO_PAGING // NOTICE: should be 0,401! FIXME! gr_init_sub_canvas(&Pages[1],grd_curcanv,0,0,automap_width,automap_height); gr_init_sub_canvas(&DrawingPages[0],&Pages[0],0,0,automap_width,automap_height); gr_init_sub_canvas(&DrawingPages[1],&Pages[1],0,0,automap_width,automap_height); #else OffscreenPage = gr_create_canvas( automap_width,automap_height ); if (!OffscreenPage) { nm_messagebox("No memory for automap", 1, "Ok"); return; } gr_init_sub_canvas(&DrawingPages[0],OffscreenPage,0,0,automap_width,automap_height); #endif #endif gr_init_bitmap_data (&Automap_background); // pcx_error = pcx_read_bitmap(filename,&Automap_background,BM_LINEAR,NULL); // if ( pcx_error != PCX_ERROR_NONE ) { // printf("File %s - PCX error: %s",filename,pcx_errormsg(pcx_error)); // Error("File %s - PCX error: %s",filename,pcx_errormsg(pcx_error)); // return; // } #ifndef AUTOMAP_DIRECT_RENDER #ifndef AUTOMAP_NO_PAGING for (i=0; i<2; i++ ) { gr_set_current_canvas(&Pages[i]); #else { gr_set_current_canvas(OffscreenPage); #endif // gr_bitmap( 0, 0, &Automap_background ); // modex_printf( 40, 22,TXT_AUTOMAP,GFONT_BIG_1); // modex_printf( 70,353,TXT_TURN_SHIP,GFONT_SMALL); // modex_printf( 70,369,TXT_SLIDE_UPDOWN,GFONT_SMALL); // modex_printf( 70,385,TXT_VIEWING_DISTANCE,GFONT_SMALL); } #ifdef AUTOMAP_NO_PAGING //killed 05/17/99 Matt Mueller - this seems to merely copy undefined bytes around.. not needed //--killed-- gr_bm_ubitblt(automap_width,automap_height, 0, 0, 0, 0, &OffscreenPage->cv_bitmap,&Pages[0].cv_bitmap); //end kill -MM #endif gr_free_bitmap_data (&Automap_background); gr_set_current_canvas(&DrawingPages[current_page]); #endif automap_build_edge_list(); if ( ViewDist==0 ) ViewDist = ZOOM_DEFAULT; ViewMatrix = Objects[Players[Player_num].objnum].orient; tangles.p = PITCH_DEFAULT; tangles.h = 0; tangles.b = 0; done = 0; view_target = Objects[Players[Player_num].objnum].pos; t1 = entry_time = timer_get_fixed_seconds(); t2 = t1; //Fill in Automap_visited from Objects[Players[Player_num].objnum].segnum Max_segments_away = set_segment_depths(Objects[Players[Player_num].objnum].segnum, Automap_visited); SegmentLimit = Max_segments_away; adjust_segment_limit(SegmentLimit); while(!done) { if ( leave_mode==0 && Controls.automap_state && (timer_get_fixed_seconds()-entry_time)>LEAVE_TIME) leave_mode = 1; if ( !Controls.automap_state && (leave_mode==1) ) done=1; if (!pause_game) { ushort old_wiggle; saved_control_info = Controls; // Save controls so we can zero them memset(&Controls,0,sizeof(control_info)); // Clear everything... old_wiggle = ConsoleObject->mtype.phys_info.flags & PF_WIGGLE; // Save old wiggle ConsoleObject->mtype.phys_info.flags &= ~PF_WIGGLE; // Turn off wiggle #ifdef NETWORK if (multi_menu_poll()) done = 1; #endif // GameLoop( 0, 0 ); // Do game loop with no rendering and no reading controls. ConsoleObject->mtype.phys_info.flags |= old_wiggle; // Restore wiggle Controls = saved_control_info; } controls_read_all(); if ( Controls.automap_down_count ) { if (leave_mode==0) done = 1; c = 0; } while( (c=key_inkey()) ) { switch( c ) { #ifndef NDEBUG case KEY_BACKSP: Int3(); break; #endif case KEY_PRINT_SCREEN: save_screen_shot(1); break; case KEY_ESC: if (leave_mode==0) done = 1; break; case KEY_ALTED+KEY_F: // Alt+F shows full map, if cheats enabled if (Cheats_enabled) { uint t; t = Players[Player_num].flags; Players[Player_num].flags |= PLAYER_FLAGS_MAP_ALL_CHEAT; automap_build_edge_list(); Players[Player_num].flags=t; } break; #ifndef NDEBUG case KEY_DEBUGGED+KEY_F: { for (i=0; i<=Highest_segment_index; i++ ) Automap_visited[i] = 1; automap_build_edge_list(); Max_segments_away = set_segment_depths(Objects[Players[Player_num].objnum].segnum, Automap_visited); SegmentLimit = Max_segments_away; adjust_segment_limit(SegmentLimit); } break; #endif case KEY_MINUS: if (SegmentLimit > 1) { SegmentLimit--; adjust_segment_limit(SegmentLimit); } break; case KEY_EQUAL: if (SegmentLimit < Max_segments_away) { SegmentLimit++; adjust_segment_limit(SegmentLimit); } break; } } if ( Controls.fire_primary_down_count ) { // Reset orientation ViewDist = ZOOM_DEFAULT; tangles.p = PITCH_DEFAULT; tangles.h = 0; tangles.b = 0; view_target = Objects[Players[Player_num].objnum].pos; } ViewDist -= Controls.forward_thrust_time*ZOOM_SPEED_FACTOR; tangles.p += fixdiv( Controls.pitch_time, ROT_SPEED_DIVISOR ); tangles.h += fixdiv( Controls.heading_time, ROT_SPEED_DIVISOR ); tangles.b += fixdiv( Controls.bank_time, ROT_SPEED_DIVISOR*2 ); if ( Controls.vertical_thrust_time || Controls.sideways_thrust_time ) { vms_angvec tangles1; vms_vector old_vt; old_vt = view_target; tangles1 = tangles; vm_angles_2_matrix(&tempm,&tangles1); vm_matrix_x_matrix(&ViewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); vm_vec_scale_add2( &view_target, &ViewMatrix.uvec, Controls.vertical_thrust_time*SLIDE_SPEED ); vm_vec_scale_add2( &view_target, &ViewMatrix.rvec, Controls.sideways_thrust_time*SLIDE_SPEED ); if ( vm_vec_dist_quick( &view_target, &Objects[Players[Player_num].objnum].pos) > i2f(1000) ) { view_target = old_vt; } } vm_angles_2_matrix(&tempm,&tangles); vm_matrix_x_matrix(&ViewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); if ( ViewDist < ZOOM_MIN_VALUE ) ViewDist = ZOOM_MIN_VALUE; if ( ViewDist > ZOOM_MAX_VALUE ) ViewDist = ZOOM_MAX_VALUE; draw_automap(); if ( first_time ) { first_time = 0; gr_palette_load( gr_palette ); } t2 = timer_get_fixed_seconds(); while (t2-t1<F1_0/100){//ogl is fast enough that the automap can read the input too fast and you start to turn really slow. So delay a bit (and free up some cpu :) if (nice_automap) d_delay(1); t2 = timer_get_fixed_seconds(); } if (pause_game) FrameTime=t2-t1; t1 = t2; } //free(Edges); //free(DrawingListBright); gr_free_canvas(name_canv); name_canv=NULL; #ifdef AUTOMAP_NO_PAGING gr_free_canvas(OffscreenPage); OffscreenPage = NULL; #endif mprintf( (0, "Automap memory freed\n" )); game_flush_inputs(); if (pause_game) start_time(); } void adjust_segment_limit(int SegmentLimit) { int i,e1; Edge_info * e; mprintf(( 0, "Seglimit: %d\n", SegmentLimit )); for (i=0; i<=Highest_edge_index; i++ ) { e = &Edges[i]; e->flags |= EF_TOO_FAR; for (e1=0; e1<e->num_faces; e1++ ) { if ( Automap_visited[e->segnum[e1]] <= SegmentLimit ) { e->flags &= (~EF_TOO_FAR); break; } } } }
// --------------------------------------------------------------------------------------------------- //this function is the editor. called when editor mode selected. runs until //game mode or exit selected void editor(void) { int w,h; grs_bitmap * savedbitmap; editor_view *new_cv; static int padnum=0; vms_matrix MouseRotMat,tempm; //@@short camera_objnum; //a camera for viewing init_editor(); InitCurve(); restore_effect_bitmap_icons(); if (!set_screen_mode(SCREEN_EDITOR)) { set_screen_mode(SCREEN_GAME); Function_mode=FMODE_GAME; //force back into game return; } gr_set_current_canvas( NULL ); gr_set_curfont(editor_font); //Editor renders into full (320x200) game screen set_warn_func(med_show_warning); keyd_repeat = 1; // Allow repeat in editor // _MARK_("start of editor");//Nuked to compile -KRB ui_mouse_hide(); ui_reset_idle_seconds(); //@@ //create a camera for viewing in the editor. copy position from ConsoleObject //@@ camera_objnum = obj_create(OBJ_CAMERA,0,ConsoleObject->segnum,&ConsoleObject->pos,&ConsoleObject->orient,0); //@@ Viewer = &Objects[camera_objnum]; //@@ slew_init(Viewer); //camera is slewing Viewer = ConsoleObject; slew_init(ConsoleObject); Update_flags = UF_ALL; medlisp_update_screen(); //set the wire-frame window to be the current view current_view = &LargeView; if (faded_in==0) { faded_in = 1; //gr_pal_fade_in( grd_curscreen->pal ); } w = GameViewBox->canvas->cv_bitmap.bm_w; h = GameViewBox->canvas->cv_bitmap.bm_h; savedbitmap = gr_create_bitmap(w, h ); gr_bm_ubitblt( w, h, 0, 0, 0, 0, &GameViewBox->canvas->cv_bitmap, savedbitmap ); gr_set_current_canvas( GameViewBox->canvas ); gr_set_curfont(editor_font); //gr_setcolor( CBLACK ); //gr_deaccent_canvas(); //gr_grey_canvas(); ui_mouse_show(); gr_set_curfont(editor_font); ui_pad_goto(padnum); gamestate_restore_check(); while (Function_mode == FMODE_EDITOR) { gr_set_curfont(editor_font); info_display_all(EditorWindow); ModeFlag = 0; // Update the windows // Only update if there is no key waiting and we're not in // fast play mode. if (!key_peekkey()) //-- && (MacroStatus != UI_STATUS_FASTPLAY)) medlisp_update_screen(); //do editor stuff gr_set_curfont(editor_font); ui_mega_process(); last_keypress &= ~KEY_DEBUGGED; // mask off delete key bit which has no function in editor. ui_window_do_gadgets(EditorWindow); do_robot_window(); do_object_window(); do_wall_window(); do_trigger_window(); do_hostage_window(); do_centers_window(); check_wall_validity(); Assert(Num_walls>=0); if (Gameview_lockstep) { static segment *old_cursegp=NULL; static int old_curside=-1; if (old_cursegp!=Cursegp || old_curside!=Curside) { SetPlayerFromCursegMinusOne(); old_cursegp = Cursegp; old_curside = Curside; } } // mprintf((0, "%d ", ui_get_idle_seconds() )); if ( ui_get_idle_seconds() > COMPRESS_INTERVAL ) { med_compress_mine(); ui_reset_idle_seconds(); } // Commented out because it occupies about 25% of time in twirling the mine. // Removes some Asserts.... // med_check_all_vertices(); clear_editor_status(); // if enough time elapsed, clear editor status message TimedAutosave(mine_filename); set_editor_time_of_day(); gr_set_current_canvas( GameViewBox->canvas ); // Remove keys used for slew switch(last_keypress) { case KEY_PAD9: case KEY_PAD7: case KEY_PADPLUS: case KEY_PADMINUS: case KEY_PAD8: case KEY_PAD2: case KEY_LBRACKET: case KEY_RBRACKET: case KEY_PAD1: case KEY_PAD3: case KEY_PAD6: case KEY_PAD4: last_keypress = 0; } if ((last_keypress&0xff)==KEY_LSHIFT) last_keypress=0; if ((last_keypress&0xff)==KEY_RSHIFT) last_keypress=0; if ((last_keypress&0xff)==KEY_LCTRL) last_keypress=0; if ((last_keypress&0xff)==KEY_RCTRL) last_keypress=0; // if ((last_keypress&0xff)==KEY_LALT) last_keypress=0; // if ((last_keypress&0xff)==KEY_RALT) last_keypress=0; if ((last_keypress&0xff)==KEY_LMETA) last_keypress=0; if ((last_keypress&0xff)==KEY_RMETA) last_keypress=0; gr_set_curfont(editor_font); menubar_do( last_keypress ); //=================== DO FUNCTIONS ==================== if ( KeyFunction[ last_keypress ] != NULL ) { KeyFunction[last_keypress](); last_keypress = 0; } switch (last_keypress) { case 0: case KEY_Z: case KEY_G: case KEY_LALT: case KEY_RALT: case KEY_LCTRL: case KEY_RCTRL: case KEY_LSHIFT: case KEY_RSHIFT: case KEY_LAPOSTRO: break; case KEY_SHIFTED + KEY_L: ToggleLighting(); break; case KEY_F1: render_3d_in_big_window = !render_3d_in_big_window; Update_flags |= UF_ALL; break; default: { char kdesc[100]; GetKeyDescription( kdesc, last_keypress ); editor_status("Error: %s isn't bound to anything.", kdesc ); } } //================================================================ if (ModeFlag==1) { close_editor_screen(); Function_mode=FMODE_EXIT; gr_free_bitmap( savedbitmap ); break; } if (ModeFlag==2) //-- && MacroStatus==UI_STATUS_NORMAL ) { close_editor_screen(); Function_mode = FMODE_MENU; set_screen_mode(SCREEN_MENU); //put up menu screen gr_free_bitmap(savedbitmap); break; } if (ModeFlag==3) //-- && MacroStatus==UI_STATUS_NORMAL ) { // med_compress_mine(); //will be called anyways before game. close_editor_screen(); Function_mode=FMODE_GAME; //force back into game set_screen_mode(SCREEN_GAME); //put up game screen gr_free_bitmap( savedbitmap ); break; } // if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)GameViewBox) current_view=NULL; // if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)GroupViewBox) current_view=NULL; new_cv = current_view ; #if ORTHO_VIEWS if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)LargeViewBox) new_cv=&LargeView; if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)TopViewBox) new_cv=&TopView; if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)FrontViewBox) new_cv=&FrontView; if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)RightViewBox) new_cv=&RightView; #endif if (new_cv != current_view ) { current_view->ev_changed = 1; new_cv->ev_changed = 1; current_view = new_cv; } calc_frame_time(); if (slew_frame(0)) { //do movement and check keys Update_flags |= UF_GAME_VIEW_CHANGED; if (Gameview_lockstep) { Cursegp = &Segments[ConsoleObject->segnum]; med_create_new_segment_from_cursegp(); Update_flags |= UF_ED_STATE_CHANGED; } } // DO TEXTURE STUFF texpage_do(); objpage_do(); // Process selection of Cursegp using mouse. if (LargeViewBox->mouse_onme && LargeViewBox->b1_clicked && !render_3d_in_big_window) { int xcrd,ycrd; xcrd = LargeViewBox->b1_drag_x1; ycrd = LargeViewBox->b1_drag_y1; find_segments(xcrd,ycrd,LargeViewBox->canvas,&LargeView,Cursegp,Big_depth); // Sets globals N_found_segs, Found_segs // If shift is down, then add segment to found list if (keyd_pressed[ KEY_LSHIFT ] || keyd_pressed[ KEY_RSHIFT ]) subtract_found_segments_from_selected_list(); else add_found_segments_to_selected_list(); Found_seg_index = 0; if (N_found_segs > 0) { sort_seg_list(N_found_segs,Found_segs,&ConsoleObject->pos); Cursegp = &Segments[Found_segs[0]]; med_create_new_segment_from_cursegp(); if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); } Update_flags |= UF_ED_STATE_CHANGED | UF_VIEWPOINT_MOVED; } if (GameViewBox->mouse_onme && GameViewBox->b1_dragging) { int x, y; x = GameViewBox->b1_drag_x2; y = GameViewBox->b1_drag_y2; ui_mouse_hide(); gr_set_current_canvas( GameViewBox->canvas ); gr_setcolor( 15 ); gr_rect( x-1, y-1, x+1, y+1 ); ui_mouse_show(); } // Set current segment and side by clicking on a polygon in game window. // If ctrl pressed, also assign current texture map to that side. //if (GameViewBox->mouse_onme && (GameViewBox->b1_done_dragging || GameViewBox->b1_clicked)) { if ((GameViewBox->mouse_onme && GameViewBox->b1_clicked && !render_3d_in_big_window) || (LargeViewBox->mouse_onme && LargeViewBox->b1_clicked && render_3d_in_big_window)) { int xcrd,ycrd; int seg,side,face,poly,tmap; if (render_3d_in_big_window) { xcrd = LargeViewBox->b1_drag_x1; ycrd = LargeViewBox->b1_drag_y1; } else { xcrd = GameViewBox->b1_drag_x1; ycrd = GameViewBox->b1_drag_y1; } //Int3(); if (find_seg_side_face(xcrd,ycrd,&seg,&side,&face,&poly)) { if (seg<0) { //found an object Cur_object_index = -seg-1; editor_status("Object %d selected.",Cur_object_index); Update_flags |= UF_ED_STATE_CHANGED; } else { // See if either shift key is down and, if so, assign texture map if (keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT]) { Cursegp = &Segments[seg]; Curside = side; AssignTexture(); med_create_new_segment_from_cursegp(); editor_status("Texture assigned"); } else if (keyd_pressed[KEY_G]) { tmap = Segments[seg].sides[side].tmap_num; texpage_grab_current(tmap); editor_status( "Texture grabbed." ); } else if (keyd_pressed[ KEY_LAPOSTRO] ) { ui_mouse_hide(); move_object_to_mouse_click(); } else { Cursegp = &Segments[seg]; Curside = side; med_create_new_segment_from_cursegp(); editor_status("Curseg and curside selected"); } } Update_flags |= UF_ED_STATE_CHANGED; } else editor_status("Click on non-texture ingored"); } // Allow specification of LargeView using mouse if (keyd_pressed[ KEY_LCTRL ] || keyd_pressed[ KEY_RCTRL ]) { ui_mouse_hide(); if ( (Mouse.dx!=0) && (Mouse.dy!=0) ) { GetMouseRotation( Mouse.dx, Mouse.dy, &MouseRotMat ); vm_matrix_x_matrix(&tempm,&LargeView.ev_matrix,&MouseRotMat); LargeView.ev_matrix = tempm; LargeView.ev_changed = 1; Large_view_index = -1; // say not one of the orthogonal views } } else { ui_mouse_show(); } if ( keyd_pressed[ KEY_Z ] ) { ui_mouse_hide(); if ( Mouse.dy!=0 ) { current_view->ev_dist += Mouse.dy*10000; current_view->ev_changed = 1; } } else { ui_mouse_show(); } vid_update(); } // _MARK_("end of editor");//Nuked to compile -KRB clear_warn_func(med_show_warning); //kill our camera object Viewer = ConsoleObject; //reset viewer //@@obj_delete(camera_objnum); padnum = ui_pad_get_current(); close_editor(); ui_close(); }
void do_automap( int key_code ) { int done=0; vms_matrix tempm; vms_angvec tangles; int leave_mode=0; int first_time=1; int pcx_error; int i; int c; char filename[] = "MAP.PCX"; fix entry_time; int pause_game=1; // Set to 1 if everything is paused during automap...No pause during net. fix t1, t2; control_info saved_control_info; int Max_segments_away = 0; int SegmentLimit = 1; key_code = key_code; // disable warning... if ((Game_mode & GM_MULTI) && (Function_mode == FMODE_GAME) && (!Endlevel_sequence)) pause_game = 0; if (pause_game) stop_time(); create_name_canv(); Max_edges = min(MAX_EDGES_FROM_VERTS(Num_vertices),MAX_EDGES); //make maybe smaller than max //Edges = malloc( sizeof(Edge_info)*Max_edges); //if ( Edges == NULL ) { // mprintf((0, "Couldn't get %dK for automap!", sizeof(Edge_info)*Max_edges/1024)); // return; //} //DrawingListBright = malloc( sizeof(short)*Max_edges); //if ( DrawingListBright == NULL ) { // mprintf((0, "Couldn't get %dK for automap!", sizeof(short)*Max_edges/1024)); // return; //} mprintf( (0, "Num_vertices=%d, Max_edges=%d, (MAX:%d)\n", Num_vertices, Max_edges, MAX_EDGES )); mprintf( (0, "Allocated %d K for automap edge list\n", (sizeof(Edge_info)+sizeof(short))*Max_edges/1024 )); gr_palette_clear(); gr_init_sub_canvas(&Page,&VR_render_buffer[0],0, 0, 640, 480); gr_init_sub_canvas(&DrawingPage,&Page,38,77,564,381); #if 0 gr_init_sub_canvas(&Pages[0],grd_curcanv,0,0,320,400); gr_init_sub_canvas(&Pages[1],grd_curcanv,0,401,320,400); gr_init_sub_canvas(&DrawingPages[0],&Pages[0],16,69,288,272); gr_init_sub_canvas(&DrawingPages[1],&Pages[1],16,69,288,272); #endif gr_set_current_canvas(&Page); pcx_error = pcx_read_bitmap(filename,&(grd_curcanv->cv_bitmap),BM_LINEAR,NULL); if ( pcx_error != PCX_ERROR_NONE ) { printf("File %s - PCX error: %s",filename,pcx_errormsg(pcx_error)); Error("File %s - PCX error: %s",filename,pcx_errormsg(pcx_error)); return; } gr_set_curfont(Gamefonts[GFONT_BIG_1]); gr_set_fontcolor(BM_XRGB(20, 20, 20), -1); gr_printf( 80, 36,TXT_AUTOMAP,GFONT_BIG_1); gr_set_curfont(Gamefonts[GFONT_SMALL]); gr_set_fontcolor(BM_XRGB(20, 20, 20), -1); gr_printf( 265, 27,TXT_TURN_SHIP); gr_printf( 265, 44,TXT_SLIDE_UPDOWN); gr_printf( 265, 61,TXT_VIEWING_DISTANCE); gr_set_current_canvas(&DrawingPage); automap_build_edge_list(); if ( ViewDist==0 ) ViewDist = ZOOM_DEFAULT; ViewMatrix = Objects[Players[Player_num].objnum].orient; tangles.p = PITCH_DEFAULT; tangles.h = 0; tangles.b = 0; done = 0; view_target = Objects[Players[Player_num].objnum].pos; t1 = entry_time = timer_get_fixed_seconds(); t2 = t1; //Fill in Automap_visited from Objects[Players[Player_num].objnum].segnum Max_segments_away = set_segment_depths(Objects[Players[Player_num].objnum].segnum, Automap_visited); SegmentLimit = Max_segments_away; adjust_segment_limit(SegmentLimit); while(!done) { #ifndef MAC_SHAREWARE redbook_restart_track(); #endif if ( leave_mode==0 && Controls.automap_state && (timer_get_fixed_seconds()-entry_time)>LEAVE_TIME) leave_mode = 1; if ( !Controls.automap_state && (leave_mode==1) ) done=1; if (!pause_game) { ushort old_wiggle; saved_control_info = Controls; // Save controls so we can zero them memset(&Controls,0,sizeof(control_info)); // Clear everything... old_wiggle = ConsoleObject->mtype.phys_info.flags & PF_WIGGLE; // Save old wiggle ConsoleObject->mtype.phys_info.flags &= ~PF_WIGGLE; // Turn off wiggle #ifdef NETWORK if (multi_menu_poll()) done = 1; #endif // GameLoop( 0, 0 ); // Do game loop with no rendering and no reading controls. ConsoleObject->mtype.phys_info.flags |= old_wiggle; // Restore wiggle Controls = saved_control_info; } controls_read_all(); if ( Controls.automap_down_count ) { if (leave_mode==0) done = 1; c = 0; } while( (c=key_inkey()) ) { switch( c ) { #ifndef NDEBUG case KEY_BACKSP: Int3(); break; #endif case KEY_PRINT_SCREEN: save_screen_shot(1); break; case KEY_ESC: if (leave_mode==0) done = 1; break; case KEY_ALTED+KEY_F: // Alt+F shows full map, if cheats enabled if (Cheats_enabled) { uint t; t = Players[Player_num].flags; Players[Player_num].flags |= PLAYER_FLAGS_MAP_ALL_CHEAT; automap_build_edge_list(); Players[Player_num].flags=t; } break; #ifndef NDEBUG case KEY_DEBUGGED+KEY_F: { for (i=0; i<=Highest_segment_index; i++ ) Automap_visited[i] = 1; automap_build_edge_list(); Max_segments_away = set_segment_depths(Objects[Players[Player_num].objnum].segnum, Automap_visited); SegmentLimit = Max_segments_away; adjust_segment_limit(SegmentLimit); } break; #endif case KEY_MINUS: if (SegmentLimit > 1) { SegmentLimit--; adjust_segment_limit(SegmentLimit); } break; case KEY_EQUAL: if (SegmentLimit < Max_segments_away) { SegmentLimit++; adjust_segment_limit(SegmentLimit); } break; } } if ( Controls.fire_primary_down_count ) { // Reset orientation ViewDist = ZOOM_DEFAULT; tangles.p = PITCH_DEFAULT; tangles.h = 0; tangles.b = 0; view_target = Objects[Players[Player_num].objnum].pos; } ViewDist -= Controls.forward_thrust_time*ZOOM_SPEED_FACTOR; tangles.p += fixdiv( Controls.pitch_time, ROT_SPEED_DIVISOR ); tangles.h += fixdiv( Controls.heading_time, ROT_SPEED_DIVISOR ); tangles.b += fixdiv( Controls.bank_time, ROT_SPEED_DIVISOR*2 ); if ( Controls.vertical_thrust_time || Controls.sideways_thrust_time ) { vms_angvec tangles1; vms_vector old_vt; old_vt = view_target; tangles1 = tangles; vm_angles_2_matrix(&tempm,&tangles1); vm_matrix_x_matrix(&ViewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); vm_vec_scale_add2( &view_target, &ViewMatrix.uvec, Controls.vertical_thrust_time*SLIDE_SPEED ); vm_vec_scale_add2( &view_target, &ViewMatrix.rvec, Controls.sideways_thrust_time*SLIDE_SPEED ); if ( vm_vec_dist_quick( &view_target, &Objects[Players[Player_num].objnum].pos) > i2f(1000) ) { view_target = old_vt; } } vm_angles_2_matrix(&tempm,&tangles); vm_matrix_x_matrix(&ViewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); if ( ViewDist < ZOOM_MIN_VALUE ) ViewDist = ZOOM_MIN_VALUE; if ( ViewDist > ZOOM_MAX_VALUE ) ViewDist = ZOOM_MAX_VALUE; draw_automap(); if ( first_time ) { first_time = 0; gr_palette_load( gr_palette ); } t2 = timer_get_fixed_seconds(); if (pause_game) FrameTime=t2-t1; t1 = t2; } //free(Edges); //free(DrawingListBright); gr_free_canvas(name_canv); name_canv=NULL; mprintf( (0, "Automap memory freed\n" )); game_flush_inputs(); if (pause_game) start_time(); }
void techroom_ships_render(float frametime) { // render all the common stuff tech_common_render(); if(Cur_entry_index == -1) return; // now render the trackball ship, which is unique to the ships tab float rev_rate = REVOLUTION_RATE; angles rot_angles, view_angles; int z, i, j; ship_info *sip = &Ship_info[Cur_entry_index]; model_render_params render_info; if (sip->uses_team_colors) { render_info.set_team_color(sip->default_team_name, "none", 0, 0); } // get correct revolution rate z = sip->flags; if (z & SIF_BIG_SHIP) { rev_rate *= 1.7f; } if (z & SIF_HUGE_SHIP) { rev_rate *= 3.0f; } // rotate the ship as much as required for this frame Techroom_ship_rot += PI2 * frametime / rev_rate; while (Techroom_ship_rot > PI2){ Techroom_ship_rot -= PI2; } // reorient ship if (Trackball_active) { int dx, dy; matrix mat1, mat2; if (Trackball_active) { mouse_get_delta(&dx, &dy); if (dx || dy) { vm_trackball(-dx, -dy, &mat1); vm_matrix_x_matrix(&mat2, &mat1, &Techroom_ship_orient); Techroom_ship_orient = mat2; } } } else { // setup stuff needed to render the ship view_angles.p = -0.6f; view_angles.b = 0.0f; view_angles.h = 0.0f; vm_angles_2_matrix(&Techroom_ship_orient, &view_angles); rot_angles.p = 0.0f; rot_angles.b = 0.0f; rot_angles.h = Techroom_ship_rot; vm_rotate_matrix_by_angles(&Techroom_ship_orient, &rot_angles); } gr_set_clip(Tech_ship_display_coords[gr_screen.res][SHIP_X_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_Y_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_W_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_H_COORD], GR_RESIZE_MENU); // render the ship g3_start_frame(1); g3_set_view_matrix(&sip->closeup_pos, &vmd_identity_matrix, sip->closeup_zoom * 1.3f); // lighting for techroom light_reset(); vec3d light_dir = vmd_zero_vector; light_dir.xyz.y = 1.0f; light_dir.xyz.x = 0.0000001f; light_add_directional(&light_dir, 0.85f, 1.0f, 1.0f, 1.0f); light_rotate_all(); // lighting for techroom Glowpoint_use_depth_buffer = false; model_clear_instance(Techroom_ship_modelnum); render_info.set_detail_level_lock(0); polymodel *pm = model_get(Techroom_ship_modelnum); for (i = 0; i < sip->n_subsystems; i++) { model_subsystem *msp = &sip->subsystems[i]; if (msp->type == SUBSYSTEM_TURRET) { float p = 0.0f; float h = 0.0f; for (j = 0; j < msp->n_triggers; j++) { // special case for turrets p = msp->triggers[j].angle.xyz.x; h = msp->triggers[j].angle.xyz.y; } if ( msp->subobj_num >= 0 ) { model_set_instance_techroom(Techroom_ship_modelnum, msp->subobj_num, 0.0f, h ); } if ( (msp->subobj_num != msp->turret_gun_sobj) && (msp->turret_gun_sobj >= 0) ) { model_set_instance_techroom(Techroom_ship_modelnum, msp->turret_gun_sobj, p, 0.0f ); } } } if(Cmdline_shadow_quality) { gr_reset_clip(); shadows_start_render(&Eye_matrix, &Eye_position, Proj_fov, gr_screen.clip_aspect, -sip->closeup_pos.xyz.z + pm->rad, -sip->closeup_pos.xyz.z + pm->rad + 200.0f, -sip->closeup_pos.xyz.z + pm->rad + 2000.0f, -sip->closeup_pos.xyz.z + pm->rad + 10000.0f); render_info.set_flags(MR_NO_TEXTURING | MR_NO_LIGHTING | MR_AUTOCENTER); model_render_immediate(&render_info, Techroom_ship_modelnum, &Techroom_ship_orient, &vmd_zero_vector); shadows_end_render(); gr_set_clip(Tech_ship_display_coords[gr_screen.res][SHIP_X_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_Y_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_W_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_H_COORD], GR_RESIZE_MENU); } if (!Cmdline_nohtl) { gr_set_proj_matrix(Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance); gr_set_view_matrix(&Eye_position, &Eye_matrix); } uint render_flags = MR_AUTOCENTER; if(sip->flags2 & SIF2_NO_LIGHTING) render_flags |= MR_NO_LIGHTING; render_info.set_flags(render_flags); model_render_immediate(&render_info, Techroom_ship_modelnum, &Techroom_ship_orient, &vmd_zero_vector); Glowpoint_use_depth_buffer = true; batch_render_all(); if (!Cmdline_nohtl) { gr_end_view_matrix(); gr_end_proj_matrix(); } g3_end_frame(); gr_reset_clip(); }
int automap_process_input(window *wind, d_event *event, automap *am) { vms_matrix tempm; Controls = am->controls; kconfig_read_controls(event, 1); am->controls = Controls; memset(&Controls, 0, sizeof(control_info)); if ( !am->controls.automap_state && (am->leave_mode==1) ) { window_close(wind); return 1; } if ( am->controls.automap_count > 0) { am->controls.automap_count = 0; if (am->leave_mode==0) { window_close(wind); return 1; } } if (PlayerCfg.AutomapFreeFlight) { if ( am->controls.fire_primary_count > 0) { // Reset orientation am->viewMatrix = Objects[Players[Player_num].objnum].orient; vm_vec_scale_add(&am->view_position, &Objects[Players[Player_num].objnum].pos, &am->viewMatrix.fvec, -ZOOM_DEFAULT ); am->controls.fire_primary_count = 0; } if (am->controls.pitch_time || am->controls.heading_time || am->controls.bank_time) { vms_angvec tangles; vms_matrix new_m; tangles.p = fixdiv( am->controls.pitch_time, ROT_SPEED_DIVISOR ); tangles.h = fixdiv( am->controls.heading_time, ROT_SPEED_DIVISOR ); tangles.b = fixdiv( am->controls.bank_time, ROT_SPEED_DIVISOR*2 ); vm_angles_2_matrix(&tempm, &tangles); vm_matrix_x_matrix(&new_m,&am->viewMatrix,&tempm); am->viewMatrix = new_m; check_and_fix_matrix(&am->viewMatrix); } if ( am->controls.forward_thrust_time || am->controls.vertical_thrust_time || am->controls.sideways_thrust_time ) { vm_vec_scale_add2( &am->view_position, &am->viewMatrix.fvec, am->controls.forward_thrust_time*ZOOM_SPEED_FACTOR ); vm_vec_scale_add2( &am->view_position, &am->viewMatrix.uvec, am->controls.vertical_thrust_time*SLIDE_SPEED ); vm_vec_scale_add2( &am->view_position, &am->viewMatrix.rvec, am->controls.sideways_thrust_time*SLIDE_SPEED ); // Crude wrapping check if (am->view_position.x > F1_0*32000) am->view_position.x = F1_0*32000; if (am->view_position.x < -F1_0*32000) am->view_position.x = -F1_0*32000; if (am->view_position.y > F1_0*32000) am->view_position.y = F1_0*32000; if (am->view_position.y < -F1_0*32000) am->view_position.y = -F1_0*32000; if (am->view_position.z > F1_0*32000) am->view_position.z = F1_0*32000; if (am->view_position.z < -F1_0*32000) am->view_position.z = -F1_0*32000; } } else { if ( am->controls.fire_primary_count > 0) { // Reset orientation am->viewDist = ZOOM_DEFAULT; am->tangles.p = PITCH_DEFAULT; am->tangles.h = 0; am->tangles.b = 0; am->view_target = Objects[Players[Player_num].objnum].pos; am->controls.fire_primary_count = 0; } am->viewDist -= am->controls.forward_thrust_time*ZOOM_SPEED_FACTOR; am->tangles.p += fixdiv( am->controls.pitch_time, ROT_SPEED_DIVISOR ); am->tangles.h += fixdiv( am->controls.heading_time, ROT_SPEED_DIVISOR ); am->tangles.b += fixdiv( am->controls.bank_time, ROT_SPEED_DIVISOR*2 ); if ( am->controls.vertical_thrust_time || am->controls.sideways_thrust_time ) { vms_angvec tangles1; vms_vector old_vt; old_vt = am->view_target; tangles1 = am->tangles; vm_angles_2_matrix(&tempm,&tangles1); vm_matrix_x_matrix(&am->viewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); vm_vec_scale_add2( &am->view_target, &am->viewMatrix.uvec, am->controls.vertical_thrust_time*SLIDE_SPEED ); vm_vec_scale_add2( &am->view_target, &am->viewMatrix.rvec, am->controls.sideways_thrust_time*SLIDE_SPEED ); if ( vm_vec_dist_quick( &am->view_target, &Objects[Players[Player_num].objnum].pos) > i2f(1000) ) am->view_target = old_vt; } vm_angles_2_matrix(&tempm,&am->tangles); vm_matrix_x_matrix(&am->viewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); if ( am->viewDist < ZOOM_MIN_VALUE ) am->viewDist = ZOOM_MIN_VALUE; if ( am->viewDist > ZOOM_MAX_VALUE ) am->viewDist = ZOOM_MAX_VALUE; } return 0; }
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; }
/** * nstance at specified point with specified orientation * * if matrix==NULL, don't modify matrix. This will be like doing an offset * if pos==NULL, no position change */ void g3_start_instance_matrix(const vec3d *pos, const matrix *orient, bool set_api) { vec3d tempv; matrix tempm,tempm2; Assert( G3_count == 1 ); Assert(instance_depth<MAX_INSTANCE_DEPTH); instance_stack[instance_depth].m = View_matrix; instance_stack[instance_depth].p = View_position; instance_stack[instance_depth].lm = Light_matrix; instance_stack[instance_depth].lb = Light_base; instance_stack[instance_depth].om = Object_matrix; instance_stack[instance_depth].op = Object_position; instance_depth++; // Make sure orient is valid if (!orient) { orient = &vmd_identity_matrix; // Assume no change in orient } if ( pos ) { //step 1: subtract object position from view position vm_vec_sub2(&View_position,pos); //step 2: rotate view vector through object matrix vm_vec_rotate(&tempv,&View_position,orient); View_position = tempv; vm_vec_unrotate(&tempv,pos,&Object_matrix); vm_vec_add2(&Object_position, &tempv); } else { // No movement, leave View_position alone } //step 3: rotate object matrix through view_matrix (vm = ob * vm) vm_copy_transpose(&tempm2,orient); vm_matrix_x_matrix(&tempm,&tempm2,&View_matrix); View_matrix = tempm; vm_matrix_x_matrix(&Object_matrix,&instance_stack[instance_depth-1].om,orient); // Update the lighting matrix matrix saved_orient = Light_matrix; vec3d saved_base = Light_base; if ( pos ) { vm_vec_unrotate(&Light_base,pos,&saved_orient ); vm_vec_add2(&Light_base, &saved_base ); } else { // No movement, light_base doesn't change. } vm_matrix_x_matrix(&Light_matrix,&saved_orient, orient); if(!Cmdline_nohtl && set_api) gr_start_instance_matrix(pos, orient); }
//called for each level to load & setup the exit sequence load_endlevel_data(int level_num) { char filename[13]; char line[LINE_LEN],*p; CFILE *ifile; int var,segnum,sidenum; int exit_side, i; int have_binary = 0; endlevel_data_loaded = 0; //not loaded yet try_again: ; if (level_num<0) //secret level strcpy(filename,Secret_level_names[-level_num-1]); else //normal level strcpy(filename,Level_names[level_num-1]); if (!convert_ext(filename,"END")) return; ifile = cfopen(filename,"rb"); if (!ifile) { convert_ext(filename,"TXB"); ifile = cfopen(filename,"rb"); if (!ifile) if (level_num==1) { return; //abort //Error("Cannot load file text of binary version of <%s>",filename); } else { level_num = 1; goto try_again; } have_binary = 1; } //ok...this parser is pretty simple. It ignores comments, but //everything else must be in the right place var = 0; while (cfgets(line,LINE_LEN,ifile)) { if (have_binary) { for (i = 0; i < strlen(line) - 1; i++) { encode_rotate_left(&(line[i])); line[i] = line[i] ^ BITMAP_TBL_XOR; encode_rotate_left(&(line[i])); } p = line; } if ((p=strchr(line,';'))!=NULL) *p = 0; //cut off comment for (p=line+strlen(line)-1;p>line && isspace(*p);*p--=0); for (p=line;isspace(*p);p++); if (!*p) //empty line continue; switch (var) { case 0: { //ground terrain int iff_error; ubyte pal[768]; if (terrain_bm_instance.bm_data) free(terrain_bm_instance.bm_data); iff_error = iff_read_bitmap(p,&terrain_bm_instance,BM_LINEAR,pal); if (iff_error != IFF_NO_ERROR) { mprintf((1, "File %s - IFF error: %s",p,iff_errormsg(iff_error))); Error("File %s - IFF error: %s",p,iff_errormsg(iff_error)); } terrain_bitmap = &terrain_bm_instance; gr_remap_bitmap_good( terrain_bitmap, pal, iff_transparent_color, -1); break; } case 1: //height map load_terrain(p); break; case 2: sscanf(p,"%d,%d",&exit_point_bmx,&exit_point_bmy); break; case 3: //exit heading exit_angles.h = i2f(atoi(p))/360; break; case 4: { //planet bitmap int iff_error; ubyte pal[768]; if (satellite_bm_instance.bm_data) free(satellite_bm_instance.bm_data); iff_error = iff_read_bitmap(p,&satellite_bm_instance,BM_LINEAR,pal); if (iff_error != IFF_NO_ERROR) { mprintf((1, "File %s - IFF error: %s",p,iff_errormsg(iff_error))); Error("File %s - IFF error: %s",p,iff_errormsg(iff_error)); } satellite_bitmap = &satellite_bm_instance; gr_remap_bitmap_good( satellite_bitmap, pal, iff_transparent_color, -1); break; } case 5: //earth pos case 7: { //station pos vms_matrix tm; vms_angvec ta; int pitch,head; sscanf(p,"%d,%d",&head,&pitch); ta.h = i2f(head)/360; ta.p = -i2f(pitch)/360; ta.b = 0; vm_angles_2_matrix(&tm,&ta); if (var==5) satellite_pos = tm.fvec; //vm_vec_copy_scale(&satellite_pos,&tm.fvec,SATELLITE_DIST); else station_pos = tm.fvec; break; } case 6: //planet size satellite_size = i2f(atoi(p)); break; } var++; } Assert(var == NUM_VARS); // OK, now the data is loaded. Initialize everything //find the exit sequence by searching all segments for a side with //children == -2 for (segnum=0,exit_segnum=-1;exit_segnum==-1 && segnum<=Highest_segment_index;segnum++) for (sidenum=0;sidenum<6;sidenum++) if (Segments[segnum].children[sidenum] == -2) { exit_segnum = segnum; exit_side = sidenum; break; } Assert(exit_segnum!=-1); compute_segment_center(&mine_exit_point,&Segments[exit_segnum]); extract_orient_from_segment(&mine_exit_orient,&Segments[exit_segnum]); compute_center_point_on_side(&mine_side_exit_point,&Segments[exit_segnum],exit_side); vm_vec_scale_add(&mine_ground_exit_point,&mine_exit_point,&mine_exit_orient.uvec,-i2f(20)); //compute orientation of surface { vms_vector tv; vms_matrix exit_orient,tm; vm_angles_2_matrix(&exit_orient,&exit_angles); vm_transpose_matrix(&exit_orient); vm_matrix_x_matrix(&surface_orient,&mine_exit_orient,&exit_orient); vm_copy_transpose_matrix(&tm,&surface_orient); vm_vec_rotate(&tv,&station_pos,&tm); vm_vec_scale_add(&station_pos,&mine_exit_point,&tv,STATION_DIST); vm_vec_rotate(&tv,&satellite_pos,&tm); vm_vec_scale_add(&satellite_pos,&mine_exit_point,&tv,SATELLITE_DIST); vm_vector_2_matrix(&tm,&tv,&surface_orient.uvec,NULL); vm_vec_copy_scale(&satellite_upvec,&tm.uvec,SATELLITE_HEIGHT); } cfclose(ifile); endlevel_data_loaded = 1; }
// ----------------------------------------------------------------------------------------------------------- // 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; const char ORIGINAL = 0; const char LINEAR_INTERPOLATION = 1; const char GEOMETRIC_DRAG = 2; const char STRATEGY = ORIGINAL; 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)); } if(STRATEGY == ORIGINAL) { while (count--) { if (obj->mtype.phys_info.flags & PF_USES_THRUST) { 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 if (obj->mtype.phys_info.flags & PF_USES_THRUST) { 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 (STRATEGY == LINEAR_INTERPOLATION) { vms_vector target_rotvel; vm_vec_copy_scale(&target_rotvel, &obj->mtype.phys_info.rotvel, F1_0); // Target 21.3 FPS -- three iterations for(int i = 0; i < 3; i++) { if (obj->mtype.phys_info.flags & PF_USES_THRUST) { vm_vec_add2(&target_rotvel, &accel); } vm_vec_scale(&target_rotvel,f1_0-drag); } fix target_frametime = F1_0 / 64 * 3; fix interpolation_fraction = fixdiv(FrameTime, target_frametime); vm_vec_sub2(&target_rotvel, &obj->mtype.phys_info.rotvel); vm_vec_scale(&target_rotvel, interpolation_fraction); vm_vec_add2(&obj->mtype.phys_info.rotvel, &target_rotvel); } else if(STRATEGY == GEOMETRIC_DRAG) { while (count--) { if (obj->mtype.phys_info.flags & PF_USES_THRUST) { 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 if (obj->mtype.phys_info.flags & PF_USES_THRUST) { vm_vec_scale_add2(&obj->mtype.phys_info.rotvel,&accel,k); } double target_frametime = 3.0/64.0; const double fix_offset = 65536.0; double interpolation_fraction = ((double)(r) / fix_offset) / target_frametime ; double ddrag = (double)(drag) / fix_offset; double kdrag = pow((1.0 - ddrag), interpolation_fraction*3); fix fractional_drag = (fix)(kdrag * fix_offset); vm_vec_scale(&obj->mtype.phys_info.rotvel,fractional_drag); //vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-fixmul(k,drag)); } /* fix k_drag = f1_0-fixmul(k,drag); if(FrameTime < F1_0/30) { // Pegged to 30 FPS for now double fix_offset = (double) F1_0; double target_framerate = 20.0; double ddrag = ((double) drag)/fix_offset; //double target_drag = (1.0-ddrag)*(1.0-ddrag)*(1.0-ddrag*2.0/15.0); // Drag value multiplied by at 30 hz double target_drag = (1.0-ddrag)*(1.0-ddrag)*(1.0-ddrag)*(1.0-ddrag*2.0/15.0); // Drag value at 20 hz double frame_pow = 20.0 * ((double)(FrameTime)/fix_offset); double frame_drag = pow(target_drag, frame_pow); k_drag = (fix) (frame_drag*fix_offset); } 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)); // CED -- fix this for frame independence! 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)); vm_vec_scale(&obj->mtype.phys_info.rotvel,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)); total_drag = fixmul(total_drag,k_drag); vm_vec_scale(&obj->mtype.phys_info.rotvel,total_drag); } */ } //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); }