void HudGaugeRadarOrb::drawContact(vec3d *pnt, int rad) { vertex verts[2]; vec3d p; p=*pnt; vm_vec_normalize(&p); g3_rotate_vertex(&verts[0], &p); g3_project_vertex(&verts[0]); g3_rotate_vertex(&verts[1], pnt); g3_project_vertex(&verts[1]); float size = fl_sqrt(vm_vec_dist(&Orb_eye_position, pnt) * 8.0f); if (size < i2fl(rad)) size = i2fl(rad); if (rad == Radar_blip_radius_target) { g3_draw_sphere(&verts[1],size/100.0f); } else { g3_draw_sphere(&verts[1],size/300.0f); } g3_draw_line(&verts[0],&verts[1]); }
void HudGaugeRadarOrb::drawOutlines() { int i; vertex center; // vertex extents[6]; vertex proj_orb_lines_xy[NUM_ORB_RING_SLICES]; vertex proj_orb_lines_xz[NUM_ORB_RING_SLICES]; vertex proj_orb_lines_yz[NUM_ORB_RING_SLICES]; g3_start_instance_matrix(&vmd_zero_vector, &view_perturb, false); g3_start_instance_matrix(&vmd_zero_vector, &Player_obj->orient, false); g3_rotate_vertex(¢er, &vmd_zero_vector); g3_rotate_vertex(&proj_orb_lines_xy[0], &orb_ring_xy[0]); g3_rotate_vertex(&proj_orb_lines_yz[0], &orb_ring_yz[0]); g3_rotate_vertex(&proj_orb_lines_xz[0], &orb_ring_xz[0]); g3_project_vertex(¢er); gr_set_color(255,255,255); g3_draw_sphere(¢er, .05f); g3_project_vertex(&proj_orb_lines_xy[0]); g3_project_vertex(&proj_orb_lines_yz[0]); g3_project_vertex(&proj_orb_lines_xz[0]); for (i=1; i < NUM_ORB_RING_SLICES; i++) { g3_rotate_vertex(&proj_orb_lines_xy[i], &orb_ring_xy[i]); g3_rotate_vertex(&proj_orb_lines_yz[i], &orb_ring_yz[i]); g3_rotate_vertex(&proj_orb_lines_xz[i], &orb_ring_xz[i]); g3_project_vertex(&proj_orb_lines_xy[i]); g3_project_vertex(&proj_orb_lines_yz[i]); g3_project_vertex(&proj_orb_lines_xz[i]); gr_set_color(192,96,32); g3_draw_sphere(&proj_orb_lines_xy[i-1], .01f); g3_draw_sphere(&proj_orb_lines_xz[i-1], .01f); g3_draw_line(&proj_orb_lines_xy[i-1],&proj_orb_lines_xy[i]); g3_draw_line(&proj_orb_lines_xz[i-1],&proj_orb_lines_xz[i]); gr_set_color(112,16,192); g3_draw_sphere(&proj_orb_lines_yz[i-1], .01f); g3_draw_line(&proj_orb_lines_yz[i-1],&proj_orb_lines_yz[i]); } g3_done_instance(false); }
// Decide which point lock should be homing on void hud_lock_determine_lock_point(vector *lock_world_pos_out) { vector lock_world_pos; vertex lock_point; object *target_objp; Assert(Player_ai->target_objnum >= 0); target_objp = &Objects[Player_ai->target_objnum]; Player->current_target_sx = -1; Player->current_target_sx = -1; // If subsystem is targeted, we must try to lock on that if ( Player_ai->targeted_subsys ) { hud_lock_update_lock_pos(target_objp, &lock_world_pos); Player->locking_on_center=0; Player->locking_subsys=NULL; Player->locking_subsys_parent=-1; } else { // See if we already have a successful locked point if ( hud_lock_has_homing_point() ) { hud_lock_update_lock_pos(target_objp, &lock_world_pos); } else { hud_lock_get_new_lock_pos(target_objp, &lock_world_pos); } } *lock_world_pos_out=lock_world_pos; g3_rotate_vertex(&lock_point,&lock_world_pos); g3_project_vertex(&lock_point); if (!(lock_point.flags & PF_OVERFLOW)) { // make sure point projected Player->current_target_sx = (int)lock_point.sx; Player->current_target_sy = (int)lock_point.sy; } }
// Draw a laser shaped 3d looking thing using vertex coloring (useful for things like colored laser glows) // If max_len is > 1.0, then this caps the length to be no longer than max_len pixels float g3_draw_laser_rgb(vec3d* headp, float head_width, vec3d* tailp, float tail_width, int r, int g, int b, uint tmap_flags, float max_len) { if (!Lasers) { return 0.0f; } if ((!Cmdline_nohtl) && tmap_flags & TMAP_HTL_3D_UNLIT ) { // &&(gr_screen.mode==GR_OPENGL)) { return g3_draw_laser_htl(headp, head_width, tailp, tail_width, r, g, b, tmap_flags | TMAP_HTL_3D_UNLIT); } float headx, heady, headr, tailx, taily, tailr; vertex pt1, pt2; float depth; int head_on = 0; Assert(G3_count == 1); g3_rotate_vertex(&pt1, headp); g3_project_vertex(&pt1); if (pt1.flags & PF_OVERFLOW) return 0.0f; g3_rotate_vertex(&pt2, tailp); g3_project_vertex(&pt2); if (pt2.flags & PF_OVERFLOW) return 0.0f; if ((pt1.codes & pt2.codes) != 0) { // Both off the same side return 0.0f; } headx = pt1.sx; heady = pt1.sy; headr = (head_width * Matrix_scale.xyz.x * Canv_w2 * pt1.sw); tailx = pt2.sx; taily = pt2.sy; tailr = (tail_width * Matrix_scale.xyz.x * Canv_w2 * pt2.sw); float len_2d = fl_sqrt((tailx - headx) * (tailx - headx) + (taily - heady) * (taily - heady)); // Cap the length if needed. if ((max_len > 1.0f) && (len_2d > max_len)) { float ratio = max_len / len_2d; tailx = headx + (tailx - headx) * ratio; taily = heady + (taily - heady) * ratio; tailr = headr + (tailr - headr) * ratio; len_2d = fl_sqrt((tailx - headx) * (tailx - headx) + (taily - heady) * (taily - heady)); } depth = (pt1.z + pt2.z) * 0.5f; float max_r = headr; float a; if (tailr > max_r) max_r = tailr; if (max_r < 1.0f) max_r = 1.0f; float mx, my, w, h1, h2; if (len_2d < max_r) { h1 = headr + (max_r - len_2d); if (h1 > max_r) h1 = max_r; h2 = tailr + (max_r - len_2d); if (h2 > max_r) h2 = max_r; len_2d = max_r; if (fl_abs(tailx - headx) > 0.01f) { a = (float)atan2(taily - heady, tailx - headx); } else { a = 0.0f; } w = len_2d; head_on = 1; } else { a = atan2_safe(taily - heady, tailx - headx); w = len_2d; h1 = headr; h2 = tailr; head_on = 0; } mx = (tailx + headx) / 2.0f; my = (taily + heady) / 2.0f; // gr_set_color(255,0,0); // g3_draw_line( &pt1, &pt2 ); // gr_set_color( 255, 0, 0 ); // gr_pixel( fl2i(mx),fl2i(my) ); // Draw box with width 'w' and height 'h' at angle 'a' from horizontal // centered around mx, my if (h1 < 1.0f) h1 = 1.0f; if (h2 < 1.0f) h2 = 1.0f; float sa, ca; sa = (float)sin(a); ca = (float)cos(a); vertex v[4]; vertex* vertlist[4] = { &v[3], &v[2], &v[1], &v[0] }; memset(v, 0, sizeof(vertex) * 4); float sw; if (depth < 0.0f) depth = 0.0f; sw = 1.0f / depth; v[0].sx = (-w / 2.0f) * ca + (-h1 / 2.0f) * sa + mx; v[0].sy = (-w / 2.0f) * sa - (-h1 / 2.0f) * ca + my; v[0].z = pt1.z; v[0].sw = pt1.sw; v[0].u = 0.0f; v[0].v = 0.0f; v[0].r = (ubyte)r; v[0].g = (ubyte)g; v[0].b = (ubyte)b; v[0].a = 255; v[1].sx = (w / 2.0f) * ca + (-h2 / 2.0f) * sa + mx; v[1].sy = (w / 2.0f) * sa - (-h2 / 2.0f) * ca + my; v[1].z = pt2.z; v[1].sw = pt2.sw; v[1].u = 1.0f; v[1].v = 0.0f; v[1].r = (ubyte)r; v[1].g = (ubyte)g; v[1].b = (ubyte)b; v[1].a = 255; v[2].sx = (w / 2.0f) * ca + (h2 / 2.0f) * sa + mx; v[2].sy = (w / 2.0f) * sa - (h2 / 2.0f) * ca + my; v[2].z = pt2.z; v[2].sw = pt2.sw; v[2].u = 1.0f; v[2].v = 1.0f; v[2].r = (ubyte)r; v[2].g = (ubyte)g; v[2].b = (ubyte)b; v[2].a = 255; v[3].sx = (-w / 2.0f) * ca + (h1 / 2.0f) * sa + mx; v[3].sy = (-w / 2.0f) * sa - (h1 / 2.0f) * ca + my; v[3].z = pt1.z; v[3].sw = pt1.sw; v[3].u = 0.0f; v[3].v = 1.0f; v[3].r = (ubyte)r; v[3].g = (ubyte)g; v[3].b = (ubyte)b; v[3].a = 255; gr_tmapper(4, vertlist, tmap_flags | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT); return depth; }
// This assumes you have already set a color with gr_set_color or gr_set_color_fast // and a bitmap with gr_set_bitmap. If it is very far away, it draws the laser // as flat-shaded using current color, else textured using current texture. // If max_len is > 1.0, then this caps the length to be no longer than max_len pixels. float g3_draw_laser(vec3d *headp, float head_width, vec3d *tailp, float tail_width, uint tmap_flags, float max_len ) { if (!Lasers) { return 0.0f; } if ( !Cmdline_nohtl && (tmap_flags & TMAP_HTL_3D_UNLIT) ) { return g3_draw_laser_htl(headp, head_width, tailp, tail_width, 255,255,255, tmap_flags | TMAP_HTL_3D_UNLIT); } float headx, heady, headr, tailx, taily, tailr; vertex pt1, pt2; float depth; Assert( G3_count == 1 ); g3_rotate_vertex(&pt1,headp); g3_project_vertex(&pt1); if (pt1.flags & PF_OVERFLOW) return 0.0f; g3_rotate_vertex(&pt2,tailp); g3_project_vertex(&pt2); if (pt2.flags & PF_OVERFLOW) return 0.0f; if ( (pt1.codes & pt2.codes) != 0 ) { // Both off the same side return 0.0f; } headx = pt1.screen.xyw.x; heady = pt1.screen.xyw.y; headr = (head_width*Matrix_scale.xyz.x*Canv_w2*pt1.screen.xyw.w); tailx = pt2.screen.xyw.x; taily = pt2.screen.xyw.y; tailr = (tail_width*Matrix_scale.xyz.x*Canv_w2*pt2.screen.xyw.w); float len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) ); // Cap the length if needed. if ( (max_len > 1.0f) && (len_2d > max_len) ) { float ratio = max_len / len_2d; tailx = headx + ( tailx - headx ) * ratio; taily = heady + ( taily - heady ) * ratio; tailr = headr + ( tailr - headr ) * ratio; len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) ); } depth = (pt1.world.xyz.z+pt2.world.xyz.z)*0.5f; float max_r = headr; float a; if ( tailr > max_r ) max_r = tailr; if ( max_r < 1.0f ) max_r = 1.0f; float mx, my, w, h1,h2; if ( len_2d < max_r ) { h1 = headr + (max_r-len_2d); if ( h1 > max_r ) h1 = max_r; h2 = tailr + (max_r-len_2d); if ( h2 > max_r ) h2 = max_r; len_2d = max_r; if ( fl_abs(tailx - headx) > 0.01f ) { a = (float)atan2( taily-heady, tailx-headx ); } else { a = 0.0f; } w = len_2d; } else { a = atan2_safe( taily-heady, tailx-headx ); w = len_2d; h1 = headr; h2 = tailr; } mx = (tailx+headx)/2.0f; my = (taily+heady)/2.0f; // Draw box with width 'w' and height 'h' at angle 'a' from horizontal // centered around mx, my if ( h1 < 1.0f ) h1 = 1.0f; if ( h2 < 1.0f ) h2 = 1.0f; float sa, ca; sa = (float)sin(a); ca = (float)cos(a); vertex v[4]; vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] }; memset(v,0,sizeof(vertex)*4); if ( depth < 0.0f ) depth = 0.0f; v[0].screen.xyw.x = (-w/2.0f)*ca + (-h1/2.0f)*sa + mx; v[0].screen.xyw.y = (-w/2.0f)*sa - (-h1/2.0f)*ca + my; v[0].world.xyz.z = pt1.world.xyz.z; v[0].screen.xyw.w = pt1.screen.xyw.w; v[0].texture_position.u = 0.0f; v[0].texture_position.v = 0.0f; v[0].b = 191; v[1].screen.xyw.x = (w/2.0f)*ca + (-h2/2.0f)*sa + mx; v[1].screen.xyw.y = (w/2.0f)*sa - (-h2/2.0f)*ca + my; v[1].world.xyz.z = pt2.world.xyz.z; v[1].screen.xyw.w = pt2.screen.xyw.w; v[1].texture_position.u = 1.0f; v[1].texture_position.v = 0.0f; v[1].b = 191; v[2].screen.xyw.x = (w/2.0f)*ca + (h2/2.0f)*sa + mx; v[2].screen.xyw.y = (w/2.0f)*sa - (h2/2.0f)*ca + my; v[2].world.xyz.z = pt2.world.xyz.z; v[2].screen.xyw.w = pt2.screen.xyw.w; v[2].texture_position.u = 1.0f; v[2].texture_position.v = 1.0f; v[2].b = 191; v[3].screen.xyw.x = (-w/2.0f)*ca + (h1/2.0f)*sa + mx; v[3].screen.xyw.y = (-w/2.0f)*sa - (h1/2.0f)*ca + my; v[3].world.xyz.z = pt1.world.xyz.z; v[3].screen.xyw.w = pt1.screen.xyw.w; v[3].texture_position.u = 0.0f; v[3].texture_position.v = 1.0f; v[3].b = 191; gr_tmapper(4, vertlist, tmap_flags | TMAP_FLAG_CORRECT); return depth; }
// hud_show_lock_indicator() will display the lock indicator for homing missiles. // lock_point_pos should be the world coordinates of the target being locked. Assuming all the // necessary locking calculations are done for this frame, this function will compute // where the indicator should be relative to the player's viewpoint and will render accordingly. void HudGaugeLock::render(float frametime) { int target_objnum, sx, sy; object *targetp; vertex lock_point; bool locked = Player_ai->current_target_is_locked ? true : false; bool reset_timers = false; if ( locked != Last_lock_status ) { // check if player lock status has changed since the last frame. reset_timers = true; Last_lock_status = locked; } if (Player_ai->target_objnum == -1) { return; } if (Player->target_is_dying) { return; } if (!Players[Player_num].lock_indicator_visible){ return; } target_objnum = Player_ai->target_objnum; Assert(target_objnum != -1); targetp = &Objects[target_objnum]; // check to see if there are any missile to fire.. we don't want to show the // lock indicator if there are missiles to fire. if ( !ship_secondary_bank_has_ammo(Player_obj->instance) ) { return; } bool in_frame = g3_in_frame() > 0; if(!in_frame) g3_start_frame(0); gr_set_screen_scale(base_w, base_h); // Get the target's current position on the screen. If he's not on there, // we're not going to draw the lock indicator even if he's in front // of our ship, so bail out. g3_rotate_vertex(&lock_point, &lock_world_pos); g3_project_vertex(&lock_point); if (lock_point.codes & PF_OVERFLOW) { gr_reset_screen_scale(); if(!in_frame) g3_end_frame(); return; } hud_set_iff_color(targetp); // nprintf(("Alan","lockx: %d, locky: %d TargetX: %d, TargetY: %d\n", Players[Player_num].lock_indicator_x, Players[Player_num].lock_indicator_y, Player->current_target_sx, Player->current_target_sy)); // We have the coordinates of the lock indicator relative to the target in our "virtual frame" // so, we calculate where it should be drawn based on the player's viewpoint. if (Player_ai->current_target_is_locked) { sx = fl2i(lock_point.screen.xyw.x); sy = fl2i(lock_point.screen.xyw.y); gr_unsize_screen_pos(&sx, &sy); // show the rotating triangles if target is locked renderLockTriangles(sx, sy, frametime); if ( reset_timers ) { Lock_gauge.time_elapsed = 0.0f; } } else { const float scaling_factor = (gr_screen.clip_center_x < gr_screen.clip_center_y) ? (gr_screen.clip_center_x / VIRTUAL_FRAME_HALF_WIDTH) : (gr_screen.clip_center_y / VIRTUAL_FRAME_HALF_HEIGHT); sx = fl2i(lock_point.screen.xyw.x) - fl2i(i2fl(Player->current_target_sx - Players[Player_num].lock_indicator_x) * scaling_factor); sy = fl2i(lock_point.screen.xyw.y) - fl2i(i2fl(Player->current_target_sy - Players[Player_num].lock_indicator_y) * scaling_factor); gr_unsize_screen_pos(&sx, &sy); if ( reset_timers ) { Lock_gauge_draw_stamp = -1; Lock_gauge_draw = 0; Lock_anim.time_elapsed = 0.0f; } } // show locked indicator Lock_gauge.sx = sx - Lock_gauge_half_w; Lock_gauge.sy = sy - Lock_gauge_half_h; if (Player_ai->current_target_is_locked) { hud_anim_render(&Lock_gauge, 0.0f, 1); } else { hud_anim_render(&Lock_gauge, frametime, 1); } gr_reset_screen_scale(); if(!in_frame) g3_end_frame(); }
// hud_show_lock_indicator() will display the lock indicator for homing missiles. // lock_point_pos should be the world coordinates of the target being locked. Assuming all the // necessary locking calculations are done for this frame, this function will compute // where the indicator should be relative to the player's viewpoint and will render accordingly. void hud_show_lock_indicator(float frametime, vec3d* lock_point_pos) { int target_objnum, sx, sy; object* targetp; vertex lock_point; if (!Players[Player_num].lock_indicator_visible) { return; } target_objnum = Player_ai->target_objnum; Assert(target_objnum != -1); targetp = &Objects[target_objnum]; // check to see if there are any missile to fire.. we don't want to show the // lock indicator if there are missiles to fire. if (!ship_secondary_bank_has_ammo(Player_obj->instance)) { return; } // Get the target's current position on the screen. If he's not on there, // we're not going to draw the lock indicator even if he's in front // of our ship, so bail out. g3_rotate_vertex(&lock_point, lock_point_pos); g3_project_vertex(&lock_point); if (lock_point.codes & PF_OVERFLOW) return; hud_set_iff_color(targetp); // nprintf(("Alan","lockx: %d, locky: %d TargetX: %d, TargetY: %d\n", Players[Player_num].lock_indicator_x, Players[Player_num].lock_indicator_y, Player->current_target_sx, Player->current_target_sy)); // We have the coordinates of the lock indicator relative to the target in our "virtual frame" // so, we calculate where it should be drawn based on the player's viewpoint. if (Player_ai->current_target_is_locked) { sx = fl2i(lock_point.sx); sy = fl2i(lock_point.sy); gr_unsize_screen_pos(&sx, &sy); // show the rotating triangles if target is locked hud_draw_lock_triangles(sx, sy, frametime); } else { sx = fl2i(lock_point.sx) - (Player->current_target_sx - Players[Player_num].lock_indicator_x); sy = fl2i(lock_point.sy) - (Player->current_target_sy - Players[Player_num].lock_indicator_y); gr_unsize_screen_pos(&sx, &sy); } // show locked indicator /* if ( Lock_gauge.first_frame >= 0 ) { gr_set_bitmap(Lock_gauge.first_frame); gr_aabitmap(sx - Lock_gauge_half_w[gr_screen.res], sy - Lock_gauge_half_h[gr_screen.res]); } else { hud_draw_diamond(sx, sy, Lock_target_box_width[gr_screen.res], Lock_target_box_height[gr_screen.res]); } */ Lock_gauge.sx = sx - Lock_gauge_half_w[Hud_reticle_style][gr_screen.res]; Lock_gauge.sy = sy - Lock_gauge_half_h[gr_screen.res]; if (Player_ai->current_target_is_locked) { Lock_gauge.time_elapsed = 0.0f; hud_anim_render(&Lock_gauge, 0.0f, 1); } else { hud_anim_render(&Lock_gauge, frametime, 1); } }