]> icculus.org git repositories - taylor/freespace2.git/blob - src/fred2/fredrender.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / fred2 / fredrender.cpp
1 /*
2  * $Logfile: /Freespace2/code/fred2/FredRender.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Handles rendering the scene in the window for Fred.  Also handles several other
8  * miscellaneous tasks.
9  *
10  * $Log$
11  * Revision 1.2  2002/05/07 03:16:44  theoddone33
12  * The Great Newline Fix
13  *
14  * Revision 1.1.1.1  2002/05/03 03:28:08  root
15  * Initial import.
16  *
17  * 
18  * 6     4/07/99 6:21p Dave
19  * Fred and Freespace support for multiple background bitmaps and suns.
20  * Fixed link errors on all subprojects. Moved encrypt_init() to
21  * cfile_init() and lcl_init(), since its safe to call twice.
22  * 
23  * 5     3/26/99 4:49p Dave
24  * Made cruisers able to dock with stuff. Made docking points and paths
25  * visible in fred.
26  * 
27  * 4     2/07/99 8:51p Andsager
28  * Add inner bound to asteroid field.  Inner bound tries to stay astroid
29  * free.  Wrap when within and don't throw at ships inside.
30  * 
31  * 3     1/27/99 4:09p Andsager
32  * Added highlight to ship subsystems
33  * 
34  * 2     10/07/98 6:28p Dave
35  * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
36  * Fred. Globalized mission and campaign file extensions. Removed Silent
37  * Threat specific code.
38  * 
39  * 1     10/07/98 3:02p Dave
40  * 
41  * 1     10/07/98 3:00p Dave
42  * 
43  * 162   5/21/98 12:58a Hoffoss
44  * Fixed warnings optimized build turned up.
45  * 
46  * 161   4/11/98 6:53p John
47  * Added first rev of subspace effect.
48  * 
49  * 160   4/07/98 4:17p John
50  * Made Fred be able to move suns.  Made suns actually affect the lighting
51  * in the game.
52  * 
53  * 159   3/21/98 7:36p Lawrance
54  * Move jump nodes to own lib.
55  * 
56  * 158   3/19/98 11:41a Hoffoss
57  * Fixed problems with rendering and reading of flying controls in Fred.
58  * 
59  * 157   3/14/98 5:11p Hoffoss
60  * Changed the starting camera position and orientation for Fred.
61  * 
62  * 156   3/10/98 4:24p Hoffoss
63  * Made object detection under cursor use the object's radius if it has
64  * one.
65  * 
66  * 155   3/10/98 4:18p John
67  * Cleaned up graphics lib.  Took out most unused gr functions.   Made D3D
68  * & Glide have popups and print screen.  Took out all >8bpp software
69  * support.  Made Fred zbuffer.  Made zbuffer allocate dynamically to
70  * support Fred.  Made zbuffering key off of functions rather than one
71  * global variable.
72  * 
73  * 154   3/10/98 1:41p Sandeep
74  * 
75  * 153   3/09/98 10:56a Hoffoss
76  * Added jump node objects to Fred.
77  * 
78  * 152   3/03/98 11:00a Andsager
79  * Fixed fred bug with control object initialization.
80  * 
81  * 151   2/18/98 6:45p Hoffoss
82  * Added support for lines between icons in briefings for Fred.
83  * 
84  * 150   2/12/98 3:48p Hoffoss
85  * Reduced scaler for extra precision.
86  * 
87  * 149   2/10/98 6:43p Lawrance
88  * Moved asteroid code to a separate lib.
89  * 
90  * 148   2/06/98 3:08p Mike
91  * More asteroid stuff, including resolving conflicts between the two
92  * asteroid_field structs!
93  * 
94  * 147   1/27/98 11:02a John
95  * Added first rev of sparks.   Made all code that calls model_render call
96  * clear_instance first.   Made debris pieces not render by default when
97  * clear_instance is called.
98  * 
99  * 146   1/16/98 2:22p Hoffoss
100  * Changed rendering colors of objects.
101  * 
102  * 145   12/29/97 5:09p Allender
103  * fixed problems with speed not being reported properly in multiplayer
104  * games.  Made read_flying_controls take frametime as a parameter.  More
105  * ship/weapon select stuff
106  * 
107  * 144   10/30/97 3:30p Hoffoss
108  * Made anti-aliased gridlines an option in Fred.
109  * 
110  * 143   10/29/97 5:13p John
111  * Trying to fix my lighting bugs in Fred.
112  * 
113  * 142   10/03/97 9:48a John
114  * took out alphacolors some grid lines don't draw antialiased.
115  * 
116  * 141   10/03/97 8:55a John
117  * moved Fred's grid_render code out of MissionGrid and into Fred.   Added
118  * code to turn background under overlays grey.
119  * 
120  * 140   9/18/97 9:59a John
121  * fixed bug I caused in model_collide
122  * 
123  * 139   9/16/97 9:41p Hoffoss
124  * Changed Fred code around to stop using Parse_player structure for
125  * player information, and use actual ships instead.
126  * 
127  * 138   9/09/97 2:12p Hoffoss
128  * Added code to allow briefing editor view to be a 1:1 pixel size fixed
129  * as the FreeSpace view will have.
130  * 
131  * 137   9/06/97 2:13p Mike
132  * Replace support for TEAM_NEUTRAL
133  * 
134  * 136   8/29/97 5:41p Johnson
135  * Fixed bug with controlling marked objects without having done any
136  * rotations yet of any other type.
137  * 
138  * 135   8/25/97 5:58p Hoffoss
139  * Created menu items for keypress functions in Fred, and fixed bug this
140  * uncovered with wing_delete function.
141  * 
142  * 134   8/19/97 5:46p Hoffoss
143  * Changed font used in Fred, and added display to show current eye
144  * position.
145  * 
146  * 133   8/19/97 11:23a Hoffoss
147  * Fixes to briefing editor icon select code.
148  * 
149  * 132   8/17/97 10:22p Hoffoss
150  * Fixed several bugs in Fred with Undo feature.  In the process, recoded
151  * a lot of CFile.cpp.
152  * 
153  * 131   8/16/97 2:02a Hoffoss
154  * Made docked objects move together in Fred.
155  * 
156  * 130   8/14/97 7:01p Hoffoss
157  * Fixed bug with outline rendering while in background bitmap editing
158  * mode.
159  * 
160  * 129   8/14/97 2:32p Hoffoss
161  * fixed bug where controlling an object doesn't cause screen updates, and
162  * added a number of cool features to viewpoint/control object code.
163  * 
164  * 128   8/13/97 1:38p Hoffoss
165  * Added ability to update multiple times, which in needed in one case to
166  * brute force redraw so deleted ships actually do get removed from the
167  * display.
168  * 
169  * 127   8/12/97 1:55a Hoffoss
170  * Made extensive changes to object reference checking and handling for
171  * object deletion call.
172  * 
173  * 126   8/07/97 6:01p Hoffoss
174  * Added a rotate about selected object button to toolbar and
175  * functionality, as requested by Comet.
176  * 
177  * 125   8/06/97 7:55p Hoffoss
178  * Fixed bug with objects not seeming to be where they are drawn (due to
179  * new briefing clip render stuff).  This caused rendering problems,
180  * though.  So I fixed those next.
181  * 
182  * 124   8/06/97 6:10p Hoffoss
183  * Changed Fred to display a forced aspect ratio while briefing editor is
184  * open.  This aspect ratio is the same as the briefing view in FreeSpace,
185  * so icons appear on and off screen the same as would be in FreeSpace.
186  * 
187  * 123   7/24/97 10:24a Mike
188  * Restore support for Unknown team
189  * 
190  * 122   7/17/97 1:34p Hoffoss
191  * Fixed Fred to work with physics changes.
192  * 
193  * 121   6/26/97 6:03p Hoffoss
194  * briefing icon selection now has higher priority of selection than other
195  * objects.
196  * 
197  * 120   6/26/97 5:18p Hoffoss
198  * Major rework of briefing editor functionality.
199  * 
200  * 119   6/26/97 4:20p Hoffoss
201  * Changed the behavior of Ctrl-L
202  *
203  * $NoKeywords: $
204  */
205
206 #include "stdafx.h"
207 #include "fred.h"
208 #include "freddoc.h"
209 #include "fredview.h"
210 #include "mainfrm.h"
211
212 #include <stdio.h>
213 #include <stdlib.h>
214 #include <string.h>
215 #include <float.h>
216
217 #include "management.h"
218 #include "vecmat.h"
219 #include "tmapper.h"
220 #include "2d.h"
221 #include "3d.h"
222 #include "model.h"
223 #include "bmpman.h"
224 #include "key.h"
225 #include "physics.h"
226 #include "floating.h"
227 #include "object.h"
228 #include "model.h"
229 #include "palman.h"
230 #include "editor.h"
231 #include "ailocal.h"
232 #include "ship.h"
233 #include "cfile.h"
234 #include "missionparse.h"
235 #include "linklist.h"
236 #include "fvi.h"
237 #include "3dinternal.h"
238 #include "weapon.h"
239 #include "wing.h"
240 #include "fredrender.h"
241 #include "windows.h"
242 #include "starfield.h"
243 #include "timer.h"
244 #include "lighting.h"
245 #include "asteroid.h"
246 #include "jumpnode.h"
247
248 extern float flFrametime;
249 extern subsys_to_render Render_subsys;
250
251 #ifdef _DEBUG
252 #define new DEBUG_NEW
253 #undef THIS_FILE
254 static char THIS_FILE[] = __FILE__;
255 #endif
256
257 #define MAX_FRAMETIME   (F1_0/4)                // Frametime gets saturated at this.
258 #define MIN_FRAMETIME   (F1_0/120)
259 #define MAX_STARS               500
260 #define LOLLIPOP_SIZE   2.5f
261
262 int     Aa_gridlines = 0;
263 int     Fred_outline = 0;
264 int     inited = -1;
265 int     player_start1;
266 int     Editing_mode = 1;
267 int     Control_mode = 0;
268 int     last_x=0, last_y=0;
269 int     Show_grid = 1;
270 int     Show_outlines = 0;
271 int     Show_stars = 0;
272 int     Show_grid_positions = 1;
273 int     Show_coordinates = 0;
274 int     Show_distances = 0;
275 int     Show_horizon = 0;
276 int     Show_asteroid_field = 1;
277 int     Lookat_mode = 0;
278 int     Single_axis_constraint = 0;
279 int     Universal_heading = 0;
280 int     Flying_controls_mode = 1;
281 int     Group_rotate = 1;
282 int     info_popup_active = 0;
283 int     rendering_order[MAX_SHIPS];
284 int     render_count = 0;
285 int     Last_cursor_over = -1;
286 int     True_rw, True_rh;
287 int     Fixed_briefing_size = 1;
288
289 fix             lasttime = 0;
290 vector  my_pos = {0.0f, 0.0f, -5.0f};
291 vector  view_pos, eye_pos, Viewer_pos, Last_eye_pos = { 0.0f };
292 vector  Last_control_pos = { 0.0f };
293 vector  Grid_center;
294 vector  Constraint = { 1.0f, 0.0f, 1.0f };
295 vector  Anticonstraint = { 0.0f, 1.0f, 0.0f };
296 vector  Tp1, Tp2;  // test points
297 matrix  Grid_gmatrix;
298 matrix  my_orient = IDENTITY_MATRIX;
299 matrix  trackball_orient = IDENTITY_MATRIX;
300 matrix  view_orient = IDENTITY_MATRIX, eye_orient, Last_eye_orient = IDENTITY_MATRIX;
301 matrix  Last_control_orient = IDENTITY_MATRIX;
302 physics_info view_physics;
303 control_info view_controls;
304 CWnd            info_popup;
305
306 static vector Global_light_world = { 0.208758f, -0.688253f, -0.694782f };
307
308 void display_distances();
309 void render_model_x(vector *pos, grid *gridp, int col_scheme = 0);
310 void draw_orient_sphere(object *obj, int r, int g, int b);
311 void draw_orient_sphere2(int col, object *obj, int r, int g, int b);
312 void render_compass(void);
313 void draw_compass_arrow(vector *v0);
314 void process_controls(vector *pos, matrix *orient, float frametime, int key, int mode = 0);
315 void render_one_model(object *objp);
316 void inc_mission_time();
317 void draw_asteroid_field();
318 void hilight_bitmap();
319
320 // Called every time a new mission is created (and erasing old mission from memory).
321 // New mission should be blank at this point.
322 void fred_render_init()
323 {
324         vector f, u, r;
325
326         physics_init(&view_physics);
327         view_physics.max_vel.z = 5.0f;          //forward/backward
328         view_physics.max_rotvel.x = 1.5f;               //pitch 
329         memset(&view_controls, 0, sizeof(control_info));
330
331         vm_vec_make(&view_pos, 0.0f, 150.0f, -200.0f);
332         vm_vec_make(&f, 0.0f, -0.5f, 0.866025404f);  // 30 degree angle
333         vm_vec_make(&u, 0.0f, 0.866025404f, 0.5f);
334         vm_vec_make(&r, 1.0f, 0.0f, 0.0f);
335         vm_vector_2_matrix(&view_orient, &f, &u, &r);
336
337         The_grid = create_default_grid();
338         maybe_create_new_grid(The_grid, &view_pos, &view_orient, 1);
339 //      vm_set_identity(&view_orient);
340 }
341
342 void level_object(matrix *orient)
343 {
344         vector u;
345
346         u = orient->uvec = The_grid->gmatrix.uvec;
347         if (u.x)  // y-z plane
348         {
349                 orient->fvec.x = orient->rvec.x = 0.0f;
350
351         } else if (u.y) {  // x-z plane
352                 orient->fvec.y = orient->rvec.y = 0.0f;
353
354         } else if (u.z) {  // x-y plane
355                 orient->fvec.z = orient->rvec.z = 0.0f;
356         }
357
358         vm_fix_matrix(orient);
359 }
360
361 void level_controlled()
362 {
363         int cmode, count = 0;
364         object *objp;
365
366         cmode = Control_mode;
367         if ((viewpoint == 1) && !cmode)
368                 cmode = 2;
369
370         switch (cmode) {
371                 case 0:         //      Control the viewer's location and orientation
372                         level_object(&view_orient);
373                         break;
374
375                 case 2:  // Control viewpoint object
376                         level_object(&Objects[view_obj].orient);
377                         object_moved(&Objects[view_obj]);
378                         set_modified();
379                         FREDDoc_ptr->autosave("level object");
380                         break;
381
382                 case 1:  //     Control the current object's location and orientation
383                         objp = GET_FIRST(&obj_used_list);
384                         while (objp != END_OF_LIST(&obj_used_list)) {
385                                 if (objp->flags & OF_MARKED)
386                                         level_object(&objp->orient);
387                                 
388                                 objp = GET_NEXT(objp);
389                         }
390
391                         objp = GET_FIRST(&obj_used_list);
392                         while (objp != END_OF_LIST(&obj_used_list)) {
393                                 if (objp->flags & OF_MARKED) {
394                                         object_moved(objp);
395                                         count++;
396                                 }
397                                 
398                                 objp = GET_NEXT(objp);
399                         }
400
401                         if (count) {
402                                 if (count > 1)
403                                         FREDDoc_ptr->autosave("level objects");
404                                 else
405                                         FREDDoc_ptr->autosave("level object");
406
407                                 set_modified();
408                         }
409
410                         break;
411         }
412
413         return;
414 }
415
416 void align_vector_to_axis(vector *v)
417 {
418         float x, y, z;
419
420         x = v->x;
421         if (x < 0)
422                 x = -x;
423
424         y = v->y;
425         if (y < 0)
426                 y = -y;
427
428         z = v->z;
429         if (z < 0)
430                 z = -z;
431
432         if ((x > y) && (x > z)) {  // x axis
433                 if (v->x < 0)  // negative x
434                         vm_vec_make(v, -1.0f, 0.0f, 0.0f);
435                 else  // positive x
436                         vm_vec_make(v, 1.0f, 0.0f, 0.0f);
437
438         } else if (y > z) {  // y axis
439                 if (v->y < 0)  // negative y
440                         vm_vec_make(v, 0.0f, -1.0f, 0.0f);
441                 else  // positive y
442                         vm_vec_make(v, 0.0f, 1.0f, 0.0f);
443
444         } else {  // z axis
445                 if (v->z < 0)  // negative z
446                         vm_vec_make(v, 0.0f, 0.0f, -1.0f);
447                 else  // positive z
448                         vm_vec_make(v, 0.0f, 0.0f, 1.0f);
449         }
450 }
451
452 void verticalize_object(matrix *orient)
453 {
454         align_vector_to_axis(&orient->fvec);
455         align_vector_to_axis(&orient->uvec);
456         align_vector_to_axis(&orient->rvec);
457         vm_fix_matrix(orient);  // just in case something odd occurs.
458 }
459
460 void verticalize_controlled()
461 {
462         int cmode, count = 0;
463         object *objp;
464
465         cmode = Control_mode;
466         if ((viewpoint == 1) && !cmode)
467                 cmode = 2;
468
469         switch (cmode) {
470                 case 0:         //      Control the viewer's location and orientation
471                         verticalize_object(&view_orient);
472                         break;
473
474                 case 2:  // Control viewpoint object
475                         verticalize_object(&Objects[view_obj].orient);
476                         object_moved(&Objects[view_obj]);
477                         FREDDoc_ptr->autosave("align object");
478                         set_modified();
479                         break;
480
481                 case 1:  //     Control the current object's location and orientation
482                         objp = GET_FIRST(&obj_used_list);
483                         while (objp != END_OF_LIST(&obj_used_list)) {
484                                 if (objp->flags & OF_MARKED)
485                                         verticalize_object(&objp->orient);
486                                 
487                                 objp = GET_NEXT(objp);
488                         }
489
490                         objp = GET_FIRST(&obj_used_list);
491                         while (objp != END_OF_LIST(&obj_used_list)) {
492                                 if (objp->flags & OF_MARKED) {
493                                         object_moved(objp);
494                                         count++;
495                                 }
496                                 
497                                 objp = GET_NEXT(objp);
498                         }
499
500                         if (count) {
501                                 if (count > 1)
502                                         FREDDoc_ptr->autosave("align objects");
503                                 else
504                                         FREDDoc_ptr->autosave("align object");
505
506                                 set_modified();
507                         }
508
509                         break;
510         }
511
512         return;
513 }
514
515 void move_mouse( int btn, int mdx, int mdy )
516 {
517         int dx, dy;
518
519         dx = mdx - last_x;
520         dy = mdy - last_y;
521         last_x = mdx;
522         last_y = mdy;
523
524         if ( btn & 1 )  {
525                 matrix tempm, mousem;
526
527                 if ( dx || dy ) {
528                         vm_trackball( dx, dy, &mousem );
529                         vm_matrix_x_matrix(&tempm, &trackball_orient, &mousem);
530                         trackball_orient = tempm;
531                         view_orient = trackball_orient;
532                 }
533         }
534
535         if ( btn & 2 )  {
536                 my_pos.z += (float)dy;
537         }
538 }
539
540 ///////////////////////////////////////////////////
541 void process_system_keys(int key)
542 {
543 //      mprintf(("Key = %d\n", key));
544         switch (key) {
545
546         case KEY_LAPOSTRO:
547                 CFREDView::GetView()->cycle_constraint();
548                 break;
549
550         case KEY_R:  // for some stupid reason, an accelerator for 'R' doesn't work.
551                 Editing_mode = 2;
552                 break;
553
554         case KEY_SPACEBAR:
555                 Selection_lock = !Selection_lock;
556                 break;
557
558         case KEY_ESC:
559                 if (button_down)
560                         cancel_drag();
561
562                 break;
563         }
564 }
565
566 void render_waypoints(void)
567 {
568         int i, j;
569         vertex v;
570         waypoint_list *ptr;
571
572         for (i=0; i<Num_waypoint_lists; i++)
573         {
574                 ptr = &Waypoint_lists[i];
575                 for (j=0; j<ptr->count; j++)
576                 {
577                         g3_rotate_vertex(&v, &ptr->waypoints[j]);
578                         if (!(v.codes & CC_BEHIND))
579                                 if (!(g3_project_vertex(&v) & PF_OVERFLOW))
580                                 {
581                                         if (cur_waypoint_list == i && cur_waypoint == j)
582                                                 gr_set_color(255, 255, 255);
583                                         else if (Waypoint_lists[i].flags[j] & WL_MARKED)
584                                                 gr_set_color(160, 255, 0);
585                                         else
586                                                 gr_set_color(160, 96, 0);
587
588                                         g3_draw_sphere(&v, LOLLIPOP_SIZE);
589                                         if (j)
590                                                 gr_set_color(0, 0, 0);
591                                         else
592                                                 gr_set_color(160, 96, 0);
593
594                                         g3_draw_sphere(&v, LOLLIPOP_SIZE * 0.66667f);
595                                         gr_set_color(160, 96, 0);
596                                         g3_draw_sphere(&v, LOLLIPOP_SIZE * 0.33333f);
597                                 }
598                 }
599
600                 for (j=0; j<ptr->count; j++)
601                         render_model_x(&ptr->waypoints[j], The_grid, 1);
602
603                 gr_set_color(160, 96, 0);
604                 for (j=1; j<ptr->count; j++)
605                         rpd_line(&ptr->waypoints[j-1], &ptr->waypoints[j]);
606         }
607 }
608
609 // --------------------------------------------------------------------------------
610 // get_subsystem_world_pos2() returns the world position for a given subobject on a ship
611 //
612
613 vector* get_subsystem_world_pos2(object* parent_obj, ship_subsys* subsys, vector* world_pos)
614 {
615         if (subsys == NULL) {
616                 *world_pos = parent_obj->pos;
617                 return world_pos;
618         }
619         
620         vm_vec_unrotate(world_pos, &subsys->system_info->pnt, &parent_obj->orient);
621         vm_vec_add2(world_pos, &parent_obj->pos);
622
623         return world_pos;
624 }
625
626 // returns 1 for valid bounding rect, 0 otherwise
627 int get_subsys_bounding_rect(object *ship_obj, ship_subsys *subsys, int *x1, int *x2, int *y1, int *y2)
628 {
629         if (subsys != NULL) {
630                 vertex subobj_vertex;
631                 vector  subobj_pos;
632
633                 get_subsystem_world_pos2(ship_obj, subsys, &subobj_pos);
634
635                 g3_rotate_vertex(&subobj_vertex, &subobj_pos);
636
637                 g3_project_vertex(&subobj_vertex);
638                 if (subobj_vertex.flags & PF_OVERFLOW)  // if overflow, no point in drawing brackets
639                         return 0;
640
641                 int bound_rc;
642
643                 bound_rc = subobj_find_2d_bound(subsys->system_info->radius, &ship_obj->orient, &subobj_pos, x1, y1, x2, y2);
644                 if ( bound_rc != 0 )
645                         return 0;
646
647                 return 1;
648         }
649
650         return 0;
651 }
652
653 void cancel_display_active_ship_subsystem()
654 {
655         Render_subsys.do_render = false;
656         Render_subsys.ship_obj = NULL;
657         Render_subsys.cur_subsys = NULL;
658 }
659
660 void display_active_ship_subsystem()
661 {
662         if (cur_object_index != -1) {
663                 if (Objects[cur_object_index].type == OBJ_SHIP) {
664
665                         object *objp = &Objects[cur_object_index];
666                         int x1, y1, x2, y2;
667                         char buf[256];
668
669                         // switching to a new ship, so reset
670                         if (objp != Render_subsys.ship_obj) {
671                                 cancel_display_active_ship_subsystem();
672                                 return;
673                         }
674
675                         if (Render_subsys.do_render) {
676
677                                 // get subsys name
678                                 strcpy(buf, Render_subsys.cur_subsys->system_info->subobj_name);
679
680                                 // get bounding box
681                                 if ( get_subsys_bounding_rect(objp, Render_subsys.cur_subsys, &x1, &x2, &y1, &y2) ) {
682
683                                         // set color
684                                         gr_set_color(255, 32, 32);
685
686                                         // draw box
687                                         gr_line(x1, y1, x1, y2);  gr_line(x1-1, y1, x1-1, y2);
688                                         gr_line(x1, y2, x2, y2);  gr_line(x1, y2+1, x2, y2+1);
689                                         gr_line(x2, y2, x2, y1);  gr_line(x2+1, y2, x2+1, y1);
690                                         gr_line(x2, y1, x1, y1);  gr_line(x2, y1-1, x1, y1-1);
691
692                                         // draw text
693                                         gr_string_win( (x1+x2)/2,  y2 + 10, buf);
694                                 }
695                         }
696                 }
697         } else {
698                 cancel_display_active_ship_subsystem();
699         }
700 }
701
702 void render_models(void)
703 {
704         render_count = 0;
705         obj_render_all(render_one_model);
706         if (Briefing_dialog)
707                 Briefing_dialog->batch_render();
708 }
709
710 void render_one_model(object *objp)
711 {
712         int j, z;
713         object *o2;
714
715         Assert(objp->type != OBJ_NONE);
716
717         if ( objp->type == OBJ_JUMP_NODE ) {
718                 return;
719         }
720
721         if ((objp->type == OBJ_WAYPOINT) && !Show_waypoints)
722                 return;
723
724         if ((objp->type == OBJ_START) && !Show_starts)
725                 return;
726
727         if (objp->type == OBJ_SHIP) {
728                 if (!Show_ships)
729                         return;
730
731                 if ((Ships[objp->instance].team == TEAM_FRIENDLY) && !Show_friendly)
732                         return;
733
734                 if ((Ships[objp->instance].team == TEAM_HOSTILE) && !Show_hostile)
735                         return;
736
737                 if ((Ships[objp->instance].team == TEAM_NEUTRAL) && !Show_neutral)
738                         return;
739         }
740
741         if (objp->flags & OF_HIDDEN)
742                 return;
743
744         rendering_order[render_count] = OBJ_INDEX(objp);
745         Fred_outline = 0;
746         if ((OBJ_INDEX(objp) == cur_object_index) && !Bg_bitmap_dialog)
747                 Fred_outline = 0xffffff;
748
749         else if ((objp->flags & OF_MARKED) && !Bg_bitmap_dialog)  // is it a marked object?
750                 Fred_outline = 0x9fff00;
751
752         else if ((objp->type == OBJ_SHIP) && Show_outlines) {
753                 switch (Ships[objp->instance].team)     {
754                         case TEAM_FRIENDLY:     Fred_outline = 0x0000c0;        break;
755                         case TEAM_NEUTRAL:      Fred_outline = 0x007f7f;        break;
756                         case TEAM_UNKNOWN:      Fred_outline = 0x684010;        break;
757                         case TEAM_HOSTILE:      Fred_outline = 0x7f0000;        break;
758                         default:
759                                 Fred_outline = 0x7f007f;        break;
760                 }
761
762         } else if ((objp->type == OBJ_START) && Show_outlines) {
763                 Fred_outline = 0x007f00;
764
765         } else
766                 Fred_outline = 0;
767
768         // build flags
769         if ((Show_ship_models || Show_outlines) && ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START))){
770                 if (Show_ship_models){
771                         j = MR_NORMAL;
772                 } else {
773                         j = MR_NO_POLYS;
774                 }
775                 
776                 if(Show_dock_points){
777                         j |= MR_BAY_PATHS;      
778                 }
779
780                 if(Show_paths_fred){
781                         j |= MR_SHOW_PATHS;
782                 }
783
784                 z = objp->instance;
785
786                 model_clear_instance( Ships[z].modelnum );
787
788 //              if (!viewpoint || OBJ_INDEX(objp) != cur_object_index)
789                 {
790                         if (Fred_outline)       {
791                                 model_set_outline_color(Fred_outline >> 16, (Fred_outline >> 8) & 0xff, Fred_outline & 0xff);
792                                 model_render(Ships[z].modelnum, &objp->orient, &objp->pos, j | MR_SHOW_OUTLINE);
793                         } else {
794                                 model_render(Ships[z].modelnum, &objp->orient, &objp->pos, j);
795                         }
796                 }
797         
798         } else {
799                 int r = 0, g = 0, b = 0;
800
801                 if (objp->type == OBJ_SHIP)
802                 {
803                         if (!Show_ships)
804                                 return;
805
806                         switch (Ships[objp->instance].team)     {
807                                 case TEAM_FRIENDLY:     r = 0;  g = 0;  b = 192;        break;
808                                 case TEAM_NEUTRAL:      r = 0;  g = 127;        b = 127;        break;
809                                 case TEAM_UNKNOWN:      r = 104;        g = 64; b = 16; break;
810                                 case TEAM_HOSTILE:      r = 127;        g = 0;  b = 0;  break;
811                                 default:                                        r = 127; g = 0; b = 0;  break;
812                         }
813
814                 } else if (objp->type == OBJ_START) {
815                         r = 0;  g = 127;        b = 0;
816
817                 } else if (objp->type == OBJ_WAYPOINT) {
818                         r = 96; g = 0;  b = 112;
819
820                 } else if (objp->type == OBJ_POINT) {
821                         if (objp->instance != BRIEFING_LOOKAT_POINT_ID) {
822                                 Assert(Briefing_dialog);
823                                 Briefing_dialog->draw_icon(objp);
824                                 goto skip;
825                         }
826
827                         r = 196;        g = 32; b = 196;
828
829                 } else
830                         Assert(0);
831
832                 if (Fred_outline)
833                         draw_orient_sphere2(Fred_outline, objp, r, g, b);
834                 else
835                         draw_orient_sphere(objp, r, g, b);
836         }
837
838 skip:
839         if (objp->type == OBJ_WAYPOINT)
840                 for (j=0; j<render_count; j++)
841                 {
842                         o2 = &Objects[rendering_order[j]];
843                         if (o2->type == OBJ_WAYPOINT)
844                                 if ((o2->instance == objp->instance - 1) || (o2->instance == objp->instance + 1))
845                                         rpd_line(&o2->pos, &objp->pos);
846                 }
847
848         render_model_x(&objp->pos, The_grid);
849         render_count++;
850 }
851
852 void display_distances()
853 {
854         char buf[20];
855         object *objp, *o2;
856         vector pos;
857         vertex v;
858
859         gr_set_color(255, 0, 0);
860         objp = GET_FIRST(&obj_used_list);
861         while (objp != END_OF_LIST(&obj_used_list))
862         {
863                 if (objp->flags & OF_MARKED)
864                 {
865                         o2 = GET_NEXT(objp);
866                         while (o2 != END_OF_LIST(&obj_used_list))
867                         {
868                                 if (o2->flags & OF_MARKED)
869                                 {
870                                         rpd_line(&objp->pos, &o2->pos);
871                                         vm_vec_avg(&pos, &objp->pos, &o2->pos);
872                                         g3_rotate_vertex(&v, &pos);
873                                         if (!(v.codes & CC_BEHIND))
874                                                 if (!(g3_project_vertex(&v) & PF_OVERFLOW))     {
875                                                         sprintf(buf, "%.1f", vm_vec_dist(&objp->pos, &o2->pos));
876                                                         gr_string_win((int) v.sx, (int) v.sy, buf);
877                                                 }
878                                 }
879
880                                 o2 = GET_NEXT(o2);
881                         }
882                 }
883
884                 objp = GET_NEXT(objp);
885         }
886 }
887
888 void display_ship_info()
889 {
890         char buf[512], pos[80];
891         int render = 1;
892         object *objp;
893         vertex  v;
894
895         objp = GET_FIRST(&obj_used_list);
896         while (objp != END_OF_LIST(&obj_used_list))     {
897                 Assert(objp->type != OBJ_NONE);
898                 Fred_outline = 0;
899                 render = 1;
900                 if (OBJ_INDEX(objp) == cur_object_index)
901                         Fred_outline = 0xffffff;
902                 else if (objp->flags & OF_MARKED)  // is it a marked object?
903                         Fred_outline = 0x9fff00;
904                 else
905                         Fred_outline = 0;
906
907                 if ((objp->type == OBJ_WAYPOINT) && !Show_waypoints)
908                         render = 0;
909
910                 if ((objp->type == OBJ_START) && !Show_starts)
911                         render = 0;
912                 
913                 if (objp->type == OBJ_SHIP) {
914                         if (!Show_ships)
915                                 render = 0;
916
917                         if ((Ships[objp->instance].team == TEAM_FRIENDLY) && !Show_friendly)
918                                 render = 0;
919
920                         if ((Ships[objp->instance].team == TEAM_HOSTILE) && !Show_hostile)
921                                 render = 0;
922
923                         if ((Ships[objp->instance].team == TEAM_NEUTRAL) && !Show_neutral)
924                                 render = 0;
925                 }
926
927                 if (objp->flags & OF_HIDDEN)
928                         render = 0;
929                 
930                 g3_rotate_vertex(&v, &objp->pos);
931                 if (!(v.codes & CC_BEHIND) && render)
932                         if (!(g3_project_vertex(&v) & PF_OVERFLOW))     {
933                                 *buf = 0;
934                                 if (Show_ship_info)
935                                 {
936                                         if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) {
937                                                 ship *shipp;
938                                                 int ship_type;
939
940                                                 shipp = &Ships[objp->instance];
941                                                 ship_type = shipp->ship_info_index;
942                                                 ASSERT(ship_type >= 0);
943                                                 sprintf(buf, "%s\n%s", shipp->ship_name, Ship_info[ship_type].short_name);
944
945                                         } else if (objp->type == OBJ_WAYPOINT) {
946                                                 sprintf(buf, "%s\nWaypoint %d",
947                                                         Waypoint_lists[objp->instance / 65536].name,
948                                                         (objp->instance & 0xffff) + 1);
949
950                                         } else if (objp->type == OBJ_POINT) {
951                                                 if (objp->instance == BRIEFING_LOOKAT_POINT_ID)
952                                                         strcpy(buf, "Camera lookat point");
953                                                 else
954                                                         strcpy(buf, "Briefing icon");
955
956                                         } else if (objp->type == OBJ_JUMP_NODE) {
957                                                 strcpy(buf, "Jump Node");
958                                         } else
959                                                 Assert(0);
960                                 }
961
962                                 if (Show_coordinates)
963                                 {
964                                         sprintf(pos, "( %.0f , %.0f , %.0f )", objp->pos.x, objp->pos.y, objp->pos.z);
965                                         if (*buf)
966                                                 strcat(buf, "\n");
967
968                                         strcat(buf, pos);
969                                 }
970
971                                 if (*buf)
972                                 {
973                                         if (Fred_outline)
974                                                 gr_set_color(Fred_outline >> 16, (Fred_outline >> 8) & 0xff, Fred_outline & 0xff);
975                                         else
976                                                 gr_set_color(160, 160, 160);
977
978                                         gr_string_win((int) v.sx, (int) v.sy, buf);
979                                 }
980                         }
981
982                 objp = GET_NEXT(objp);
983         }
984 }
985
986 void draw_orient_sphere(object *obj, int r, int g, int b)
987 {
988         int             flag = 0;
989         vertex  v;
990         vector  v1, v2;
991         float           size;
992
993         size = fl_sqrt(vm_vec_dist(&eye_pos, &obj->pos) / 20.0f);
994         if (size < LOLLIPOP_SIZE)
995                 size = LOLLIPOP_SIZE;
996
997         if ((obj->type != OBJ_WAYPOINT) && (obj->type != OBJ_POINT))
998         {
999                 flag = (vm_vec_dotprod(&eye_orient.fvec, &obj->orient.fvec) < 0.0f);
1000                 v1 = v2 = obj->pos;
1001                 vm_vec_scale_add2(&v1, &obj->orient.fvec, size);
1002                 vm_vec_scale_add2(&v2, &obj->orient.fvec, size * 1.5f);
1003
1004                 if (!flag)      {
1005                         gr_set_color(192, 192, 192);
1006                         rpd_line(&v1, &v2);
1007                 }
1008         }
1009
1010         gr_set_color(r, g, b);
1011         g3_rotate_vertex(&v, &obj->pos);
1012         if (!(v.codes & CC_BEHIND))
1013                 if (!(g3_project_vertex(&v) & PF_OVERFLOW))
1014                         g3_draw_sphere(&v, size);
1015
1016         if (flag)       {
1017                 gr_set_color(192, 192, 192);
1018                 rpd_line(&v1, &v2);
1019         }
1020 }
1021
1022 void draw_orient_sphere2(int col, object *obj, int r, int g, int b)
1023 {
1024         int             flag = 0;
1025         vertex  v;
1026         vector  v1, v2;
1027         float           size;
1028
1029         size = fl_sqrt(vm_vec_dist(&eye_pos, &obj->pos) / 20.0f);
1030         if (size < LOLLIPOP_SIZE)
1031                 size = LOLLIPOP_SIZE;
1032
1033         if ((obj->type != OBJ_WAYPOINT) && (obj->type != OBJ_POINT))
1034         {
1035                 flag = (vm_vec_dotprod(&eye_orient.fvec, &obj->orient.fvec) < 0.0f);
1036
1037                 v1 = v2 = obj->pos;
1038                 vm_vec_scale_add2(&v1, &obj->orient.fvec, size);
1039                 vm_vec_scale_add2(&v2, &obj->orient.fvec, size * 1.5f);
1040
1041                 if (!flag)      {
1042                         gr_set_color(192, 192, 192);
1043                         rpd_line(&v1, &v2);
1044                 }
1045         }
1046
1047         g3_rotate_vertex(&v, &obj->pos);
1048         if (!(v.codes & CC_BEHIND))
1049                 if (!(g3_project_vertex(&v) & PF_OVERFLOW))
1050                 {
1051                         gr_set_color((col >> 16) & 0xff, (col >> 8) & 0xff, col & 0xff);
1052                         g3_draw_sphere(&v, size);
1053                         gr_set_color(r, g, b);
1054                         g3_draw_sphere(&v, size * 0.75f);
1055                 }
1056
1057         if (flag)       {
1058                 gr_set_color(192, 192, 192);
1059                 rpd_line(&v1, &v2);
1060         }
1061 }
1062
1063 void render_model_x(vector *pos, grid *gridp, int col_scheme)
1064 {
1065         vector  gpos;   //      Location of point on grid.
1066         vector  tpos;
1067         float   dxz;
1068         plane   tplane;
1069         vector  *gv;
1070
1071         if (!Show_grid_positions)
1072                 return;
1073
1074         tplane.A = gridp->gmatrix.uvec.x;
1075         tplane.B = gridp->gmatrix.uvec.y;
1076         tplane.C = gridp->gmatrix.uvec.z;
1077         tplane.D = gridp->planeD;
1078
1079         compute_point_on_plane(&gpos, &tplane, pos);
1080         dxz = vm_vec_dist(pos, &gpos)/8.0f;
1081         gv = &gridp->gmatrix.uvec;
1082         if (gv->x * pos->x + gv->y * pos->y + gv->z * pos->z < -gridp->planeD)
1083                 gr_set_color(0, 127, 0);
1084         else
1085                 gr_set_color(192, 192, 192);
1086
1087
1088         rpd_line(&gpos, pos);   //      Line from grid to object center.
1089
1090         tpos = gpos;
1091
1092         vm_vec_scale_add2(&gpos, &gridp->gmatrix.rvec, -dxz/2);
1093         vm_vec_scale_add2(&gpos, &gridp->gmatrix.fvec, -dxz/2);
1094         
1095         vm_vec_scale_add2(&tpos, &gridp->gmatrix.rvec, dxz/2);
1096         vm_vec_scale_add2(&tpos, &gridp->gmatrix.fvec, dxz/2);
1097         
1098         rpd_line(&gpos, &tpos);
1099
1100         vm_vec_scale_add2(&gpos, &gridp->gmatrix.rvec, dxz);
1101         vm_vec_scale_add2(&tpos, &gridp->gmatrix.rvec, -dxz);
1102
1103         rpd_line(&gpos, &tpos);
1104 }
1105
1106 void render_active_rect(void)
1107 {
1108         if (box_marking) {
1109                 gr_set_color(255, 255, 255);
1110                 gr_line(marking_box.x1, marking_box.y1, marking_box.x1, marking_box.y2);
1111                 gr_line(marking_box.x1, marking_box.y2, marking_box.x2, marking_box.y2);
1112                 gr_line(marking_box.x2, marking_box.y2, marking_box.x2, marking_box.y1);
1113                 gr_line(marking_box.x2, marking_box.y1, marking_box.x1, marking_box.y1);
1114         }
1115 }
1116
1117
1118 void process_movement_keys(int key, vector *mvec, angles *angs)
1119 {
1120         int     raw_key;
1121
1122         mvec->x = 0.0f;
1123         mvec->y = 0.0f;
1124         mvec->z = 0.0f;
1125         angs->p = 0.0f;
1126         angs->b = 0.0f;
1127         angs->h = 0.0f;
1128
1129         raw_key = key & 0xff;
1130
1131         switch (raw_key) {
1132         case KEY_PAD1:          mvec->x += -1.0f;       break;
1133         case KEY_PAD3:          mvec->x += +1.0f;       break;
1134         case KEY_PADPLUS:       mvec->y += -1.0f;       break;
1135         case KEY_PADMINUS:      mvec->y += +1.0f;       break;
1136         case KEY_A:                     mvec->z += +1.0f;       break;
1137         case KEY_Z:                     mvec->z += -1.0f;       break;
1138         case KEY_PAD4:          angs->h += -0.1f;       break;
1139         case KEY_PAD6:          angs->h += +0.1f;       break;
1140         case KEY_PAD8:          angs->p += -0.1f;       break;
1141         case KEY_PAD2:          angs->p += +0.1f;       break;
1142         case KEY_PAD7:          angs->b += -0.1f;       break;
1143         case KEY_PAD9:          angs->b += +0.1f;       break;
1144
1145         }
1146
1147         if (key & KEY_SHIFTED) {
1148                 vm_vec_scale(mvec, 5.0f);
1149                 angs->p *= 5.0f;
1150                 angs->b *= 5.0f;
1151                 angs->h *= 5.0f;
1152         }
1153 }
1154
1155 void process_controls(vector *pos, matrix *orient, float frametime, int key, int mode)
1156 {
1157         if (Flying_controls_mode)       {
1158                 grid_read_camera_controls(&view_controls, frametime);
1159
1160                 if (key_get_shift_status())
1161                         memset(&view_controls, 0, sizeof(control_info));
1162
1163                 if ((fabs(view_controls.pitch) > (frametime / 100)) &&
1164                         (fabs(view_controls.vertical) > (frametime / 100)) &&
1165                         (fabs(view_controls.heading) > (frametime / 100)) &&
1166                         (fabs(view_controls.sideways) > (frametime / 100)) &&
1167                         (fabs(view_controls.bank) > (frametime / 100)) &&
1168                         (fabs(view_controls.forward) > (frametime / 100)))
1169                                 Update_window = 1;
1170
1171                 flFrametime = frametime;
1172                 physics_read_flying_controls(orient, &view_physics, &view_controls, flFrametime);
1173                 if (mode)
1174                         physics_sim_editor(pos, orient, &view_physics, frametime);
1175                 else
1176                         physics_sim(pos, orient, &view_physics, frametime);
1177
1178         } else {
1179                 vector          movement_vec, rel_movement_vec;
1180                 angles          rotangs;
1181                 matrix          newmat, rotmat;
1182
1183                 process_movement_keys(key, &movement_vec, &rotangs);
1184                 vm_vec_rotate(&rel_movement_vec, &movement_vec, &The_grid->gmatrix);
1185                 vm_vec_add2(pos, &rel_movement_vec);
1186
1187                 vm_angles_2_matrix(&rotmat, &rotangs);
1188                 if (rotangs.h && Universal_heading)
1189                         vm_transpose_matrix(orient);
1190                 vm_matrix_x_matrix(&newmat, orient, &rotmat);
1191                 *orient = newmat;
1192                 if (rotangs.h && Universal_heading)
1193                         vm_transpose_matrix(orient);
1194         }
1195 }
1196
1197 int Fred_grid_colors_inited = 0;
1198 color Fred_grid_bright, Fred_grid_dark, Fred_grid_bright_aa, Fred_grid_dark_aa;
1199
1200 //      Renders a grid defined in a grid struct
1201 void fred_render_grid(grid *gridp)
1202 {
1203         int     i, ncols, nrows;
1204
1205         if ( !Fred_grid_colors_inited ) {
1206                 Fred_grid_colors_inited = 1;
1207
1208                 gr_init_alphacolor( &Fred_grid_dark_aa, 64, 64, 64, 255 );
1209                 gr_init_alphacolor( &Fred_grid_bright_aa, 128, 128, 128, 255 );
1210                 gr_init_color( &Fred_grid_dark, 64, 64, 64 );
1211                 gr_init_color( &Fred_grid_bright, 128, 128, 128 );
1212         }
1213
1214         ncols = gridp->ncols;
1215         nrows = gridp->nrows;
1216         if (double_fine_gridlines) {
1217                 ncols *= 2;
1218                 nrows *= 2;
1219         }
1220
1221         if (Aa_gridlines)
1222                 gr_set_color_fast(&Fred_grid_dark_aa);
1223         else
1224                 gr_set_color_fast(&Fred_grid_dark);
1225
1226         //      Draw the column lines.
1227         for (i=0; i<=ncols; i++)
1228                 rpd_line(&gridp->gpoints1[i], &gridp->gpoints2[i]);
1229
1230         //      Draw the row lines.
1231         for (i=0; i<=nrows; i++)
1232                 rpd_line(&gridp->gpoints3[i], &gridp->gpoints4[i]);
1233
1234         ncols = gridp->ncols / 2;
1235         nrows = gridp->nrows / 2;
1236
1237         // now draw the larger, brighter gridlines that is x10 the scale of smaller one.
1238         if (Aa_gridlines)
1239                 gr_set_color_fast(&Fred_grid_bright_aa);
1240         else
1241                 gr_set_color_fast(&Fred_grid_bright);
1242         
1243         for (i=0; i<=ncols; i++)
1244                 rpd_line(&gridp->gpoints5[i], &gridp->gpoints6[i]);
1245
1246         for (i=0; i<=nrows; i++)
1247                 rpd_line(&gridp->gpoints7[i], &gridp->gpoints8[i]);
1248 }
1249
1250 void render_frame()
1251 {
1252         char buf[256];
1253         int x, y, w, h, inst;
1254         vector pos;
1255         vertex v;
1256         angles a;
1257
1258         g3_end_frame();
1259
1260         gr_reset_clip();
1261         gr_clear();
1262
1263         if (Briefing_dialog) {
1264                 CRect rect;
1265
1266                 Fred_main_wnd->GetClientRect(rect);
1267                 True_rw = rect.Width();
1268                 True_rh = rect.Height();
1269                 if (Fixed_briefing_size) {
1270                         True_rw = BRIEF_GRID_W;
1271                         True_rh = BRIEF_GRID_H;
1272
1273                 } else {
1274                         if ((float) True_rh / (float) True_rw > (float) BRIEF_GRID_H / (float) BRIEF_GRID_W) {
1275                                 True_rh = (int) ((float) BRIEF_GRID_H * (float) True_rw / (float) BRIEF_GRID_W);
1276
1277                         } else {  // Fred is wider than briefing window
1278                                 True_rw = (int) ((float) BRIEF_GRID_W * (float) True_rh / (float) BRIEF_GRID_H);
1279                         }
1280                 }
1281
1282                 g3_start_frame(0);
1283                 gr_set_color(255, 255, 255);
1284                 gr_line(0, True_rh, True_rw, True_rh);
1285                 gr_line(True_rw, 0, True_rw, True_rh);
1286                 g3_end_frame();
1287                 gr_set_clip(0, 0, True_rw, True_rh);
1288         }
1289
1290         g3_start_frame(1);              // 1 means use zbuffering
1291         gr_set_font(Fred_font);
1292         light_reset();
1293
1294         g3_set_view_matrix(&eye_pos, &eye_orient, 0.5f);
1295         Viewer_pos = eye_pos;  // for starfield code
1296         
1297         if ( Bg_bitmap_dialog ) {
1298                 stars_draw( Show_stars, 1, Show_stars, 0 );
1299         } else {
1300                 stars_draw( Show_stars, Show_stars, Show_stars, 0 );
1301         }
1302
1303         if (Show_horizon) {
1304                 gr_set_color(128, 128, 64);
1305                 g3_draw_horizon_line();
1306         }
1307
1308         if (Show_asteroid_field) {
1309                 gr_set_color(192, 96, 16);
1310                 draw_asteroid_field();
1311         }
1312
1313         if (Show_grid)
1314                 fred_render_grid(The_grid);
1315         if (Bg_bitmap_dialog)
1316                 hilight_bitmap();
1317
1318         gr_set_color(0, 0, 64);
1319         render_models();
1320         if (Show_distances)
1321                 display_distances();
1322
1323         display_ship_info();
1324         display_active_ship_subsystem();
1325         render_active_rect();
1326
1327         if (query_valid_object(Cursor_over)) {  // display a tool-tip like infobox
1328                 pos = Objects[Cursor_over].pos;
1329                 inst = Objects[Cursor_over].instance;
1330                 if ((Objects[Cursor_over].type == OBJ_SHIP) || (Objects[Cursor_over].type == OBJ_START)) {
1331                         vm_extract_angles_matrix(&a, &Objects[Cursor_over].orient);
1332                         sprintf(buf, "%s\n%s\n( %.1f , %.1f , %.1f )\nHeading: %.2f\nPitch: %.2f\nBank: %.2f",
1333                                 Ships[inst].ship_name, Ship_info[Ships[inst].ship_info_index].short_name,
1334                                 pos.x, pos.y, pos.z, a.h, a.p, a.b);
1335
1336                 } else if (Objects[Cursor_over].type == OBJ_WAYPOINT) {
1337                         sprintf(buf, "%s\nWaypoint %d\n( %.1f , %.1f , %.1f )",
1338                                 Waypoint_lists[inst / 65536].name, (inst & 0xffff) + 1, pos.x, pos.y, pos.z);
1339
1340                 } else if (Objects[Cursor_over].type == OBJ_POINT) {
1341                         sprintf(buf, "Briefing icon\n( %.1f , %.1f , %.1f )", pos.x, pos.y, pos.z);
1342
1343                 } else
1344                         sprintf(buf, "( %.1f , %.1f , %.1f )", pos.x, pos.y, pos.z);
1345
1346                 g3_rotate_vertex(&v, &pos);
1347                 if (!(v.codes & CC_BEHIND))
1348                         if (!(g3_project_vertex(&v) & PF_OVERFLOW))     {
1349                                 x = (int) v.sx;
1350                                 y = (int) v.sy + 20;
1351                                 gr_get_string_size_win(&w, &h, buf);
1352                                 gr_set_color(192, 192, 192);
1353                                 gr_rect(x-1, y-1, w+2, h+2);
1354                                 gr_set_color(255, 255, 255);
1355                                 gr_line(x-2, y-2, x+w+1, y-2);
1356                                 gr_line(x-2, y-2, x-2, y+h+1);
1357                                 gr_line(x+w+1, y-2, x+w+1, y+h+1);
1358                                 gr_line(x-2, y+h+1, x+w+1, y+h+1);
1359
1360                                 gr_set_color(0, 0, 0);
1361                                 gr_string_win(x, y, buf);
1362                         }
1363         }
1364
1365         gr_set_color(0, 160, 0);
1366         jumpnode_render_all();
1367
1368         sprintf(buf, "( %.1f , %.1f , %.1f )", eye_pos.x, eye_pos.y, eye_pos.z);
1369         gr_get_string_size_win(&w, &h, buf);
1370         gr_set_color(192, 192, 192);
1371         gr_string_win(gr_screen.max_w - w - 2, 2, buf);
1372
1373         g3_end_frame();
1374         render_compass();
1375         gr_reset_clip();
1376         if (Briefing_dialog)
1377                 gr_set_clip(0, 0, True_rw, True_rh);
1378
1379         g3_start_frame(0);
1380         g3_set_view_matrix(&eye_pos, &eye_orient, 0.5f);
1381 }
1382
1383 void game_do_frame()
1384 {
1385         int key, cmode;
1386         vector viewer_position, control_pos;
1387         object *objp;
1388         matrix control_orient;
1389
1390         inc_mission_time();
1391
1392         viewer_position = my_orient.fvec;
1393         vm_vec_scale(&viewer_position,my_pos.z);
1394
1395         if ((viewpoint == 1) && !query_valid_object(view_obj))
1396                 viewpoint = 0;
1397
1398         key = key_inkey();
1399         process_system_keys(key);
1400         cmode = Control_mode;
1401         if ((viewpoint == 1) && !cmode)
1402                 cmode = 2;
1403
1404         control_pos = Last_control_pos;
1405         control_orient = Last_control_orient;
1406
1407 //      if ((key & KEY_MASK) == key)  // unmodified
1408                 switch (cmode) {
1409                         case 0:         //      Control the viewer's location and orientation
1410                                 process_controls(&view_pos, &view_orient, f2fl(Frametime), key, 1);
1411                                 control_pos = view_pos;
1412                                 control_orient = view_orient;
1413                                 break;
1414
1415                         case 2:  // Control viewpoint object
1416                                 process_controls(&Objects[view_obj].pos, &Objects[view_obj].orient, f2fl(Frametime), key);
1417                                 object_moved(&Objects[view_obj]);
1418                                 control_pos = Objects[view_obj].pos;
1419                                 control_orient = Objects[view_obj].orient;
1420                                 break;
1421
1422                         case 1:  //     Control the current object's location and orientation
1423                                 if (query_valid_object()) {
1424                                         vector delta_pos, leader_old_pos;
1425                                         matrix leader_orient, leader_transpose, tmp;
1426                                         object *leader;
1427                                         
1428                                         leader = &Objects[cur_object_index];
1429                                         leader_old_pos = leader->pos;  // save original position
1430                                         leader_orient = leader->orient;                 // save original orientation
1431                                         vm_copy_transpose_matrix(&leader_transpose, &leader_orient);
1432
1433                                         process_controls(&leader->pos, &leader->orient, f2fl(Frametime), key);
1434                                         vm_vec_sub(&delta_pos, &leader->pos, &leader_old_pos);  // get position change
1435                                         control_pos = leader->pos;
1436                                         control_orient = leader->orient;
1437
1438                                         objp = GET_FIRST(&obj_used_list);
1439                                         while (objp != END_OF_LIST(&obj_used_list))                     {
1440                                                 Assert(objp->type != OBJ_NONE);
1441                                                 if ((objp->flags & OF_MARKED) && (cur_object_index != OBJ_INDEX(objp))) {
1442                                                         if (Group_rotate) {
1443                                                                 matrix rot_trans;
1444                                                                 vector tmpv1, tmpv2;
1445
1446                                                                 // change rotation matrix to rotate in opposite direction.  This rotation
1447                                                                 // matrix is what the leader ship has rotated by.
1448                                                                 vm_copy_transpose_matrix(&rot_trans, &view_physics.last_rotmat);
1449
1450                                                                 // get point relative to our point of rotation (make POR the origin).  Since
1451                                                                 // only the leader has been moved yet, and not the objects, we have to use
1452                                                                 // the old leader's position.
1453                                                                 vm_vec_sub(&tmpv1, &objp->pos, &leader_old_pos);
1454
1455                                                                 // convert point from real-world coordinates to leader's relative coordinate
1456                                                                 // system (z=forward vec, y=up vec, x=right vec
1457                                                                 vm_vec_rotate(&tmpv2, &tmpv1, &leader_orient);
1458
1459                                                                 // now rotate the point by the transpose from above.
1460                                                                 vm_vec_rotate(&tmpv1, &tmpv2, &rot_trans);
1461
1462                                                                 // convert point back into real-world coordinates
1463                                                                 vm_vec_rotate(&tmpv2, &tmpv1, &leader_transpose);
1464
1465                                                                 // and move origin back to real-world origin.  Object is now at it's correct
1466                                                                 // position.  Note we used the leader's new position, instead of old position.
1467                                                                 vm_vec_add(&objp->pos, &leader->pos, &tmpv2);
1468
1469                                                                 // Now fix the object's orientation to what it should be.
1470                                                                 vm_matrix_x_matrix(&tmp, &objp->orient, &view_physics.last_rotmat);
1471                                                                 vm_orthogonalize_matrix(&tmp);  // safety check
1472                                                                 objp->orient = tmp;
1473
1474                                                         } else {
1475                                                                 vm_vec_add2(&objp->pos, &delta_pos);
1476                                                                 vm_matrix_x_matrix(&tmp, &objp->orient, &view_physics.last_rotmat);
1477                                                                 objp->orient = tmp;
1478                                                         }
1479                                                 }
1480                                                 
1481                                                 objp = GET_NEXT(objp);
1482                                         }
1483
1484                                         objp = GET_FIRST(&obj_used_list);
1485                                         while (objp != END_OF_LIST(&obj_used_list)) {
1486                                                 if (objp->flags & OF_MARKED)
1487                                                         object_moved(objp);
1488                                                 
1489                                                 objp = GET_NEXT(objp);
1490                                         }
1491
1492                                         set_modified();
1493                                 }
1494
1495                                 break;
1496                         
1497                         default:
1498                                 Assert(0);
1499                 }
1500
1501         if (Lookat_mode && query_valid_object()) {
1502                 float dist;
1503
1504                 dist = vm_vec_dist(&view_pos, &Objects[cur_object_index].pos);
1505                 vm_vec_scale_add(&view_pos, &Objects[cur_object_index].pos, &view_orient.fvec, -dist);
1506         }
1507
1508         switch (viewpoint)
1509         {
1510                 case 0:
1511                         eye_pos = view_pos;
1512                         eye_orient = view_orient;
1513                         break;
1514
1515                 case 1:
1516                         eye_pos = Objects[view_obj].pos;
1517                         eye_orient = Objects[view_obj].orient;
1518                         break;
1519
1520                 default:
1521                         Assert(0);
1522         }
1523
1524         maybe_create_new_grid(The_grid, &eye_pos, &eye_orient);
1525
1526         if (Cursor_over != Last_cursor_over) {
1527                 Last_cursor_over = Cursor_over;
1528                 Update_window = 1;
1529         }
1530
1531         // redraw screen if controlled object moved or rotated
1532         if (vm_vec_cmp(&control_pos, &Last_control_pos) || vm_matrix_cmp(&control_orient, &Last_control_orient)) {
1533                 Update_window = 1;
1534                 Last_control_pos = control_pos;
1535                 Last_control_orient = control_orient;
1536         }
1537
1538         // redraw screen if current viewpoint moved or rotated
1539         if (vm_vec_cmp(&eye_pos, &Last_eye_pos) || vm_matrix_cmp(&eye_orient, &Last_eye_orient)) {
1540                 Update_window = 1;
1541                 Last_eye_pos = eye_pos;
1542                 Last_eye_orient = eye_orient;
1543         }
1544 }
1545
1546 void hilight_bitmap()
1547 {
1548         /*
1549         int i;
1550         vertex p[4];
1551
1552         if (Starfield_bitmaps[Cur_bitmap].bitmap_index == -1)  // can't draw if no bitmap
1553                 return;
1554
1555         for (i=0; i<4; i++)
1556         {
1557                 g3_rotate_faraway_vertex(&p[i], &Starfield_bitmaps[Cur_bitmap].points[i]);
1558                 if (p[i].codes & CC_BEHIND)
1559                         return;
1560
1561                 g3_project_vertex(&p[i]);
1562                 if (p[i].flags & PF_OVERFLOW)
1563                         return;
1564         }
1565
1566         gr_set_color(255, 255, 255);
1567         g3_draw_line(&p[0], &p[1]);
1568         g3_draw_line(&p[1], &p[2]);
1569         g3_draw_line(&p[2], &p[3]);
1570         g3_draw_line(&p[3], &p[0]);
1571         */
1572 }
1573
1574 void draw_asteroid_field()
1575 {
1576         int i, j;
1577         vector p[8], ip[8];
1578         vertex v[8], iv[8];
1579
1580         for (i=0; i<1 /*MAX_ASTEROID_FIELDS*/; i++)
1581                 if (Asteroid_field.num_initial_asteroids) {
1582                         p[0].x = p[2].x = p[4].x = p[6].x = Asteroid_field.min_bound.x;
1583                         p[1].x = p[3].x = p[5].x = p[7].x = Asteroid_field.max_bound.x;
1584                         p[0].y = p[1].y = p[4].y = p[5].y = Asteroid_field.min_bound.y;
1585                         p[2].y = p[3].y = p[6].y = p[7].y = Asteroid_field.max_bound.y;
1586                         p[0].z = p[1].z = p[2].z = p[3].z = Asteroid_field.min_bound.z;
1587                         p[4].z = p[5].z = p[6].z = p[7].z = Asteroid_field.max_bound.z;
1588
1589                         for (j=0; j<8; j++)
1590                                 g3_rotate_vertex(&v[j], &p[j]);
1591
1592                         g3_draw_line(&v[0], &v[1]);
1593                         g3_draw_line(&v[2], &v[3]);
1594                         g3_draw_line(&v[4], &v[5]);
1595                         g3_draw_line(&v[6], &v[7]);
1596                         g3_draw_line(&v[0], &v[2]);
1597                         g3_draw_line(&v[1], &v[3]);
1598                         g3_draw_line(&v[4], &v[6]);
1599                         g3_draw_line(&v[5], &v[7]);
1600                         g3_draw_line(&v[0], &v[4]);
1601                         g3_draw_line(&v[1], &v[5]);
1602                         g3_draw_line(&v[2], &v[6]);
1603                         g3_draw_line(&v[3], &v[7]);
1604
1605
1606                         // maybe draw inner box
1607                         if (Asteroid_field.has_inner_bound) {
1608
1609                                 gr_set_color(16, 192, 92);
1610
1611                                 ip[0].x = ip[2].x = ip[4].x = ip[6].x = Asteroid_field.inner_min_bound.x;
1612                                 ip[1].x = ip[3].x = ip[5].x = ip[7].x = Asteroid_field.inner_max_bound.x;
1613                                 ip[0].y = ip[1].y = ip[4].y = ip[5].y = Asteroid_field.inner_min_bound.y;
1614                                 ip[2].y = ip[3].y = ip[6].y = ip[7].y = Asteroid_field.inner_max_bound.y;
1615                                 ip[0].z = ip[1].z = ip[2].z = ip[3].z = Asteroid_field.inner_min_bound.z;
1616                                 ip[4].z = ip[5].z = ip[6].z = ip[7].z = Asteroid_field.inner_max_bound.z;
1617
1618                                 for (j=0; j<8; j++)
1619                                         g3_rotate_vertex(&iv[j], &ip[j]);
1620
1621                                 g3_draw_line(&iv[0], &iv[1]);
1622                                 g3_draw_line(&iv[2], &iv[3]);
1623                                 g3_draw_line(&iv[4], &iv[5]);
1624                                 g3_draw_line(&iv[6], &iv[7]);
1625                                 g3_draw_line(&iv[0], &iv[2]);
1626                                 g3_draw_line(&iv[1], &iv[3]);
1627                                 g3_draw_line(&iv[4], &iv[6]);
1628                                 g3_draw_line(&iv[5], &iv[7]);
1629                                 g3_draw_line(&iv[0], &iv[4]);
1630                                 g3_draw_line(&iv[1], &iv[5]);
1631                                 g3_draw_line(&iv[2], &iv[6]);
1632                                 g3_draw_line(&iv[3], &iv[7]);
1633                         }
1634
1635                 }
1636 }
1637
1638 //      See if object "objnum" obstructs the vector from point p0 to point p1.
1639 //      If so, return true and stuff hit point in *hitpos.
1640 //      If not, return false.
1641 int object_check_collision(object *objp, vector *p0, vector *p1, vector *hitpos)
1642 {
1643         mc_info mc;
1644
1645         if ((objp->type == OBJ_NONE) || (objp->type == OBJ_POINT))
1646                 return 0;
1647
1648         if ((objp->type == OBJ_WAYPOINT) && !Show_waypoints)
1649                 return 0;
1650
1651         if ((objp->type == OBJ_START) && !Show_starts)
1652                 return 0;
1653
1654         if (objp->type == OBJ_SHIP) {
1655                 if (!Show_ships)
1656                         return 0;
1657
1658                 if ((Ships[objp->instance].team == TEAM_FRIENDLY) && !Show_friendly)
1659                         return 0;
1660
1661                 if ((Ships[objp->instance].team == TEAM_HOSTILE) && !Show_hostile)
1662                         return 0;
1663
1664                 if ((Ships[objp->instance].team == TEAM_NEUTRAL) && !Show_neutral)
1665                         return 0;
1666         }
1667
1668         if (objp->flags & OF_HIDDEN)
1669                 return 0;
1670
1671         if ((Show_ship_models || Show_outlines) && (objp->type == OBJ_SHIP))    {
1672                 mc.model_num = Ships[objp->instance].modelnum;                  // Fill in the model to check
1673
1674         } else if ((Show_ship_models || Show_outlines) && (objp->type == OBJ_START))    {
1675                 mc.model_num = Ships[objp->instance].modelnum;                  // Fill in the model to check
1676
1677         } else
1678                 return fvi_ray_sphere(hitpos, p0, p1, &objp->pos, (objp->radius > 0.1f) ? objp->radius : LOLLIPOP_SIZE);
1679
1680         mc.orient = &objp->orient;      // The object's orient
1681         mc.pos = &objp->pos;                    // The object's position
1682         mc.p0 = p0;                                     // Point 1 of ray to check
1683         mc.p1 = p1;                                     // Point 2 of ray to check
1684         mc.flags = MC_CHECK_MODEL | MC_CHECK_RAY;  // flags
1685         model_collide(&mc);
1686         *hitpos = mc.hit_point_world;
1687         if ( mc.num_hits < 1 )  {
1688                 // check shield
1689                 mc.orient = &objp->orient;      // The object's orient
1690                 mc.pos = &objp->pos;                    // The object's position
1691                 mc.p0 = p0;                                     // Point 1 of ray to check
1692                 mc.p1 = p1;                                     // Point 2 of ray to check
1693                 mc.flags = MC_CHECK_SHIELD;     // flags
1694                 model_collide(&mc);
1695                 *hitpos = mc.hit_point_world;
1696         }
1697
1698         return mc.num_hits;
1699 }
1700
1701 // Finds the closest object or waypoint under the mouse cursor and returns
1702 // it's index, or -1 if nothing there.
1703 int select_object(int cx, int cy)
1704 {
1705         int             best = -1;
1706         double  dist, best_dist = 9e99;
1707         vector  p0, p1, v, hitpos;
1708         vertex  vt;
1709         object *ptr;
1710
1711         if (Briefing_dialog) {
1712                 best = Briefing_dialog->check_mouse_hit(cx, cy);
1713                 if (best >= 0)
1714                         return best;
1715         }
1716
1717 /*      gr_reset_clip();
1718         g3_start_frame(0);
1719         g3_set_view_matrix(&eye_pos, &eye_orient, 0.5f);*/
1720
1721         //      Get 3d vector specified by mouse cursor location.
1722         g3_point_to_vec(&v, cx, cy);
1723
1724 //      g3_end_frame();
1725         if (!v.x && !v.y && !v.z)  // zero vector
1726                 return -1;
1727
1728         p0 = view_pos;
1729         vm_vec_scale_add(&p1, &p0, &v, 100.0f);
1730
1731         ptr = GET_FIRST(&obj_used_list);
1732         while (ptr != END_OF_LIST(&obj_used_list))
1733         {
1734                 if (object_check_collision(ptr, &p0, &p1, &hitpos))     {
1735                         hitpos.x = ptr->pos.x - view_pos.x;
1736                         hitpos.y = ptr->pos.y - view_pos.y;
1737                         hitpos.z = ptr->pos.z - view_pos.z;
1738                         dist = hitpos.x * hitpos.x + hitpos.y * hitpos.y + hitpos.z * hitpos.z;
1739                         if (dist < best_dist) {
1740                                 best = OBJ_INDEX(ptr);
1741                                 best_dist = dist;
1742                         }
1743                 }
1744                 
1745                 ptr = GET_NEXT(ptr);
1746         }
1747
1748         if (best >= 0)
1749                 return best;
1750
1751         ptr = GET_FIRST(&obj_used_list);
1752         while (ptr != END_OF_LIST(&obj_used_list))
1753         {
1754                 g3_rotate_vertex(&vt, &ptr->pos);
1755                 if (!(vt.codes & CC_BEHIND))
1756                         if (!(g3_project_vertex(&vt) & PF_OVERFLOW)) {
1757                                 hitpos.x = vt.sx - cx;
1758                                 hitpos.y = vt.sy - cy;
1759                                 dist = hitpos.x * hitpos.x + hitpos.y * hitpos.y;
1760                                 if ((dist < 8) && (dist < best_dist)) {
1761                                         best = OBJ_INDEX(ptr);
1762                                         best_dist = dist;
1763                                 }
1764                         }
1765
1766                 ptr = GET_NEXT(ptr);
1767         }
1768
1769         return best;
1770 }
1771
1772 void render_compass(void)
1773 {
1774         vector v, eye = { 0.0f };
1775         
1776         if (!Show_compass)
1777                 return;
1778
1779         gr_set_clip(gr_screen.max_w - 100, 0, 100, 100);
1780         g3_start_frame(0);   // required !!!
1781         vm_vec_scale_add2(&eye, &eye_orient.fvec, -1.5f);
1782         g3_set_view_matrix(&eye, &eye_orient, 1.0f);
1783
1784         v.x = 1.0f;
1785         v.y = v.z = 0.0f;
1786         if (vm_vec_dotprod(&eye, &v) < 0.0f)
1787                 gr_set_color(159, 20, 20);
1788         else
1789                 gr_set_color(255, 32, 32);
1790         draw_compass_arrow(&v);
1791
1792         v.y = 1.0f;
1793         v.x = v.z = 0.0f;
1794         if (vm_vec_dotprod(&eye, &v) < 0.0f)
1795                 gr_set_color(20, 159, 20);
1796         else
1797                 gr_set_color(32, 255, 32);
1798         draw_compass_arrow(&v);
1799
1800         v.z = 1.0f;
1801         v.x = v.y = 0.0f;
1802         if (vm_vec_dotprod(&eye, &v) < 0.0f)
1803                 gr_set_color(20, 20, 159);
1804         else
1805                 gr_set_color(32, 32, 255);
1806         draw_compass_arrow(&v);
1807
1808         g3_end_frame();
1809 }
1810
1811 void draw_compass_arrow(vector *v0)
1812 {
1813         vector  v1 = { 0.0f };
1814         vertex  tv0, tv1;
1815
1816         g3_rotate_vertex(&tv0, v0);
1817         g3_rotate_vertex(&tv1, &v1);
1818         g3_project_vertex(&tv0);        
1819         g3_project_vertex(&tv1);
1820 //      tv0.sx = (tv0.sx - tv1.sx) * 1 + tv1.sx;
1821 //      tv0.sy = (tv0.sy - tv1.sy) * 1 + tv1.sy;
1822         g3_draw_line(&tv0, &tv1);
1823 }
1824
1825
1826 void inc_mission_time()
1827 {
1828         fix thistime;
1829
1830         thistime = timer_get_fixed_seconds();
1831         if (!lasttime)
1832                 Frametime = F1_0 / 30;
1833         else
1834                 Frametime = thistime - lasttime;
1835
1836         if (Frametime > MAX_FRAMETIME)
1837                 Frametime = MAX_FRAMETIME;
1838
1839         if (Frametime < MIN_FRAMETIME)
1840                 Frametime = MIN_FRAMETIME;
1841
1842         Missiontime += Frametime;
1843         lasttime = thistime;
1844 }
1845