2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Hud/HUDbrackets.cpp $
15 * C file that contains functions for drawing target brackets on the HUD
18 * Revision 1.3 2002/06/09 04:41:21 relnev
19 * added copyright header
21 * Revision 1.2 2002/05/07 03:16:45 theoddone33
22 * The Great Newline Fix
24 * Revision 1.1.1.1 2002/05/03 03:28:09 root
28 * 6 8/03/99 5:35p Andsager
29 * Dont draw target dot for instructor in training mission
31 * 5 6/07/99 4:20p Andsager
32 * Add HUD color for tagged object. Apply to target and radar.
34 * 4 12/28/98 3:17p Dave
35 * Support for multiple hud bitmap filenames for hi-res mode.
37 * 3 12/21/98 5:02p Dave
38 * Modified all hud elements to be multi-resolution friendly.
40 * 2 10/07/98 10:53a Dave
43 * 1 10/07/98 10:49a Dave
45 * 54 8/25/98 1:48p Dave
46 * First rev of EMP effect. Player side stuff basically done. Next comes
49 * 53 6/01/98 11:43a John
50 * JAS & MK: Classified all strings for localization.
52 * 52 5/27/98 1:22p Allender
53 * make targeting dots work in multiplayer -- as well as many other minor
56 * 51 5/23/98 2:26a Lawrance
59 * 50 5/14/98 11:26a Lawrance
60 * ensure fighter bays are drawn with correct bracket color
62 * 49 5/12/98 9:27a Mike
63 * num-ships-attacking: always showed an additional ship attacking
64 * asteroid or debris. Fixed.
66 * 48 5/08/98 10:16a Lawrance
67 * Add new "ship attacking count" gauge
69 * 47 5/07/98 4:07p Mike
70 * Use smaller num-ships-attacking blip.
72 * 46 5/06/98 5:30p John
73 * Removed unused cfilearchiver. Removed/replaced some unused/little used
74 * graphics functions, namely gradient_h and _v and pixel_sp. Put in new
75 * DirectX header files and libs that fixed the Direct3D alpha blending
78 * 45 5/06/98 2:46p Mike
79 * Modify num-ships-attacking system.
81 * 44 5/03/98 1:07a Mike
82 * Show + for ships attacking your target, whether hostile or friendly.
84 * 43 4/05/98 7:42p Lawrance
85 * fix inconsistent distance display on the HUD
87 * 42 4/01/98 9:21p John
88 * Made NDEBUG, optimized build with no warnings or errors.
90 * 41 3/30/98 12:20a Lawrance
91 * Draw subsystem targeting brackets gray if subsystem is destroyed.
93 * 40 3/18/98 6:04p Lawrance
94 * Improve when brackets get drawn for large objects
96 * 39 3/10/98 6:03p Lawrance
97 * Ensure proper bracket color gets drawn for traitors
99 * 38 3/06/98 5:13p Johnson
100 * Put in a check for team traitor in hud_brackets_get_iff_color()
102 * 37 3/02/98 11:32p Lawrance
103 * Allow asteroids about to impact ships to be bracketed
105 * 36 2/21/98 2:49p Lawrance
106 * Don't do facing check for subsystems when deciding whether to draw
109 * 35 2/19/98 12:48a Lawrance
110 * Ensure subsystem brackets remain between HUD and target monitor
112 * 34 2/09/98 8:05p Lawrance
113 * Add new gauges: cmeasure success, warp-out, and missiontime
115 * 33 2/07/98 5:46p Lawrance
116 * Show target distance on brackets
118 * 32 1/19/98 11:37p Lawrance
119 * Fixing Optimization build warnings
121 * 31 1/18/98 5:09p Lawrance
122 * Added support for TEAM_TRAITOR
124 * 30 1/02/98 10:01p Lawrance
125 * Ensure correct subsystem bracket color gets drawn once player goes
128 * 29 1/02/98 9:10p Lawrance
129 * Big changes to how colors get set on the HUD.
131 * 28 12/28/97 5:54p Lawrance
132 * Draw HUD brackets the correct IFF color.. taking into account that the
133 * player may be TEAM_NEUTRAL
135 * 27 12/18/97 8:46p Lawrance
136 * Move IFF_color definitions from HUD->ship, so FRED can use them.
138 * 26 12/17/97 11:14p Mike
139 * Change radar and hud color to red for all neutral.
141 * 25 11/27/97 4:24p Lawrance
142 * change appearance of subsystem targeting brackets
144 * 24 10/22/97 5:53p Lawrance
145 * change name of subsystem_in_sight() function
147 * 23 9/06/97 2:13p Mike
148 * Replace support for TEAM_NEUTRAL
150 * 22 7/24/97 10:45a Mike
151 * Fix hole in Unknown team support.
153 * 21 7/24/97 10:24a Mike
154 * Restore support for Unknown team
156 * 20 6/11/97 1:12p John
157 * Started fixing all the text colors in the game.
159 * 19 5/21/97 11:12a Mike
160 * Move more stuff out of player struct, mainly subsys stuff.
162 * 18 5/20/97 2:45p Mike
163 * Move current_target and a bunch of other stuff out of player struct.
165 * 17 4/09/97 3:30p Lawrance
166 * let target brackets grow to bracket ship entirely
168 * 16 4/08/97 1:28p Lawrance
169 * get brackets for targeting and messaging drawing right
171 * 15 4/08/97 11:44a Lawrance
172 * get selection and target brackets drawing right at close and far
175 * 14 4/08/97 10:55a Allender
176 * draw purple brackets on ship sending a message
178 * 13 4/08/97 9:58a Lawrance
179 * center bracket on target center. Give min and max dimensions to
180 * subsystem target brackets.
182 * 12 4/07/97 6:03p Lawrance
183 * draw diamond brackets instead of dashed boxes
185 * 11 4/07/97 3:50p Allender
186 * ability to assign > 1 ship to a hotkey. Enabled use of hotkeys in
187 * squadmate messaging
189 * 10 4/02/97 10:08a Lawrance
190 * fixed bracket drawing glitches
192 * 9 3/28/97 2:46p John
193 * added code to make debris chunks target properly.
195 * 8 3/27/97 5:44p Lawrance
196 * drawing dashed lines for sub-object targeting box that is not in line
199 * 7 3/27/97 3:59p Lawrance
200 * made brackets draw even if center of target is offscreen
202 * 6 3/27/97 9:29a Lawrance
203 * If reach maximum bounding box size, use radius targeting box method
205 * 5 3/25/97 3:55p Lawrance
206 * allowing debris to be targeted and shown on radar
208 * 4 3/23/97 11:55p Lawrance
209 * made max targeting bracket size of 200x200
211 * 3 3/07/97 4:37p Mike
212 * Make rockeye missile home.
213 * Remove UNKNOWN and NEUTRAL teams.
215 * 2 12/24/96 4:30p Lawrance
216 * Target bracket drawing code moved to separate files
221 #include "hudbrackets.h"
224 #include "hudtarget.h"
228 #include "freespace.h"
230 #include "linklist.h"
233 #define FADE_FACTOR 2 // how much the bounding brackets get faded
234 #define LOWEST_RED 50 // lowest r value for bounding bracket
235 #define LOWEST_GREEN 50 // lowest g value for bounding bracket
236 #define LOWEST_BLUE 50 // lowest b value for bounding bracket
238 char Ships_attack_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
243 // resolution adjust factors for the above defines
244 int Min_target_box_width[GR_NUM_RESOLUTIONS] = { 20, 30 };
245 int Min_target_box_height[GR_NUM_RESOLUTIONS] = { 20, 30 };
246 int Min_subtarget_box_width[GR_NUM_RESOLUTIONS] = { 12, 24 };
247 int Min_subtarget_box_height[GR_NUM_RESOLUTIONS] = { 12, 24 };
249 void hud_init_brackets()
253 // find IFF color index for brackets based on team
254 int hud_brackets_get_iff_color(int team)
256 int color=IFF_COLOR_FRIENDLY;
264 if ( (team == Player_ship->team) && (team != TEAM_TRAITOR) ) {
265 color = IFF_COLOR_FRIENDLY;
269 color = IFF_COLOR_NEUTRAL;
272 color = IFF_COLOR_UNKNOWN;
277 color = IFF_COLOR_HOSTILE;
283 color = IFF_COLOR_SELECTION;
287 color = IFF_COLOR_MESSAGE;
291 color = IFF_COLOR_UNKNOWN;
299 // Called by draw_bounding_brackets.
300 void draw_brackets_square(int x1, int y1, int x2, int y2)
309 // make the brackets extend 25% of the way along the width or height
310 int bracket_width = width/4;
311 int bracket_height = height/4;
314 if ( (x1 + bracket_width > 0) && (x1 < gr_screen.clip_width) ){
315 gr_gradient(x1,y1,x1+bracket_width-1,y1); // top left
316 gr_gradient(x1,y2,x1+bracket_width-1,y2); // bottom left
319 if ( (x2 - bracket_width < gr_screen.clip_width) && (x2 > 0) ) {
320 gr_gradient(x2, y1, x2-bracket_width+1,y1); // top right
321 gr_gradient(x2, y2, x2-bracket_width+1,y2); // bottom right
325 if ( (y1 + bracket_height > 0) && (y1 < gr_screen.clip_height) ) {
326 gr_gradient(x1,y1,x1,y1+bracket_height-1); // top left
327 gr_gradient(x2,y1,x2,y1+bracket_height-1); // top right
330 if ( (y2 - bracket_height < gr_screen.clip_height) && (y2 > 0) ) {
331 gr_gradient(x1,y2,x1,y2-bracket_height+1); // bottom left
332 gr_gradient(x2,y2,x2,y2-bracket_height+1); // bottom right
336 void draw_brackets_square_quick(int x1, int y1, int x2, int y2, int thick)
343 // make the brackets extend 25% of the way along the width or height
344 int bracket_width = width/4;
345 int bracket_height = height/4;
348 gr_line(x1,y1,x1+bracket_width,y1);
349 gr_line(x2,y1,x2-bracket_width,y1);
351 gr_line(x1,y1+1,x1+bracket_width,y1+1);
352 gr_line(x2,y1+1,x2-bracket_width,y1+1);
356 gr_line(x1,y2,x1+bracket_width,y2);
357 gr_line(x2,y2,x2-bracket_width,y2);
359 gr_line(x1,y2-1,x1+bracket_width,y2-1);
360 gr_line(x2,y2-1,x2-bracket_width,y2-1);
365 gr_line(x1,y1+2,x1,y1+bracket_height);
366 gr_line(x1,y2-2,x1,y2-bracket_height);
367 gr_line(x1+1,y1+2,x1+1,y1+bracket_height);
368 gr_line(x1+1,y2-2,x1+1,y2-bracket_height);
370 gr_line(x1,y1+1,x1,y1+bracket_height);
371 gr_line(x1,y2-1,x1,y2-bracket_height);
376 gr_line(x2,y1+2,x2,y1+bracket_height);
377 gr_line(x2,y2-2,x2,y2-bracket_height);
378 gr_line(x2-1,y1+2,x2-1,y1+bracket_height);
379 gr_line(x2-1,y2-2,x2-1,y2-bracket_height);
381 gr_line(x2,y1+1,x2,y1+bracket_height);
382 gr_line(x2,y2-1,x2,y2-bracket_height);
388 void draw_brackets_dashed_square_quick(int x1, int y1, int x2, int y2)
390 int width, height, i;
395 // make the brackets extend 25% of the way along the width or height
396 float bracket_width = width/4.0f;
397 float bracket_height = height/4.0f;
400 dash_width = fl2i(bracket_width / ( NUM_DASHES*2 - 1 ) + 0.5f);
402 if ( dash_width < 1 ) {
403 draw_brackets_square_quick(x1, y1, x2, y2);
408 dash_height = fl2i(bracket_height / ( NUM_DASHES*2 - 1 ) + 0.5f);
410 if ( dash_height < 1 ) {
411 draw_brackets_square_quick(x1, y1, x2, y2);
415 int dash_x1, dash_x2, dash_y1, dash_y2;
422 for ( i = 0; i < NUM_DASHES; i++ ) {
424 gr_line(dash_x1, y1, dash_x1+(dash_width-1), y1);
425 gr_line(dash_x2, y1, dash_x2-(dash_width-1), y1);
428 gr_line(dash_x1, y2, dash_x1+(dash_width-1), y2);
429 gr_line(dash_x2, y2, dash_x2-(dash_width-1), y2);
431 dash_x1 += dash_width*2;
432 dash_x2 -= dash_width*2;
435 gr_line(x1, dash_y1, x1, dash_y1+(dash_height-1));
436 gr_line(x1, dash_y2, x1, dash_y2-(dash_height-1));
439 gr_line(x2, dash_y1, x2, dash_y1+(dash_height-1));
440 gr_line(x2, dash_y2, x2, dash_y2-(dash_height-1));
442 dash_y1 += dash_height*2;
443 dash_y2 -= dash_height*2;
450 // draw_brackets_diamond()
451 // Called by draw_bounding_brackets.
453 void draw_brackets_diamond(int x1, int y1, int x2, int y2)
455 int width, height, half_width, half_height;
456 int center_x, center_y;
457 int x_delta, y_delta;
459 float side_len, bracket_len;
464 half_width = fl2i( width/2.0f + 0.5f );
465 half_height = fl2i( height/2.0f +0.5f );
467 side_len = (float)_hypot(half_width, half_height);
468 bracket_len = side_len / 8;
470 x_delta = fl2i(bracket_len * width / side_len + 0.5f);
471 y_delta = fl2i(bracket_len * height / side_len + 0.5f);
474 center_x = x1 + half_width;
475 center_y = y1 + half_height;
478 gr_gradient(center_x - x_delta, y1 + y_delta,center_x, y1);
479 gr_gradient(x1 + x_delta, center_y - y_delta, x1, center_y);
482 gr_gradient(center_x + x_delta, y1 + y_delta,center_x, y1);
483 gr_gradient(x2 - x_delta, center_y - y_delta, x2, center_y);
486 gr_gradient(x1 + x_delta, center_y + y_delta, x1, center_y);
487 gr_gradient(center_x - x_delta, y2 - y_delta, center_x, y2);
490 gr_gradient(x2 - x_delta, center_y + y_delta, x2, center_y);
491 gr_gradient(center_x + x_delta, y2 - y_delta, center_x, y2);
494 void draw_brackets_diamond_quick(int x1, int y1, int x2, int y2, int thick)
496 int width, height, half_width, half_height;
497 int center_x, center_y;
498 int x_delta, y_delta;
500 float side_len, bracket_len;
505 half_width = fl2i( width/2.0f + 0.5f);
506 half_height = fl2i( height/2.0f + 0.5f);
508 side_len = (float)_hypot(half_width, half_height);
509 bracket_len = side_len / 8;
511 x_delta = fl2i(bracket_len * width / side_len + 0.5f);
512 y_delta = fl2i(bracket_len * height / side_len + 0.5f);
514 center_x = x1 + half_width;
515 center_y = y1 + half_height;
518 gr_line(center_x - x_delta, y1 + y_delta,center_x, y1);
519 gr_line(x1 + x_delta, center_y - y_delta, x1, center_y);
522 gr_line(center_x + x_delta, y1 + y_delta,center_x, y1);
523 gr_line(x2 - x_delta, center_y - y_delta, x2, center_y);
526 gr_line(x1 + x_delta, center_y + y_delta, x1, center_y);
527 gr_line(center_x - x_delta, y2 - y_delta, center_x, y2);
530 gr_line(x2 - x_delta, center_y + y_delta, x2, center_y);
531 gr_line(center_x + x_delta, y2 - y_delta, center_x, y2);
533 // draw an 'X' in the middle of the brackets
534 gr_line(center_x-x_delta, center_y-y_delta, center_x+x_delta, center_y+y_delta);
535 gr_line(center_x-x_delta, center_y+y_delta, center_x+x_delta, center_y-y_delta);
539 int subsys_is_fighterbay(ship_subsys *ss)
541 if ( !strnicmp(NOX("fighter"), ss->system_info->name, 7) ) {
548 // Draw bounding brackets for a subobject.
549 void draw_bounding_brackets_subobject()
551 if (Player_ai->targeted_subsys_parent == Player_ai->target_objnum)
552 if (Player_ai->targeted_subsys != NULL) {
556 vertex subobj_vertex;
560 subsys = Player_ai->targeted_subsys;
561 target_objnum = Player_ai->target_objnum;
562 Assert(target_objnum != -1);
563 targetp = &Objects[target_objnum];
564 Assert( targetp->type == OBJ_SHIP );
566 get_subsystem_world_pos(targetp, subsys, &subobj_pos);
568 g3_rotate_vertex(&subobj_vertex,&subobj_pos);
570 g3_project_vertex(&subobj_vertex);
571 if (subobj_vertex.flags & PF_OVERFLOW) // if overflow, no point in drawing brackets
574 int subobj_x = fl2i(subobj_vertex.sx + 0.5f);
575 int subobj_y = fl2i(subobj_vertex.sy + 0.5f);
576 int hud_subtarget_w, hud_subtarget_h, bound_rc;
578 bound_rc = subobj_find_2d_bound(subsys->system_info->radius, &targetp->orient, &subobj_pos, &x1,&y1,&x2,&y2);
582 hud_subtarget_w = x2-x1+1;
583 if ( hud_subtarget_w > gr_screen.clip_width ) {
584 hud_subtarget_w = gr_screen.clip_width;
587 hud_subtarget_h = y2-y1+1;
588 if ( hud_subtarget_h > gr_screen.clip_height ) {
589 hud_subtarget_h = gr_screen.clip_height;
592 if ( hud_subtarget_w > gr_screen.max_w ) {
593 x1 = subobj_x - (gr_screen.max_w>>1);
594 x2 = subobj_x + (gr_screen.max_w>>1);
596 if ( hud_subtarget_h > gr_screen.max_h ) {
597 y1 = subobj_y - (gr_screen.max_h>>1);
598 y2 = subobj_y + (gr_screen.max_h>>1);
601 if ( hud_subtarget_w < Min_subtarget_box_width[gr_screen.res] ) {
602 x1 = subobj_x - (Min_subtarget_box_width[gr_screen.res]>>1);
603 x2 = subobj_x + (Min_subtarget_box_width[gr_screen.res]>>1);
605 if ( hud_subtarget_h < Min_subtarget_box_height[gr_screen.res] ) {
606 y1 = subobj_y - (Min_subtarget_box_height[gr_screen.res]>>1);
607 y2 = subobj_y + (Min_subtarget_box_height[gr_screen.res]>>1);
610 // determine if subsystem is on far or near side of the ship
611 Player->subsys_in_view = ship_subsystem_in_sight(targetp, subsys, &View_position, &subobj_pos, 0);
613 // AL 29-3-98: If subsystem is destroyed, draw gray brackets
614 if ( (Player_ai->targeted_subsys->current_hits <= 0) && (!subsys_is_fighterbay(Player_ai->targeted_subsys)) ) {
615 gr_set_color_fast(&IFF_colors[IFF_COLOR_MESSAGE][1]);
617 hud_set_iff_color( targetp, 1 );
620 if ( Player->subsys_in_view ) {
621 draw_brackets_square_quick(x1, y1, x2, y2);
623 draw_brackets_diamond_quick(x1, y1, x2, y2);
625 // mprintf(("Drawing subobject brackets at %4i, %4i\n", sx, sy));
629 extern int HUD_drew_selection_bracket_on_target;
631 // Display the current target distance, right justified at (x,y)
632 void hud_target_show_dist_on_bracket(int x, int y, float distance)
637 if ( y < 0 || y > gr_screen.clip_height ) {
641 if ( x < 0 || x > gr_screen.clip_width ) {
645 sprintf(text_dist, "%d", fl2i(distance+0.5f));
646 hud_num_make_mono(text_dist);
647 gr_get_string_size(&w,&h,text_dist);
650 if ( HUD_drew_selection_bracket_on_target ) {
654 gr_string(x - w+2, y+y_delta, text_dist);
659 // Given an object number, return the number of ships attacking it.
660 // MWA 5/26/98 -- copied from aicode num_attacking_ships()!!!
662 int hud_bracket_num_ships_attacking(int objnum)
668 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
669 objp = &Objects[so->objnum];
670 if (objp->instance != -1) {
672 aip = &Ai_info[Ships[objp->instance].ai_index];
674 // don't count instructor
675 int is_training_mission();
676 if ( is_training_mission() && stricmp(Ships[objp->instance].ship_name, "Instructor") == 0) {
680 if ( ((Game_mode & GM_MULTIPLAYER) || (aip->mode == AIM_CHASE)) && (aip->target_objnum == objnum))
681 if (Ships[objp->instance].team != Ships[Objects[objnum].instance].team)
690 int Ships_attacking_bitmap = -1;
692 // draw_bounding_brackets() will draw the faded brackets that surround the current target
693 void draw_bounding_brackets(int x1, int y1, int x2, int y2, int w_correction, int h_correction, float distance, int target_objnum)
697 if ( ( x1 < 0 && x2 < 0 ) || ( y1 < 0 && y2 < 0 ) )
700 if ( ( x1 > gr_screen.clip_width && x2 > gr_screen.clip_width ) ||
701 ( y1 > gr_screen.clip_height && y2 > gr_screen.clip_height ) )
710 if ( (width>(gr_screen.max_w - 1)) && (height>(gr_screen.max_h - 1)) ) {
713 if ( width > 1200 ) {
717 if ( height > 1200) {
721 if (width < Min_target_box_width[gr_screen.res]) {
722 x1 = x1 - (Min_target_box_width[gr_screen.res]-width)/2;
723 x2 = x2 + (Min_target_box_width[gr_screen.res]-width)/2;
726 if (height < Min_target_box_height[gr_screen.res]) {
727 y1 = y1 - (Min_target_box_height[gr_screen.res]-height)/2;
728 y2 = y2 + (Min_target_box_height[gr_screen.res]-height)/2;
731 draw_brackets_square(x1-w_correction, y1-h_correction, x2+w_correction, y2+h_correction);
733 // draw distance to target in lower right corner of box
734 if ( distance > 0 ) {
735 hud_target_show_dist_on_bracket(x2+w_correction,y2+h_correction,distance);
738 // Maybe show + for each additional fighter or bomber attacking target.
739 if ( (target_objnum != -1) && hud_gauge_active(HUD_ATTACKING_TARGET_COUNT) ) {
740 int num_attacking = hud_bracket_num_ships_attacking(target_objnum);
742 if (Ships_attacking_bitmap == -1){
743 Ships_attacking_bitmap = bm_load(Ships_attack_fname[gr_screen.res]);
746 if (Ships_attacking_bitmap == -1) {
751 // If a ship not on player's team, show one fewer plus since it is targeted and attacked by player.
753 if (Objects[target_objnum].type == OBJ_SHIP) {
754 if (Ships[Objects[target_objnum].instance].team != Player_ship->team){
761 if (num_attacking > k) {
764 num_blips = num_attacking-k;
769 //int bitmap = get_blip_bitmap();
771 if (Ships_attacking_bitmap > -1) {
775 for (i=0; i<num_blips; i++) {
776 GR_AABITMAP(Ships_attacking_bitmap, x2+3, y1+i*7);