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/fred2/FredRender.cpp $
15 * Handles rendering the scene in the window for Fred. Also handles several other
16 * miscellaneous tasks.
19 * Revision 1.3 2002/06/09 04:41:16 relnev
20 * added copyright header
22 * Revision 1.2 2002/05/07 03:16:44 theoddone33
23 * The Great Newline Fix
25 * Revision 1.1.1.1 2002/05/03 03:28:08 root
29 * 6 4/07/99 6:21p Dave
30 * Fred and Freespace support for multiple background bitmaps and suns.
31 * Fixed link errors on all subprojects. Moved encrypt_init() to
32 * cfile_init() and lcl_init(), since its safe to call twice.
34 * 5 3/26/99 4:49p Dave
35 * Made cruisers able to dock with stuff. Made docking points and paths
38 * 4 2/07/99 8:51p Andsager
39 * Add inner bound to asteroid field. Inner bound tries to stay astroid
40 * free. Wrap when within and don't throw at ships inside.
42 * 3 1/27/99 4:09p Andsager
43 * Added highlight to ship subsystems
45 * 2 10/07/98 6:28p Dave
46 * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
47 * Fred. Globalized mission and campaign file extensions. Removed Silent
48 * Threat specific code.
50 * 1 10/07/98 3:02p Dave
52 * 1 10/07/98 3:00p Dave
54 * 162 5/21/98 12:58a Hoffoss
55 * Fixed warnings optimized build turned up.
57 * 161 4/11/98 6:53p John
58 * Added first rev of subspace effect.
60 * 160 4/07/98 4:17p John
61 * Made Fred be able to move suns. Made suns actually affect the lighting
64 * 159 3/21/98 7:36p Lawrance
65 * Move jump nodes to own lib.
67 * 158 3/19/98 11:41a Hoffoss
68 * Fixed problems with rendering and reading of flying controls in Fred.
70 * 157 3/14/98 5:11p Hoffoss
71 * Changed the starting camera position and orientation for Fred.
73 * 156 3/10/98 4:24p Hoffoss
74 * Made object detection under cursor use the object's radius if it has
77 * 155 3/10/98 4:18p John
78 * Cleaned up graphics lib. Took out most unused gr functions. Made D3D
79 * & Glide have popups and print screen. Took out all >8bpp software
80 * support. Made Fred zbuffer. Made zbuffer allocate dynamically to
81 * support Fred. Made zbuffering key off of functions rather than one
84 * 154 3/10/98 1:41p Sandeep
86 * 153 3/09/98 10:56a Hoffoss
87 * Added jump node objects to Fred.
89 * 152 3/03/98 11:00a Andsager
90 * Fixed fred bug with control object initialization.
92 * 151 2/18/98 6:45p Hoffoss
93 * Added support for lines between icons in briefings for Fred.
95 * 150 2/12/98 3:48p Hoffoss
96 * Reduced scaler for extra precision.
98 * 149 2/10/98 6:43p Lawrance
99 * Moved asteroid code to a separate lib.
101 * 148 2/06/98 3:08p Mike
102 * More asteroid stuff, including resolving conflicts between the two
103 * asteroid_field structs!
105 * 147 1/27/98 11:02a John
106 * Added first rev of sparks. Made all code that calls model_render call
107 * clear_instance first. Made debris pieces not render by default when
108 * clear_instance is called.
110 * 146 1/16/98 2:22p Hoffoss
111 * Changed rendering colors of objects.
113 * 145 12/29/97 5:09p Allender
114 * fixed problems with speed not being reported properly in multiplayer
115 * games. Made read_flying_controls take frametime as a parameter. More
116 * ship/weapon select stuff
118 * 144 10/30/97 3:30p Hoffoss
119 * Made anti-aliased gridlines an option in Fred.
121 * 143 10/29/97 5:13p John
122 * Trying to fix my lighting bugs in Fred.
124 * 142 10/03/97 9:48a John
125 * took out alphacolors some grid lines don't draw antialiased.
127 * 141 10/03/97 8:55a John
128 * moved Fred's grid_render code out of MissionGrid and into Fred. Added
129 * code to turn background under overlays grey.
131 * 140 9/18/97 9:59a John
132 * fixed bug I caused in model_collide
134 * 139 9/16/97 9:41p Hoffoss
135 * Changed Fred code around to stop using Parse_player structure for
136 * player information, and use actual ships instead.
138 * 138 9/09/97 2:12p Hoffoss
139 * Added code to allow briefing editor view to be a 1:1 pixel size fixed
140 * as the FreeSpace view will have.
142 * 137 9/06/97 2:13p Mike
143 * Replace support for TEAM_NEUTRAL
145 * 136 8/29/97 5:41p Johnson
146 * Fixed bug with controlling marked objects without having done any
147 * rotations yet of any other type.
149 * 135 8/25/97 5:58p Hoffoss
150 * Created menu items for keypress functions in Fred, and fixed bug this
151 * uncovered with wing_delete function.
153 * 134 8/19/97 5:46p Hoffoss
154 * Changed font used in Fred, and added display to show current eye
157 * 133 8/19/97 11:23a Hoffoss
158 * Fixes to briefing editor icon select code.
160 * 132 8/17/97 10:22p Hoffoss
161 * Fixed several bugs in Fred with Undo feature. In the process, recoded
162 * a lot of CFile.cpp.
164 * 131 8/16/97 2:02a Hoffoss
165 * Made docked objects move together in Fred.
167 * 130 8/14/97 7:01p Hoffoss
168 * Fixed bug with outline rendering while in background bitmap editing
171 * 129 8/14/97 2:32p Hoffoss
172 * fixed bug where controlling an object doesn't cause screen updates, and
173 * added a number of cool features to viewpoint/control object code.
175 * 128 8/13/97 1:38p Hoffoss
176 * Added ability to update multiple times, which in needed in one case to
177 * brute force redraw so deleted ships actually do get removed from the
180 * 127 8/12/97 1:55a Hoffoss
181 * Made extensive changes to object reference checking and handling for
182 * object deletion call.
184 * 126 8/07/97 6:01p Hoffoss
185 * Added a rotate about selected object button to toolbar and
186 * functionality, as requested by Comet.
188 * 125 8/06/97 7:55p Hoffoss
189 * Fixed bug with objects not seeming to be where they are drawn (due to
190 * new briefing clip render stuff). This caused rendering problems,
191 * though. So I fixed those next.
193 * 124 8/06/97 6:10p Hoffoss
194 * Changed Fred to display a forced aspect ratio while briefing editor is
195 * open. This aspect ratio is the same as the briefing view in FreeSpace,
196 * so icons appear on and off screen the same as would be in FreeSpace.
198 * 123 7/24/97 10:24a Mike
199 * Restore support for Unknown team
201 * 122 7/17/97 1:34p Hoffoss
202 * Fixed Fred to work with physics changes.
204 * 121 6/26/97 6:03p Hoffoss
205 * briefing icon selection now has higher priority of selection than other
208 * 120 6/26/97 5:18p Hoffoss
209 * Major rework of briefing editor functionality.
211 * 119 6/26/97 4:20p Hoffoss
212 * Changed the behavior of Ctrl-L
220 #include "fredview.h"
228 #include "management.h"
237 #include "floating.h"
245 #include "missionparse.h"
246 #include "linklist.h"
248 #include "3dinternal.h"
251 #include "fredrender.h"
253 #include "starfield.h"
255 #include "lighting.h"
256 #include "asteroid.h"
257 #include "jumpnode.h"
259 extern float flFrametime;
260 extern subsys_to_render Render_subsys;
263 #define new DEBUG_NEW
265 static char THIS_FILE[] = __FILE__;
268 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this.
269 #define MIN_FRAMETIME (F1_0/120)
270 #define MAX_STARS 500
271 #define LOLLIPOP_SIZE 2.5f
273 int Aa_gridlines = 0;
274 int Fred_outline = 0;
277 int Editing_mode = 1;
278 int Control_mode = 0;
279 int last_x=0, last_y=0;
281 int Show_outlines = 0;
283 int Show_grid_positions = 1;
284 int Show_coordinates = 0;
285 int Show_distances = 0;
286 int Show_horizon = 0;
287 int Show_asteroid_field = 1;
289 int Single_axis_constraint = 0;
290 int Universal_heading = 0;
291 int Flying_controls_mode = 1;
292 int Group_rotate = 1;
293 int info_popup_active = 0;
294 int rendering_order[MAX_SHIPS];
295 int render_count = 0;
296 int Last_cursor_over = -1;
297 int True_rw, True_rh;
298 int Fixed_briefing_size = 1;
301 vector my_pos = {0.0f, 0.0f, -5.0f};
302 vector view_pos, eye_pos, Viewer_pos, Last_eye_pos = { 0.0f };
303 vector Last_control_pos = { 0.0f };
305 vector Constraint = { 1.0f, 0.0f, 1.0f };
306 vector Anticonstraint = { 0.0f, 1.0f, 0.0f };
307 vector Tp1, Tp2; // test points
309 matrix my_orient = IDENTITY_MATRIX;
310 matrix trackball_orient = IDENTITY_MATRIX;
311 matrix view_orient = IDENTITY_MATRIX, eye_orient, Last_eye_orient = IDENTITY_MATRIX;
312 matrix Last_control_orient = IDENTITY_MATRIX;
313 physics_info view_physics;
314 control_info view_controls;
317 static vector Global_light_world = { 0.208758f, -0.688253f, -0.694782f };
319 void display_distances();
320 void render_model_x(vector *pos, grid *gridp, int col_scheme = 0);
321 void draw_orient_sphere(object *obj, int r, int g, int b);
322 void draw_orient_sphere2(int col, object *obj, int r, int g, int b);
323 void render_compass(void);
324 void draw_compass_arrow(vector *v0);
325 void process_controls(vector *pos, matrix *orient, float frametime, int key, int mode = 0);
326 void render_one_model(object *objp);
327 void inc_mission_time();
328 void draw_asteroid_field();
329 void hilight_bitmap();
331 // Called every time a new mission is created (and erasing old mission from memory).
332 // New mission should be blank at this point.
333 void fred_render_init()
337 physics_init(&view_physics);
338 view_physics.max_vel.z = 5.0f; //forward/backward
339 view_physics.max_rotvel.x = 1.5f; //pitch
340 memset(&view_controls, 0, sizeof(control_info));
342 vm_vec_make(&view_pos, 0.0f, 150.0f, -200.0f);
343 vm_vec_make(&f, 0.0f, -0.5f, 0.866025404f); // 30 degree angle
344 vm_vec_make(&u, 0.0f, 0.866025404f, 0.5f);
345 vm_vec_make(&r, 1.0f, 0.0f, 0.0f);
346 vm_vector_2_matrix(&view_orient, &f, &u, &r);
348 The_grid = create_default_grid();
349 maybe_create_new_grid(The_grid, &view_pos, &view_orient, 1);
350 // vm_set_identity(&view_orient);
353 void level_object(matrix *orient)
357 u = orient->uvec = The_grid->gmatrix.uvec;
358 if (u.x) // y-z plane
360 orient->fvec.x = orient->rvec.x = 0.0f;
362 } else if (u.y) { // x-z plane
363 orient->fvec.y = orient->rvec.y = 0.0f;
365 } else if (u.z) { // x-y plane
366 orient->fvec.z = orient->rvec.z = 0.0f;
369 vm_fix_matrix(orient);
372 void level_controlled()
374 int cmode, count = 0;
377 cmode = Control_mode;
378 if ((viewpoint == 1) && !cmode)
382 case 0: // Control the viewer's location and orientation
383 level_object(&view_orient);
386 case 2: // Control viewpoint object
387 level_object(&Objects[view_obj].orient);
388 object_moved(&Objects[view_obj]);
390 FREDDoc_ptr->autosave("level object");
393 case 1: // Control the current object's location and orientation
394 objp = GET_FIRST(&obj_used_list);
395 while (objp != END_OF_LIST(&obj_used_list)) {
396 if (objp->flags & OF_MARKED)
397 level_object(&objp->orient);
399 objp = GET_NEXT(objp);
402 objp = GET_FIRST(&obj_used_list);
403 while (objp != END_OF_LIST(&obj_used_list)) {
404 if (objp->flags & OF_MARKED) {
409 objp = GET_NEXT(objp);
414 FREDDoc_ptr->autosave("level objects");
416 FREDDoc_ptr->autosave("level object");
427 void align_vector_to_axis(vector *v)
443 if ((x > y) && (x > z)) { // x axis
444 if (v->x < 0) // negative x
445 vm_vec_make(v, -1.0f, 0.0f, 0.0f);
447 vm_vec_make(v, 1.0f, 0.0f, 0.0f);
449 } else if (y > z) { // y axis
450 if (v->y < 0) // negative y
451 vm_vec_make(v, 0.0f, -1.0f, 0.0f);
453 vm_vec_make(v, 0.0f, 1.0f, 0.0f);
456 if (v->z < 0) // negative z
457 vm_vec_make(v, 0.0f, 0.0f, -1.0f);
459 vm_vec_make(v, 0.0f, 0.0f, 1.0f);
463 void verticalize_object(matrix *orient)
465 align_vector_to_axis(&orient->fvec);
466 align_vector_to_axis(&orient->uvec);
467 align_vector_to_axis(&orient->rvec);
468 vm_fix_matrix(orient); // just in case something odd occurs.
471 void verticalize_controlled()
473 int cmode, count = 0;
476 cmode = Control_mode;
477 if ((viewpoint == 1) && !cmode)
481 case 0: // Control the viewer's location and orientation
482 verticalize_object(&view_orient);
485 case 2: // Control viewpoint object
486 verticalize_object(&Objects[view_obj].orient);
487 object_moved(&Objects[view_obj]);
488 FREDDoc_ptr->autosave("align object");
492 case 1: // Control the current object's location and orientation
493 objp = GET_FIRST(&obj_used_list);
494 while (objp != END_OF_LIST(&obj_used_list)) {
495 if (objp->flags & OF_MARKED)
496 verticalize_object(&objp->orient);
498 objp = GET_NEXT(objp);
501 objp = GET_FIRST(&obj_used_list);
502 while (objp != END_OF_LIST(&obj_used_list)) {
503 if (objp->flags & OF_MARKED) {
508 objp = GET_NEXT(objp);
513 FREDDoc_ptr->autosave("align objects");
515 FREDDoc_ptr->autosave("align object");
526 void move_mouse( int btn, int mdx, int mdy )
536 matrix tempm, mousem;
539 vm_trackball( dx, dy, &mousem );
540 vm_matrix_x_matrix(&tempm, &trackball_orient, &mousem);
541 trackball_orient = tempm;
542 view_orient = trackball_orient;
547 my_pos.z += (float)dy;
551 ///////////////////////////////////////////////////
552 void process_system_keys(int key)
554 // mprintf(("Key = %d\n", key));
558 CFREDView::GetView()->cycle_constraint();
561 case KEY_R: // for some stupid reason, an accelerator for 'R' doesn't work.
566 Selection_lock = !Selection_lock;
577 void render_waypoints(void)
583 for (i=0; i<Num_waypoint_lists; i++)
585 ptr = &Waypoint_lists[i];
586 for (j=0; j<ptr->count; j++)
588 g3_rotate_vertex(&v, &ptr->waypoints[j]);
589 if (!(v.codes & CC_BEHIND))
590 if (!(g3_project_vertex(&v) & PF_OVERFLOW))
592 if (cur_waypoint_list == i && cur_waypoint == j)
593 gr_set_color(255, 255, 255);
594 else if (Waypoint_lists[i].flags[j] & WL_MARKED)
595 gr_set_color(160, 255, 0);
597 gr_set_color(160, 96, 0);
599 g3_draw_sphere(&v, LOLLIPOP_SIZE);
601 gr_set_color(0, 0, 0);
603 gr_set_color(160, 96, 0);
605 g3_draw_sphere(&v, LOLLIPOP_SIZE * 0.66667f);
606 gr_set_color(160, 96, 0);
607 g3_draw_sphere(&v, LOLLIPOP_SIZE * 0.33333f);
611 for (j=0; j<ptr->count; j++)
612 render_model_x(&ptr->waypoints[j], The_grid, 1);
614 gr_set_color(160, 96, 0);
615 for (j=1; j<ptr->count; j++)
616 rpd_line(&ptr->waypoints[j-1], &ptr->waypoints[j]);
620 // --------------------------------------------------------------------------------
621 // get_subsystem_world_pos2() returns the world position for a given subobject on a ship
624 vector* get_subsystem_world_pos2(object* parent_obj, ship_subsys* subsys, vector* world_pos)
626 if (subsys == NULL) {
627 *world_pos = parent_obj->pos;
631 vm_vec_unrotate(world_pos, &subsys->system_info->pnt, &parent_obj->orient);
632 vm_vec_add2(world_pos, &parent_obj->pos);
637 // returns 1 for valid bounding rect, 0 otherwise
638 int get_subsys_bounding_rect(object *ship_obj, ship_subsys *subsys, int *x1, int *x2, int *y1, int *y2)
640 if (subsys != NULL) {
641 vertex subobj_vertex;
644 get_subsystem_world_pos2(ship_obj, subsys, &subobj_pos);
646 g3_rotate_vertex(&subobj_vertex, &subobj_pos);
648 g3_project_vertex(&subobj_vertex);
649 if (subobj_vertex.flags & PF_OVERFLOW) // if overflow, no point in drawing brackets
654 bound_rc = subobj_find_2d_bound(subsys->system_info->radius, &ship_obj->orient, &subobj_pos, x1, y1, x2, y2);
664 void cancel_display_active_ship_subsystem()
666 Render_subsys.do_render = false;
667 Render_subsys.ship_obj = NULL;
668 Render_subsys.cur_subsys = NULL;
671 void display_active_ship_subsystem()
673 if (cur_object_index != -1) {
674 if (Objects[cur_object_index].type == OBJ_SHIP) {
676 object *objp = &Objects[cur_object_index];
680 // switching to a new ship, so reset
681 if (objp != Render_subsys.ship_obj) {
682 cancel_display_active_ship_subsystem();
686 if (Render_subsys.do_render) {
689 strcpy(buf, Render_subsys.cur_subsys->system_info->subobj_name);
692 if ( get_subsys_bounding_rect(objp, Render_subsys.cur_subsys, &x1, &x2, &y1, &y2) ) {
695 gr_set_color(255, 32, 32);
698 gr_line(x1, y1, x1, y2); gr_line(x1-1, y1, x1-1, y2);
699 gr_line(x1, y2, x2, y2); gr_line(x1, y2+1, x2, y2+1);
700 gr_line(x2, y2, x2, y1); gr_line(x2+1, y2, x2+1, y1);
701 gr_line(x2, y1, x1, y1); gr_line(x2, y1-1, x1, y1-1);
704 gr_string_win( (x1+x2)/2, y2 + 10, buf);
709 cancel_display_active_ship_subsystem();
713 void render_models(void)
716 obj_render_all(render_one_model);
718 Briefing_dialog->batch_render();
721 void render_one_model(object *objp)
726 SDL_assert(objp->type != OBJ_NONE);
728 if ( objp->type == OBJ_JUMP_NODE ) {
732 if ((objp->type == OBJ_WAYPOINT) && !Show_waypoints)
735 if ((objp->type == OBJ_START) && !Show_starts)
738 if (objp->type == OBJ_SHIP) {
742 if ((Ships[objp->instance].team == TEAM_FRIENDLY) && !Show_friendly)
745 if ((Ships[objp->instance].team == TEAM_HOSTILE) && !Show_hostile)
748 if ((Ships[objp->instance].team == TEAM_NEUTRAL) && !Show_neutral)
752 if (objp->flags & OF_HIDDEN)
755 rendering_order[render_count] = OBJ_INDEX(objp);
757 if ((OBJ_INDEX(objp) == cur_object_index) && !Bg_bitmap_dialog)
758 Fred_outline = 0xffffff;
760 else if ((objp->flags & OF_MARKED) && !Bg_bitmap_dialog) // is it a marked object?
761 Fred_outline = 0x9fff00;
763 else if ((objp->type == OBJ_SHIP) && Show_outlines) {
764 switch (Ships[objp->instance].team) {
765 case TEAM_FRIENDLY: Fred_outline = 0x0000c0; break;
766 case TEAM_NEUTRAL: Fred_outline = 0x007f7f; break;
767 case TEAM_UNKNOWN: Fred_outline = 0x684010; break;
768 case TEAM_HOSTILE: Fred_outline = 0x7f0000; break;
770 Fred_outline = 0x7f007f; break;
773 } else if ((objp->type == OBJ_START) && Show_outlines) {
774 Fred_outline = 0x007f00;
780 if ((Show_ship_models || Show_outlines) && ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START))){
781 if (Show_ship_models){
787 if(Show_dock_points){
797 model_clear_instance( Ships[z].modelnum );
799 // if (!viewpoint || OBJ_INDEX(objp) != cur_object_index)
802 model_set_outline_color(Fred_outline >> 16, (Fred_outline >> 8) & 0xff, Fred_outline & 0xff);
803 model_render(Ships[z].modelnum, &objp->orient, &objp->pos, j | MR_SHOW_OUTLINE);
805 model_render(Ships[z].modelnum, &objp->orient, &objp->pos, j);
810 int r = 0, g = 0, b = 0;
812 if (objp->type == OBJ_SHIP)
817 switch (Ships[objp->instance].team) {
818 case TEAM_FRIENDLY: r = 0; g = 0; b = 192; break;
819 case TEAM_NEUTRAL: r = 0; g = 127; b = 127; break;
820 case TEAM_UNKNOWN: r = 104; g = 64; b = 16; break;
821 case TEAM_HOSTILE: r = 127; g = 0; b = 0; break;
822 default: r = 127; g = 0; b = 0; break;
825 } else if (objp->type == OBJ_START) {
826 r = 0; g = 127; b = 0;
828 } else if (objp->type == OBJ_WAYPOINT) {
829 r = 96; g = 0; b = 112;
831 } else if (objp->type == OBJ_POINT) {
832 if (objp->instance != BRIEFING_LOOKAT_POINT_ID) {
833 SDL_assert(Briefing_dialog);
834 Briefing_dialog->draw_icon(objp);
838 r = 196; g = 32; b = 196;
844 draw_orient_sphere2(Fred_outline, objp, r, g, b);
846 draw_orient_sphere(objp, r, g, b);
850 if (objp->type == OBJ_WAYPOINT)
851 for (j=0; j<render_count; j++)
853 o2 = &Objects[rendering_order[j]];
854 if (o2->type == OBJ_WAYPOINT)
855 if ((o2->instance == objp->instance - 1) || (o2->instance == objp->instance + 1))
856 rpd_line(&o2->pos, &objp->pos);
859 render_model_x(&objp->pos, The_grid);
863 void display_distances()
870 gr_set_color(255, 0, 0);
871 objp = GET_FIRST(&obj_used_list);
872 while (objp != END_OF_LIST(&obj_used_list))
874 if (objp->flags & OF_MARKED)
877 while (o2 != END_OF_LIST(&obj_used_list))
879 if (o2->flags & OF_MARKED)
881 rpd_line(&objp->pos, &o2->pos);
882 vm_vec_avg(&pos, &objp->pos, &o2->pos);
883 g3_rotate_vertex(&v, &pos);
884 if (!(v.codes & CC_BEHIND))
885 if (!(g3_project_vertex(&v) & PF_OVERFLOW)) {
886 sprintf(buf, "%.1f", vm_vec_dist(&objp->pos, &o2->pos));
887 gr_string_win((int) v.sx, (int) v.sy, buf);
895 objp = GET_NEXT(objp);
899 void display_ship_info()
901 char buf[512], pos[80];
906 objp = GET_FIRST(&obj_used_list);
907 while (objp != END_OF_LIST(&obj_used_list)) {
908 SDL_assert(objp->type != OBJ_NONE);
911 if (OBJ_INDEX(objp) == cur_object_index)
912 Fred_outline = 0xffffff;
913 else if (objp->flags & OF_MARKED) // is it a marked object?
914 Fred_outline = 0x9fff00;
918 if ((objp->type == OBJ_WAYPOINT) && !Show_waypoints)
921 if ((objp->type == OBJ_START) && !Show_starts)
924 if (objp->type == OBJ_SHIP) {
928 if ((Ships[objp->instance].team == TEAM_FRIENDLY) && !Show_friendly)
931 if ((Ships[objp->instance].team == TEAM_HOSTILE) && !Show_hostile)
934 if ((Ships[objp->instance].team == TEAM_NEUTRAL) && !Show_neutral)
938 if (objp->flags & OF_HIDDEN)
941 g3_rotate_vertex(&v, &objp->pos);
942 if (!(v.codes & CC_BEHIND) && render)
943 if (!(g3_project_vertex(&v) & PF_OVERFLOW)) {
947 if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) {
951 shipp = &Ships[objp->instance];
952 ship_type = shipp->ship_info_index;
953 ASSERT(ship_type >= 0);
954 sprintf(buf, "%s\n%s", shipp->ship_name, Ship_info[ship_type].short_name);
956 } else if (objp->type == OBJ_WAYPOINT) {
957 sprintf(buf, "%s\nWaypoint %d",
958 Waypoint_lists[objp->instance / 65536].name,
959 (objp->instance & 0xffff) + 1);
961 } else if (objp->type == OBJ_POINT) {
962 if (objp->instance == BRIEFING_LOOKAT_POINT_ID)
963 strcpy(buf, "Camera lookat point");
965 strcpy(buf, "Briefing icon");
967 } else if (objp->type == OBJ_JUMP_NODE) {
968 strcpy(buf, "Jump Node");
973 if (Show_coordinates)
975 sprintf(pos, "( %.0f , %.0f , %.0f )", objp->pos.x, objp->pos.y, objp->pos.z);
985 gr_set_color(Fred_outline >> 16, (Fred_outline >> 8) & 0xff, Fred_outline & 0xff);
987 gr_set_color(160, 160, 160);
989 gr_string_win((int) v.sx, (int) v.sy, buf);
993 objp = GET_NEXT(objp);
997 void draw_orient_sphere(object *obj, int r, int g, int b)
1004 size = fl_sqrt(vm_vec_dist(&eye_pos, &obj->pos) / 20.0f);
1005 if (size < LOLLIPOP_SIZE)
1006 size = LOLLIPOP_SIZE;
1008 if ((obj->type != OBJ_WAYPOINT) && (obj->type != OBJ_POINT))
1010 flag = (vm_vec_dotprod(&eye_orient.fvec, &obj->orient.fvec) < 0.0f);
1012 vm_vec_scale_add2(&v1, &obj->orient.fvec, size);
1013 vm_vec_scale_add2(&v2, &obj->orient.fvec, size * 1.5f);
1016 gr_set_color(192, 192, 192);
1021 gr_set_color(r, g, b);
1022 g3_rotate_vertex(&v, &obj->pos);
1023 if (!(v.codes & CC_BEHIND))
1024 if (!(g3_project_vertex(&v) & PF_OVERFLOW))
1025 g3_draw_sphere(&v, size);
1028 gr_set_color(192, 192, 192);
1033 void draw_orient_sphere2(int col, object *obj, int r, int g, int b)
1040 size = fl_sqrt(vm_vec_dist(&eye_pos, &obj->pos) / 20.0f);
1041 if (size < LOLLIPOP_SIZE)
1042 size = LOLLIPOP_SIZE;
1044 if ((obj->type != OBJ_WAYPOINT) && (obj->type != OBJ_POINT))
1046 flag = (vm_vec_dotprod(&eye_orient.fvec, &obj->orient.fvec) < 0.0f);
1049 vm_vec_scale_add2(&v1, &obj->orient.fvec, size);
1050 vm_vec_scale_add2(&v2, &obj->orient.fvec, size * 1.5f);
1053 gr_set_color(192, 192, 192);
1058 g3_rotate_vertex(&v, &obj->pos);
1059 if (!(v.codes & CC_BEHIND))
1060 if (!(g3_project_vertex(&v) & PF_OVERFLOW))
1062 gr_set_color((col >> 16) & 0xff, (col >> 8) & 0xff, col & 0xff);
1063 g3_draw_sphere(&v, size);
1064 gr_set_color(r, g, b);
1065 g3_draw_sphere(&v, size * 0.75f);
1069 gr_set_color(192, 192, 192);
1074 void render_model_x(vector *pos, grid *gridp, int col_scheme)
1076 vector gpos; // Location of point on grid.
1082 if (!Show_grid_positions)
1085 tplane.A = gridp->gmatrix.uvec.x;
1086 tplane.B = gridp->gmatrix.uvec.y;
1087 tplane.C = gridp->gmatrix.uvec.z;
1088 tplane.D = gridp->planeD;
1090 compute_point_on_plane(&gpos, &tplane, pos);
1091 dxz = vm_vec_dist(pos, &gpos)/8.0f;
1092 gv = &gridp->gmatrix.uvec;
1093 if (gv->x * pos->x + gv->y * pos->y + gv->z * pos->z < -gridp->planeD)
1094 gr_set_color(0, 127, 0);
1096 gr_set_color(192, 192, 192);
1099 rpd_line(&gpos, pos); // Line from grid to object center.
1103 vm_vec_scale_add2(&gpos, &gridp->gmatrix.rvec, -dxz/2);
1104 vm_vec_scale_add2(&gpos, &gridp->gmatrix.fvec, -dxz/2);
1106 vm_vec_scale_add2(&tpos, &gridp->gmatrix.rvec, dxz/2);
1107 vm_vec_scale_add2(&tpos, &gridp->gmatrix.fvec, dxz/2);
1109 rpd_line(&gpos, &tpos);
1111 vm_vec_scale_add2(&gpos, &gridp->gmatrix.rvec, dxz);
1112 vm_vec_scale_add2(&tpos, &gridp->gmatrix.rvec, -dxz);
1114 rpd_line(&gpos, &tpos);
1117 void render_active_rect(void)
1120 gr_set_color(255, 255, 255);
1121 gr_line(marking_box.x1, marking_box.y1, marking_box.x1, marking_box.y2);
1122 gr_line(marking_box.x1, marking_box.y2, marking_box.x2, marking_box.y2);
1123 gr_line(marking_box.x2, marking_box.y2, marking_box.x2, marking_box.y1);
1124 gr_line(marking_box.x2, marking_box.y1, marking_box.x1, marking_box.y1);
1129 void process_movement_keys(int key, vector *mvec, angles *angs)
1140 raw_key = key & 0xff;
1143 case KEY_PAD1: mvec->x += -1.0f; break;
1144 case KEY_PAD3: mvec->x += +1.0f; break;
1145 case KEY_PADPLUS: mvec->y += -1.0f; break;
1146 case KEY_PADMINUS: mvec->y += +1.0f; break;
1147 case KEY_A: mvec->z += +1.0f; break;
1148 case KEY_Z: mvec->z += -1.0f; break;
1149 case KEY_PAD4: angs->h += -0.1f; break;
1150 case KEY_PAD6: angs->h += +0.1f; break;
1151 case KEY_PAD8: angs->p += -0.1f; break;
1152 case KEY_PAD2: angs->p += +0.1f; break;
1153 case KEY_PAD7: angs->b += -0.1f; break;
1154 case KEY_PAD9: angs->b += +0.1f; break;
1158 if (key & KEY_SHIFTED) {
1159 vm_vec_scale(mvec, 5.0f);
1166 void process_controls(vector *pos, matrix *orient, float frametime, int key, int mode)
1168 if (Flying_controls_mode) {
1169 grid_read_camera_controls(&view_controls, frametime);
1171 if (key_get_shift_status())
1172 memset(&view_controls, 0, sizeof(control_info));
1174 if ((fabs(view_controls.pitch) > (frametime / 100)) &&
1175 (fabs(view_controls.vertical) > (frametime / 100)) &&
1176 (fabs(view_controls.heading) > (frametime / 100)) &&
1177 (fabs(view_controls.sideways) > (frametime / 100)) &&
1178 (fabs(view_controls.bank) > (frametime / 100)) &&
1179 (fabs(view_controls.forward) > (frametime / 100)))
1182 flFrametime = frametime;
1183 physics_read_flying_controls(orient, &view_physics, &view_controls, flFrametime);
1185 physics_sim_editor(pos, orient, &view_physics, frametime);
1187 physics_sim(pos, orient, &view_physics, frametime);
1190 vector movement_vec, rel_movement_vec;
1192 matrix newmat, rotmat;
1194 process_movement_keys(key, &movement_vec, &rotangs);
1195 vm_vec_rotate(&rel_movement_vec, &movement_vec, &The_grid->gmatrix);
1196 vm_vec_add2(pos, &rel_movement_vec);
1198 vm_angles_2_matrix(&rotmat, &rotangs);
1199 if (rotangs.h && Universal_heading)
1200 vm_transpose_matrix(orient);
1201 vm_matrix_x_matrix(&newmat, orient, &rotmat);
1203 if (rotangs.h && Universal_heading)
1204 vm_transpose_matrix(orient);
1208 int Fred_grid_colors_inited = 0;
1209 color Fred_grid_bright, Fred_grid_dark, Fred_grid_bright_aa, Fred_grid_dark_aa;
1211 // Renders a grid defined in a grid struct
1212 void fred_render_grid(grid *gridp)
1214 int i, ncols, nrows;
1216 if ( !Fred_grid_colors_inited ) {
1217 Fred_grid_colors_inited = 1;
1219 gr_init_alphacolor( &Fred_grid_dark_aa, 64, 64, 64, 255 );
1220 gr_init_alphacolor( &Fred_grid_bright_aa, 128, 128, 128, 255 );
1221 gr_init_color( &Fred_grid_dark, 64, 64, 64 );
1222 gr_init_color( &Fred_grid_bright, 128, 128, 128 );
1225 ncols = gridp->ncols;
1226 nrows = gridp->nrows;
1227 if (double_fine_gridlines) {
1233 gr_set_color_fast(&Fred_grid_dark_aa);
1235 gr_set_color_fast(&Fred_grid_dark);
1237 // Draw the column lines.
1238 for (i=0; i<=ncols; i++)
1239 rpd_line(&gridp->gpoints1[i], &gridp->gpoints2[i]);
1241 // Draw the row lines.
1242 for (i=0; i<=nrows; i++)
1243 rpd_line(&gridp->gpoints3[i], &gridp->gpoints4[i]);
1245 ncols = gridp->ncols / 2;
1246 nrows = gridp->nrows / 2;
1248 // now draw the larger, brighter gridlines that is x10 the scale of smaller one.
1250 gr_set_color_fast(&Fred_grid_bright_aa);
1252 gr_set_color_fast(&Fred_grid_bright);
1254 for (i=0; i<=ncols; i++)
1255 rpd_line(&gridp->gpoints5[i], &gridp->gpoints6[i]);
1257 for (i=0; i<=nrows; i++)
1258 rpd_line(&gridp->gpoints7[i], &gridp->gpoints8[i]);
1264 int x, y, w, h, inst;
1274 if (Briefing_dialog) {
1277 Fred_main_wnd->GetClientRect(rect);
1278 True_rw = rect.Width();
1279 True_rh = rect.Height();
1280 if (Fixed_briefing_size) {
1281 True_rw = BRIEF_GRID_W;
1282 True_rh = BRIEF_GRID_H;
1285 if ((float) True_rh / (float) True_rw > (float) BRIEF_GRID_H / (float) BRIEF_GRID_W) {
1286 True_rh = (int) ((float) BRIEF_GRID_H * (float) True_rw / (float) BRIEF_GRID_W);
1288 } else { // Fred is wider than briefing window
1289 True_rw = (int) ((float) BRIEF_GRID_W * (float) True_rh / (float) BRIEF_GRID_H);
1294 gr_set_color(255, 255, 255);
1295 gr_line(0, True_rh, True_rw, True_rh);
1296 gr_line(True_rw, 0, True_rw, True_rh);
1298 gr_set_clip(0, 0, True_rw, True_rh);
1301 g3_start_frame(1); // 1 means use zbuffering
1302 gr_set_font(Fred_font);
1305 g3_set_view_matrix(&eye_pos, &eye_orient, 0.5f);
1306 Viewer_pos = eye_pos; // for starfield code
1308 if ( Bg_bitmap_dialog ) {
1309 stars_draw( Show_stars, 1, Show_stars, 0 );
1311 stars_draw( Show_stars, Show_stars, Show_stars, 0 );
1315 gr_set_color(128, 128, 64);
1316 g3_draw_horizon_line();
1319 if (Show_asteroid_field) {
1320 gr_set_color(192, 96, 16);
1321 draw_asteroid_field();
1325 fred_render_grid(The_grid);
1326 if (Bg_bitmap_dialog)
1329 gr_set_color(0, 0, 64);
1332 display_distances();
1334 display_ship_info();
1335 display_active_ship_subsystem();
1336 render_active_rect();
1338 if (query_valid_object(Cursor_over)) { // display a tool-tip like infobox
1339 pos = Objects[Cursor_over].pos;
1340 inst = Objects[Cursor_over].instance;
1341 if ((Objects[Cursor_over].type == OBJ_SHIP) || (Objects[Cursor_over].type == OBJ_START)) {
1342 vm_extract_angles_matrix(&a, &Objects[Cursor_over].orient);
1343 sprintf(buf, "%s\n%s\n( %.1f , %.1f , %.1f )\nHeading: %.2f\nPitch: %.2f\nBank: %.2f",
1344 Ships[inst].ship_name, Ship_info[Ships[inst].ship_info_index].short_name,
1345 pos.x, pos.y, pos.z, a.h, a.p, a.b);
1347 } else if (Objects[Cursor_over].type == OBJ_WAYPOINT) {
1348 sprintf(buf, "%s\nWaypoint %d\n( %.1f , %.1f , %.1f )",
1349 Waypoint_lists[inst / 65536].name, (inst & 0xffff) + 1, pos.x, pos.y, pos.z);
1351 } else if (Objects[Cursor_over].type == OBJ_POINT) {
1352 sprintf(buf, "Briefing icon\n( %.1f , %.1f , %.1f )", pos.x, pos.y, pos.z);
1355 sprintf(buf, "( %.1f , %.1f , %.1f )", pos.x, pos.y, pos.z);
1357 g3_rotate_vertex(&v, &pos);
1358 if (!(v.codes & CC_BEHIND))
1359 if (!(g3_project_vertex(&v) & PF_OVERFLOW)) {
1361 y = (int) v.sy + 20;
1362 gr_get_string_size_win(&w, &h, buf);
1363 gr_set_color(192, 192, 192);
1364 gr_rect(x-1, y-1, w+2, h+2);
1365 gr_set_color(255, 255, 255);
1366 gr_line(x-2, y-2, x+w+1, y-2);
1367 gr_line(x-2, y-2, x-2, y+h+1);
1368 gr_line(x+w+1, y-2, x+w+1, y+h+1);
1369 gr_line(x-2, y+h+1, x+w+1, y+h+1);
1371 gr_set_color(0, 0, 0);
1372 gr_string_win(x, y, buf);
1376 gr_set_color(0, 160, 0);
1377 jumpnode_render_all();
1379 sprintf(buf, "( %.1f , %.1f , %.1f )", eye_pos.x, eye_pos.y, eye_pos.z);
1380 gr_get_string_size_win(&w, &h, buf);
1381 gr_set_color(192, 192, 192);
1382 gr_string_win(gr_screen.max_w - w - 2, 2, buf);
1387 if (Briefing_dialog)
1388 gr_set_clip(0, 0, True_rw, True_rh);
1391 g3_set_view_matrix(&eye_pos, &eye_orient, 0.5f);
1394 void game_do_frame()
1397 vector viewer_position, control_pos;
1399 matrix control_orient;
1403 viewer_position = my_orient.fvec;
1404 vm_vec_scale(&viewer_position,my_pos.z);
1406 if ((viewpoint == 1) && !query_valid_object(view_obj))
1410 process_system_keys(key);
1411 cmode = Control_mode;
1412 if ((viewpoint == 1) && !cmode)
1415 control_pos = Last_control_pos;
1416 control_orient = Last_control_orient;
1418 // if ((key & KEY_MASK) == key) // unmodified
1420 case 0: // Control the viewer's location and orientation
1421 process_controls(&view_pos, &view_orient, f2fl(Frametime), key, 1);
1422 control_pos = view_pos;
1423 control_orient = view_orient;
1426 case 2: // Control viewpoint object
1427 process_controls(&Objects[view_obj].pos, &Objects[view_obj].orient, f2fl(Frametime), key);
1428 object_moved(&Objects[view_obj]);
1429 control_pos = Objects[view_obj].pos;
1430 control_orient = Objects[view_obj].orient;
1433 case 1: // Control the current object's location and orientation
1434 if (query_valid_object()) {
1435 vector delta_pos, leader_old_pos;
1436 matrix leader_orient, leader_transpose, tmp;
1439 leader = &Objects[cur_object_index];
1440 leader_old_pos = leader->pos; // save original position
1441 leader_orient = leader->orient; // save original orientation
1442 vm_copy_transpose_matrix(&leader_transpose, &leader_orient);
1444 process_controls(&leader->pos, &leader->orient, f2fl(Frametime), key);
1445 vm_vec_sub(&delta_pos, &leader->pos, &leader_old_pos); // get position change
1446 control_pos = leader->pos;
1447 control_orient = leader->orient;
1449 objp = GET_FIRST(&obj_used_list);
1450 while (objp != END_OF_LIST(&obj_used_list)) {
1451 SDL_assert(objp->type != OBJ_NONE);
1452 if ((objp->flags & OF_MARKED) && (cur_object_index != OBJ_INDEX(objp))) {
1455 vector tmpv1, tmpv2;
1457 // change rotation matrix to rotate in opposite direction. This rotation
1458 // matrix is what the leader ship has rotated by.
1459 vm_copy_transpose_matrix(&rot_trans, &view_physics.last_rotmat);
1461 // get point relative to our point of rotation (make POR the origin). Since
1462 // only the leader has been moved yet, and not the objects, we have to use
1463 // the old leader's position.
1464 vm_vec_sub(&tmpv1, &objp->pos, &leader_old_pos);
1466 // convert point from real-world coordinates to leader's relative coordinate
1467 // system (z=forward vec, y=up vec, x=right vec
1468 vm_vec_rotate(&tmpv2, &tmpv1, &leader_orient);
1470 // now rotate the point by the transpose from above.
1471 vm_vec_rotate(&tmpv1, &tmpv2, &rot_trans);
1473 // convert point back into real-world coordinates
1474 vm_vec_rotate(&tmpv2, &tmpv1, &leader_transpose);
1476 // and move origin back to real-world origin. Object is now at it's correct
1477 // position. Note we used the leader's new position, instead of old position.
1478 vm_vec_add(&objp->pos, &leader->pos, &tmpv2);
1480 // Now fix the object's orientation to what it should be.
1481 vm_matrix_x_matrix(&tmp, &objp->orient, &view_physics.last_rotmat);
1482 vm_orthogonalize_matrix(&tmp); // safety check
1486 vm_vec_add2(&objp->pos, &delta_pos);
1487 vm_matrix_x_matrix(&tmp, &objp->orient, &view_physics.last_rotmat);
1492 objp = GET_NEXT(objp);
1495 objp = GET_FIRST(&obj_used_list);
1496 while (objp != END_OF_LIST(&obj_used_list)) {
1497 if (objp->flags & OF_MARKED)
1500 objp = GET_NEXT(objp);
1512 if (Lookat_mode && query_valid_object()) {
1515 dist = vm_vec_dist(&view_pos, &Objects[cur_object_index].pos);
1516 vm_vec_scale_add(&view_pos, &Objects[cur_object_index].pos, &view_orient.fvec, -dist);
1523 eye_orient = view_orient;
1527 eye_pos = Objects[view_obj].pos;
1528 eye_orient = Objects[view_obj].orient;
1535 maybe_create_new_grid(The_grid, &eye_pos, &eye_orient);
1537 if (Cursor_over != Last_cursor_over) {
1538 Last_cursor_over = Cursor_over;
1542 // redraw screen if controlled object moved or rotated
1543 if (vm_vec_cmp(&control_pos, &Last_control_pos) || vm_matrix_cmp(&control_orient, &Last_control_orient)) {
1545 Last_control_pos = control_pos;
1546 Last_control_orient = control_orient;
1549 // redraw screen if current viewpoint moved or rotated
1550 if (vm_vec_cmp(&eye_pos, &Last_eye_pos) || vm_matrix_cmp(&eye_orient, &Last_eye_orient)) {
1552 Last_eye_pos = eye_pos;
1553 Last_eye_orient = eye_orient;
1557 void hilight_bitmap()
1563 if (Starfield_bitmaps[Cur_bitmap].bitmap_index == -1) // can't draw if no bitmap
1568 g3_rotate_faraway_vertex(&p[i], &Starfield_bitmaps[Cur_bitmap].points[i]);
1569 if (p[i].codes & CC_BEHIND)
1572 g3_project_vertex(&p[i]);
1573 if (p[i].flags & PF_OVERFLOW)
1577 gr_set_color(255, 255, 255);
1578 g3_draw_line(&p[0], &p[1]);
1579 g3_draw_line(&p[1], &p[2]);
1580 g3_draw_line(&p[2], &p[3]);
1581 g3_draw_line(&p[3], &p[0]);
1585 void draw_asteroid_field()
1591 for (i=0; i<1 /*MAX_ASTEROID_FIELDS*/; i++)
1592 if (Asteroid_field.num_initial_asteroids) {
1593 p[0].x = p[2].x = p[4].x = p[6].x = Asteroid_field.min_bound.x;
1594 p[1].x = p[3].x = p[5].x = p[7].x = Asteroid_field.max_bound.x;
1595 p[0].y = p[1].y = p[4].y = p[5].y = Asteroid_field.min_bound.y;
1596 p[2].y = p[3].y = p[6].y = p[7].y = Asteroid_field.max_bound.y;
1597 p[0].z = p[1].z = p[2].z = p[3].z = Asteroid_field.min_bound.z;
1598 p[4].z = p[5].z = p[6].z = p[7].z = Asteroid_field.max_bound.z;
1601 g3_rotate_vertex(&v[j], &p[j]);
1603 g3_draw_line(&v[0], &v[1]);
1604 g3_draw_line(&v[2], &v[3]);
1605 g3_draw_line(&v[4], &v[5]);
1606 g3_draw_line(&v[6], &v[7]);
1607 g3_draw_line(&v[0], &v[2]);
1608 g3_draw_line(&v[1], &v[3]);
1609 g3_draw_line(&v[4], &v[6]);
1610 g3_draw_line(&v[5], &v[7]);
1611 g3_draw_line(&v[0], &v[4]);
1612 g3_draw_line(&v[1], &v[5]);
1613 g3_draw_line(&v[2], &v[6]);
1614 g3_draw_line(&v[3], &v[7]);
1617 // maybe draw inner box
1618 if (Asteroid_field.has_inner_bound) {
1620 gr_set_color(16, 192, 92);
1622 ip[0].x = ip[2].x = ip[4].x = ip[6].x = Asteroid_field.inner_min_bound.x;
1623 ip[1].x = ip[3].x = ip[5].x = ip[7].x = Asteroid_field.inner_max_bound.x;
1624 ip[0].y = ip[1].y = ip[4].y = ip[5].y = Asteroid_field.inner_min_bound.y;
1625 ip[2].y = ip[3].y = ip[6].y = ip[7].y = Asteroid_field.inner_max_bound.y;
1626 ip[0].z = ip[1].z = ip[2].z = ip[3].z = Asteroid_field.inner_min_bound.z;
1627 ip[4].z = ip[5].z = ip[6].z = ip[7].z = Asteroid_field.inner_max_bound.z;
1630 g3_rotate_vertex(&iv[j], &ip[j]);
1632 g3_draw_line(&iv[0], &iv[1]);
1633 g3_draw_line(&iv[2], &iv[3]);
1634 g3_draw_line(&iv[4], &iv[5]);
1635 g3_draw_line(&iv[6], &iv[7]);
1636 g3_draw_line(&iv[0], &iv[2]);
1637 g3_draw_line(&iv[1], &iv[3]);
1638 g3_draw_line(&iv[4], &iv[6]);
1639 g3_draw_line(&iv[5], &iv[7]);
1640 g3_draw_line(&iv[0], &iv[4]);
1641 g3_draw_line(&iv[1], &iv[5]);
1642 g3_draw_line(&iv[2], &iv[6]);
1643 g3_draw_line(&iv[3], &iv[7]);
1649 // See if object "objnum" obstructs the vector from point p0 to point p1.
1650 // If so, return true and stuff hit point in *hitpos.
1651 // If not, return false.
1652 int object_check_collision(object *objp, vector *p0, vector *p1, vector *hitpos)
1656 if ((objp->type == OBJ_NONE) || (objp->type == OBJ_POINT))
1659 if ((objp->type == OBJ_WAYPOINT) && !Show_waypoints)
1662 if ((objp->type == OBJ_START) && !Show_starts)
1665 if (objp->type == OBJ_SHIP) {
1669 if ((Ships[objp->instance].team == TEAM_FRIENDLY) && !Show_friendly)
1672 if ((Ships[objp->instance].team == TEAM_HOSTILE) && !Show_hostile)
1675 if ((Ships[objp->instance].team == TEAM_NEUTRAL) && !Show_neutral)
1679 if (objp->flags & OF_HIDDEN)
1682 if ((Show_ship_models || Show_outlines) && (objp->type == OBJ_SHIP)) {
1683 mc.model_num = Ships[objp->instance].modelnum; // Fill in the model to check
1685 } else if ((Show_ship_models || Show_outlines) && (objp->type == OBJ_START)) {
1686 mc.model_num = Ships[objp->instance].modelnum; // Fill in the model to check
1689 return fvi_ray_sphere(hitpos, p0, p1, &objp->pos, (objp->radius > 0.1f) ? objp->radius : LOLLIPOP_SIZE);
1691 mc.orient = &objp->orient; // The object's orient
1692 mc.pos = &objp->pos; // The object's position
1693 mc.p0 = p0; // Point 1 of ray to check
1694 mc.p1 = p1; // Point 2 of ray to check
1695 mc.flags = MC_CHECK_MODEL | MC_CHECK_RAY; // flags
1697 *hitpos = mc.hit_point_world;
1698 if ( mc.num_hits < 1 ) {
1700 mc.orient = &objp->orient; // The object's orient
1701 mc.pos = &objp->pos; // The object's position
1702 mc.p0 = p0; // Point 1 of ray to check
1703 mc.p1 = p1; // Point 2 of ray to check
1704 mc.flags = MC_CHECK_SHIELD; // flags
1706 *hitpos = mc.hit_point_world;
1712 // Finds the closest object or waypoint under the mouse cursor and returns
1713 // it's index, or -1 if nothing there.
1714 int select_object(int cx, int cy)
1717 double dist, best_dist = 9e99;
1718 vector p0, p1, v, hitpos;
1722 if (Briefing_dialog) {
1723 best = Briefing_dialog->check_mouse_hit(cx, cy);
1730 g3_set_view_matrix(&eye_pos, &eye_orient, 0.5f);*/
1732 // Get 3d vector specified by mouse cursor location.
1733 g3_point_to_vec(&v, cx, cy);
1736 if (!v.x && !v.y && !v.z) // zero vector
1740 vm_vec_scale_add(&p1, &p0, &v, 100.0f);
1742 ptr = GET_FIRST(&obj_used_list);
1743 while (ptr != END_OF_LIST(&obj_used_list))
1745 if (object_check_collision(ptr, &p0, &p1, &hitpos)) {
1746 hitpos.x = ptr->pos.x - view_pos.x;
1747 hitpos.y = ptr->pos.y - view_pos.y;
1748 hitpos.z = ptr->pos.z - view_pos.z;
1749 dist = hitpos.x * hitpos.x + hitpos.y * hitpos.y + hitpos.z * hitpos.z;
1750 if (dist < best_dist) {
1751 best = OBJ_INDEX(ptr);
1756 ptr = GET_NEXT(ptr);
1762 ptr = GET_FIRST(&obj_used_list);
1763 while (ptr != END_OF_LIST(&obj_used_list))
1765 g3_rotate_vertex(&vt, &ptr->pos);
1766 if (!(vt.codes & CC_BEHIND))
1767 if (!(g3_project_vertex(&vt) & PF_OVERFLOW)) {
1768 hitpos.x = vt.sx - cx;
1769 hitpos.y = vt.sy - cy;
1770 dist = hitpos.x * hitpos.x + hitpos.y * hitpos.y;
1771 if ((dist < 8) && (dist < best_dist)) {
1772 best = OBJ_INDEX(ptr);
1777 ptr = GET_NEXT(ptr);
1783 void render_compass(void)
1785 vector v, eye = { 0.0f };
1790 gr_set_clip(gr_screen.max_w - 100, 0, 100, 100);
1791 g3_start_frame(0); // required !!!
1792 vm_vec_scale_add2(&eye, &eye_orient.fvec, -1.5f);
1793 g3_set_view_matrix(&eye, &eye_orient, 1.0f);
1797 if (vm_vec_dotprod(&eye, &v) < 0.0f)
1798 gr_set_color(159, 20, 20);
1800 gr_set_color(255, 32, 32);
1801 draw_compass_arrow(&v);
1805 if (vm_vec_dotprod(&eye, &v) < 0.0f)
1806 gr_set_color(20, 159, 20);
1808 gr_set_color(32, 255, 32);
1809 draw_compass_arrow(&v);
1813 if (vm_vec_dotprod(&eye, &v) < 0.0f)
1814 gr_set_color(20, 20, 159);
1816 gr_set_color(32, 32, 255);
1817 draw_compass_arrow(&v);
1822 void draw_compass_arrow(vector *v0)
1824 vector v1 = { 0.0f };
1827 g3_rotate_vertex(&tv0, v0);
1828 g3_rotate_vertex(&tv1, &v1);
1829 g3_project_vertex(&tv0);
1830 g3_project_vertex(&tv1);
1831 // tv0.sx = (tv0.sx - tv1.sx) * 1 + tv1.sx;
1832 // tv0.sy = (tv0.sy - tv1.sy) * 1 + tv1.sy;
1833 g3_draw_line(&tv0, &tv1);
1837 void inc_mission_time()
1841 thistime = timer_get_fixed_seconds();
1843 Frametime = F1_0 / 30;
1845 Frametime = thistime - lasttime;
1847 if (Frametime > MAX_FRAMETIME)
1848 Frametime = MAX_FRAMETIME;
1850 if (Frametime < MIN_FRAMETIME)
1851 Frametime = MIN_FRAMETIME;
1853 Missiontime += Frametime;
1854 lasttime = thistime;