]> icculus.org git repositories - taylor/freespace2.git/blob - src/fred2/fredrender.cpp
fix issue with looping audio streams
[taylor/freespace2.git] / src / fred2 / fredrender.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/fred2/FredRender.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Handles rendering the scene in the window for Fred.  Also handles several other
16  * miscellaneous tasks.
17  *
18  * $Log$
19  * Revision 1.3  2002/06/09 04:41:16  relnev
20  * added copyright header
21  *
22  * Revision 1.2  2002/05/07 03:16:44  theoddone33
23  * The Great Newline Fix
24  *
25  * Revision 1.1.1.1  2002/05/03 03:28:08  root
26  * Initial import.
27  *
28  * 
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.
33  * 
34  * 5     3/26/99 4:49p Dave
35  * Made cruisers able to dock with stuff. Made docking points and paths
36  * visible in fred.
37  * 
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.
41  * 
42  * 3     1/27/99 4:09p Andsager
43  * Added highlight to ship subsystems
44  * 
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.
49  * 
50  * 1     10/07/98 3:02p Dave
51  * 
52  * 1     10/07/98 3:00p Dave
53  * 
54  * 162   5/21/98 12:58a Hoffoss
55  * Fixed warnings optimized build turned up.
56  * 
57  * 161   4/11/98 6:53p John
58  * Added first rev of subspace effect.
59  * 
60  * 160   4/07/98 4:17p John
61  * Made Fred be able to move suns.  Made suns actually affect the lighting
62  * in the game.
63  * 
64  * 159   3/21/98 7:36p Lawrance
65  * Move jump nodes to own lib.
66  * 
67  * 158   3/19/98 11:41a Hoffoss
68  * Fixed problems with rendering and reading of flying controls in Fred.
69  * 
70  * 157   3/14/98 5:11p Hoffoss
71  * Changed the starting camera position and orientation for Fred.
72  * 
73  * 156   3/10/98 4:24p Hoffoss
74  * Made object detection under cursor use the object's radius if it has
75  * one.
76  * 
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
82  * global variable.
83  * 
84  * 154   3/10/98 1:41p Sandeep
85  * 
86  * 153   3/09/98 10:56a Hoffoss
87  * Added jump node objects to Fred.
88  * 
89  * 152   3/03/98 11:00a Andsager
90  * Fixed fred bug with control object initialization.
91  * 
92  * 151   2/18/98 6:45p Hoffoss
93  * Added support for lines between icons in briefings for Fred.
94  * 
95  * 150   2/12/98 3:48p Hoffoss
96  * Reduced scaler for extra precision.
97  * 
98  * 149   2/10/98 6:43p Lawrance
99  * Moved asteroid code to a separate lib.
100  * 
101  * 148   2/06/98 3:08p Mike
102  * More asteroid stuff, including resolving conflicts between the two
103  * asteroid_field structs!
104  * 
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.
109  * 
110  * 146   1/16/98 2:22p Hoffoss
111  * Changed rendering colors of objects.
112  * 
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
117  * 
118  * 144   10/30/97 3:30p Hoffoss
119  * Made anti-aliased gridlines an option in Fred.
120  * 
121  * 143   10/29/97 5:13p John
122  * Trying to fix my lighting bugs in Fred.
123  * 
124  * 142   10/03/97 9:48a John
125  * took out alphacolors some grid lines don't draw antialiased.
126  * 
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.
130  * 
131  * 140   9/18/97 9:59a John
132  * fixed bug I caused in model_collide
133  * 
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.
137  * 
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.
141  * 
142  * 137   9/06/97 2:13p Mike
143  * Replace support for TEAM_NEUTRAL
144  * 
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.
148  * 
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.
152  * 
153  * 134   8/19/97 5:46p Hoffoss
154  * Changed font used in Fred, and added display to show current eye
155  * position.
156  * 
157  * 133   8/19/97 11:23a Hoffoss
158  * Fixes to briefing editor icon select code.
159  * 
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.
163  * 
164  * 131   8/16/97 2:02a Hoffoss
165  * Made docked objects move together in Fred.
166  * 
167  * 130   8/14/97 7:01p Hoffoss
168  * Fixed bug with outline rendering while in background bitmap editing
169  * mode.
170  * 
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.
174  * 
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
178  * display.
179  * 
180  * 127   8/12/97 1:55a Hoffoss
181  * Made extensive changes to object reference checking and handling for
182  * object deletion call.
183  * 
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.
187  * 
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.
192  * 
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.
197  * 
198  * 123   7/24/97 10:24a Mike
199  * Restore support for Unknown team
200  * 
201  * 122   7/17/97 1:34p Hoffoss
202  * Fixed Fred to work with physics changes.
203  * 
204  * 121   6/26/97 6:03p Hoffoss
205  * briefing icon selection now has higher priority of selection than other
206  * objects.
207  * 
208  * 120   6/26/97 5:18p Hoffoss
209  * Major rework of briefing editor functionality.
210  * 
211  * 119   6/26/97 4:20p Hoffoss
212  * Changed the behavior of Ctrl-L
213  *
214  * $NoKeywords: $
215  */
216
217 #include "stdafx.h"
218 #include "fred.h"
219 #include "freddoc.h"
220 #include "fredview.h"
221 #include "mainfrm.h"
222
223 #include <stdio.h>
224 #include <stdlib.h>
225 #include <string.h>
226 #include <float.h>
227
228 #include "management.h"
229 #include "vecmat.h"
230 #include "tmapper.h"
231 #include "2d.h"
232 #include "3d.h"
233 #include "model.h"
234 #include "bmpman.h"
235 #include "key.h"
236 #include "physics.h"
237 #include "floating.h"
238 #include "object.h"
239 #include "model.h"
240 #include "palman.h"
241 #include "editor.h"
242 #include "ailocal.h"
243 #include "ship.h"
244 #include "cfile.h"
245 #include "missionparse.h"
246 #include "linklist.h"
247 #include "fvi.h"
248 #include "3dinternal.h"
249 #include "weapon.h"
250 #include "wing.h"
251 #include "fredrender.h"
252 #include "windows.h"
253 #include "starfield.h"
254 #include "timer.h"
255 #include "lighting.h"
256 #include "asteroid.h"
257 #include "jumpnode.h"
258
259 extern float flFrametime;
260 extern subsys_to_render Render_subsys;
261
262 #ifdef _DEBUG
263 #define new DEBUG_NEW
264 #undef THIS_FILE
265 static char THIS_FILE[] = __FILE__;
266 #endif
267
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
272
273 int     Aa_gridlines = 0;
274 int     Fred_outline = 0;
275 int     inited = -1;
276 int     player_start1;
277 int     Editing_mode = 1;
278 int     Control_mode = 0;
279 int     last_x=0, last_y=0;
280 int     Show_grid = 1;
281 int     Show_outlines = 0;
282 int     Show_stars = 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;
288 int     Lookat_mode = 0;
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;
299
300 fix             lasttime = 0;
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 };
304 vector  Grid_center;
305 vector  Constraint = { 1.0f, 0.0f, 1.0f };
306 vector  Anticonstraint = { 0.0f, 1.0f, 0.0f };
307 vector  Tp1, Tp2;  // test points
308 matrix  Grid_gmatrix;
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;
315 CWnd            info_popup;
316
317 static vector Global_light_world = { 0.208758f, -0.688253f, -0.694782f };
318
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();
330
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()
334 {
335         vector f, u, r;
336
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));
341
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);
347
348         The_grid = create_default_grid();
349         maybe_create_new_grid(The_grid, &view_pos, &view_orient, 1);
350 //      vm_set_identity(&view_orient);
351 }
352
353 void level_object(matrix *orient)
354 {
355         vector u;
356
357         u = orient->uvec = The_grid->gmatrix.uvec;
358         if (u.x)  // y-z plane
359         {
360                 orient->fvec.x = orient->rvec.x = 0.0f;
361
362         } else if (u.y) {  // x-z plane
363                 orient->fvec.y = orient->rvec.y = 0.0f;
364
365         } else if (u.z) {  // x-y plane
366                 orient->fvec.z = orient->rvec.z = 0.0f;
367         }
368
369         vm_fix_matrix(orient);
370 }
371
372 void level_controlled()
373 {
374         int cmode, count = 0;
375         object *objp;
376
377         cmode = Control_mode;
378         if ((viewpoint == 1) && !cmode)
379                 cmode = 2;
380
381         switch (cmode) {
382                 case 0:         //      Control the viewer's location and orientation
383                         level_object(&view_orient);
384                         break;
385
386                 case 2:  // Control viewpoint object
387                         level_object(&Objects[view_obj].orient);
388                         object_moved(&Objects[view_obj]);
389                         set_modified();
390                         FREDDoc_ptr->autosave("level object");
391                         break;
392
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);
398                                 
399                                 objp = GET_NEXT(objp);
400                         }
401
402                         objp = GET_FIRST(&obj_used_list);
403                         while (objp != END_OF_LIST(&obj_used_list)) {
404                                 if (objp->flags & OF_MARKED) {
405                                         object_moved(objp);
406                                         count++;
407                                 }
408                                 
409                                 objp = GET_NEXT(objp);
410                         }
411
412                         if (count) {
413                                 if (count > 1)
414                                         FREDDoc_ptr->autosave("level objects");
415                                 else
416                                         FREDDoc_ptr->autosave("level object");
417
418                                 set_modified();
419                         }
420
421                         break;
422         }
423
424         return;
425 }
426
427 void align_vector_to_axis(vector *v)
428 {
429         float x, y, z;
430
431         x = v->x;
432         if (x < 0)
433                 x = -x;
434
435         y = v->y;
436         if (y < 0)
437                 y = -y;
438
439         z = v->z;
440         if (z < 0)
441                 z = -z;
442
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);
446                 else  // positive x
447                         vm_vec_make(v, 1.0f, 0.0f, 0.0f);
448
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);
452                 else  // positive y
453                         vm_vec_make(v, 0.0f, 1.0f, 0.0f);
454
455         } else {  // z axis
456                 if (v->z < 0)  // negative z
457                         vm_vec_make(v, 0.0f, 0.0f, -1.0f);
458                 else  // positive z
459                         vm_vec_make(v, 0.0f, 0.0f, 1.0f);
460         }
461 }
462
463 void verticalize_object(matrix *orient)
464 {
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.
469 }
470
471 void verticalize_controlled()
472 {
473         int cmode, count = 0;
474         object *objp;
475
476         cmode = Control_mode;
477         if ((viewpoint == 1) && !cmode)
478                 cmode = 2;
479
480         switch (cmode) {
481                 case 0:         //      Control the viewer's location and orientation
482                         verticalize_object(&view_orient);
483                         break;
484
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");
489                         set_modified();
490                         break;
491
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);
497                                 
498                                 objp = GET_NEXT(objp);
499                         }
500
501                         objp = GET_FIRST(&obj_used_list);
502                         while (objp != END_OF_LIST(&obj_used_list)) {
503                                 if (objp->flags & OF_MARKED) {
504                                         object_moved(objp);
505                                         count++;
506                                 }
507                                 
508                                 objp = GET_NEXT(objp);
509                         }
510
511                         if (count) {
512                                 if (count > 1)
513                                         FREDDoc_ptr->autosave("align objects");
514                                 else
515                                         FREDDoc_ptr->autosave("align object");
516
517                                 set_modified();
518                         }
519
520                         break;
521         }
522
523         return;
524 }
525
526 void move_mouse( int btn, int mdx, int mdy )
527 {
528         int dx, dy;
529
530         dx = mdx - last_x;
531         dy = mdy - last_y;
532         last_x = mdx;
533         last_y = mdy;
534
535         if ( btn & 1 )  {
536                 matrix tempm, mousem;
537
538                 if ( dx || dy ) {
539                         vm_trackball( dx, dy, &mousem );
540                         vm_matrix_x_matrix(&tempm, &trackball_orient, &mousem);
541                         trackball_orient = tempm;
542                         view_orient = trackball_orient;
543                 }
544         }
545
546         if ( btn & 2 )  {
547                 my_pos.z += (float)dy;
548         }
549 }
550
551 ///////////////////////////////////////////////////
552 void process_system_keys(int key)
553 {
554 //      mprintf(("Key = %d\n", key));
555         switch (key) {
556
557         case KEY_LAPOSTRO:
558                 CFREDView::GetView()->cycle_constraint();
559                 break;
560
561         case KEY_R:  // for some stupid reason, an accelerator for 'R' doesn't work.
562                 Editing_mode = 2;
563                 break;
564
565         case KEY_SPACEBAR:
566                 Selection_lock = !Selection_lock;
567                 break;
568
569         case KEY_ESC:
570                 if (button_down)
571                         cancel_drag();
572
573                 break;
574         }
575 }
576
577 void render_waypoints(void)
578 {
579         int i, j;
580         vertex v;
581         waypoint_list *ptr;
582
583         for (i=0; i<Num_waypoint_lists; i++)
584         {
585                 ptr = &Waypoint_lists[i];
586                 for (j=0; j<ptr->count; j++)
587                 {
588                         g3_rotate_vertex(&v, &ptr->waypoints[j]);
589                         if (!(v.codes & CC_BEHIND))
590                                 if (!(g3_project_vertex(&v) & PF_OVERFLOW))
591                                 {
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);
596                                         else
597                                                 gr_set_color(160, 96, 0);
598
599                                         g3_draw_sphere(&v, LOLLIPOP_SIZE);
600                                         if (j)
601                                                 gr_set_color(0, 0, 0);
602                                         else
603                                                 gr_set_color(160, 96, 0);
604
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);
608                                 }
609                 }
610
611                 for (j=0; j<ptr->count; j++)
612                         render_model_x(&ptr->waypoints[j], The_grid, 1);
613
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]);
617         }
618 }
619
620 // --------------------------------------------------------------------------------
621 // get_subsystem_world_pos2() returns the world position for a given subobject on a ship
622 //
623
624 vector* get_subsystem_world_pos2(object* parent_obj, ship_subsys* subsys, vector* world_pos)
625 {
626         if (subsys == NULL) {
627                 *world_pos = parent_obj->pos;
628                 return world_pos;
629         }
630         
631         vm_vec_unrotate(world_pos, &subsys->system_info->pnt, &parent_obj->orient);
632         vm_vec_add2(world_pos, &parent_obj->pos);
633
634         return world_pos;
635 }
636
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)
639 {
640         if (subsys != NULL) {
641                 vertex subobj_vertex;
642                 vector  subobj_pos;
643
644                 get_subsystem_world_pos2(ship_obj, subsys, &subobj_pos);
645
646                 g3_rotate_vertex(&subobj_vertex, &subobj_pos);
647
648                 g3_project_vertex(&subobj_vertex);
649                 if (subobj_vertex.flags & PF_OVERFLOW)  // if overflow, no point in drawing brackets
650                         return 0;
651
652                 int bound_rc;
653
654                 bound_rc = subobj_find_2d_bound(subsys->system_info->radius, &ship_obj->orient, &subobj_pos, x1, y1, x2, y2);
655                 if ( bound_rc != 0 )
656                         return 0;
657
658                 return 1;
659         }
660
661         return 0;
662 }
663
664 void cancel_display_active_ship_subsystem()
665 {
666         Render_subsys.do_render = false;
667         Render_subsys.ship_obj = NULL;
668         Render_subsys.cur_subsys = NULL;
669 }
670
671 void display_active_ship_subsystem()
672 {
673         if (cur_object_index != -1) {
674                 if (Objects[cur_object_index].type == OBJ_SHIP) {
675
676                         object *objp = &Objects[cur_object_index];
677                         int x1, y1, x2, y2;
678                         char buf[256];
679
680                         // switching to a new ship, so reset
681                         if (objp != Render_subsys.ship_obj) {
682                                 cancel_display_active_ship_subsystem();
683                                 return;
684                         }
685
686                         if (Render_subsys.do_render) {
687
688                                 // get subsys name
689                                 strcpy(buf, Render_subsys.cur_subsys->system_info->subobj_name);
690
691                                 // get bounding box
692                                 if ( get_subsys_bounding_rect(objp, Render_subsys.cur_subsys, &x1, &x2, &y1, &y2) ) {
693
694                                         // set color
695                                         gr_set_color(255, 32, 32);
696
697                                         // draw box
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);
702
703                                         // draw text
704                                         gr_string_win( (x1+x2)/2,  y2 + 10, buf);
705                                 }
706                         }
707                 }
708         } else {
709                 cancel_display_active_ship_subsystem();
710         }
711 }
712
713 void render_models(void)
714 {
715         render_count = 0;
716         obj_render_all(render_one_model);
717         if (Briefing_dialog)
718                 Briefing_dialog->batch_render();
719 }
720
721 void render_one_model(object *objp)
722 {
723         int j, z;
724         object *o2;
725
726         SDL_assert(objp->type != OBJ_NONE);
727
728         if ( objp->type == OBJ_JUMP_NODE ) {
729                 return;
730         }
731
732         if ((objp->type == OBJ_WAYPOINT) && !Show_waypoints)
733                 return;
734
735         if ((objp->type == OBJ_START) && !Show_starts)
736                 return;
737
738         if (objp->type == OBJ_SHIP) {
739                 if (!Show_ships)
740                         return;
741
742                 if ((Ships[objp->instance].team == TEAM_FRIENDLY) && !Show_friendly)
743                         return;
744
745                 if ((Ships[objp->instance].team == TEAM_HOSTILE) && !Show_hostile)
746                         return;
747
748                 if ((Ships[objp->instance].team == TEAM_NEUTRAL) && !Show_neutral)
749                         return;
750         }
751
752         if (objp->flags & OF_HIDDEN)
753                 return;
754
755         rendering_order[render_count] = OBJ_INDEX(objp);
756         Fred_outline = 0;
757         if ((OBJ_INDEX(objp) == cur_object_index) && !Bg_bitmap_dialog)
758                 Fred_outline = 0xffffff;
759
760         else if ((objp->flags & OF_MARKED) && !Bg_bitmap_dialog)  // is it a marked object?
761                 Fred_outline = 0x9fff00;
762
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;
769                         default:
770                                 Fred_outline = 0x7f007f;        break;
771                 }
772
773         } else if ((objp->type == OBJ_START) && Show_outlines) {
774                 Fred_outline = 0x007f00;
775
776         } else
777                 Fred_outline = 0;
778
779         // build flags
780         if ((Show_ship_models || Show_outlines) && ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START))){
781                 if (Show_ship_models){
782                         j = MR_NORMAL;
783                 } else {
784                         j = MR_NO_POLYS;
785                 }
786                 
787                 if(Show_dock_points){
788                         j |= MR_BAY_PATHS;      
789                 }
790
791                 if(Show_paths_fred){
792                         j |= MR_SHOW_PATHS;
793                 }
794
795                 z = objp->instance;
796
797                 model_clear_instance( Ships[z].modelnum );
798
799 //              if (!viewpoint || OBJ_INDEX(objp) != cur_object_index)
800                 {
801                         if (Fred_outline)       {
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);
804                         } else {
805                                 model_render(Ships[z].modelnum, &objp->orient, &objp->pos, j);
806                         }
807                 }
808         
809         } else {
810                 int r = 0, g = 0, b = 0;
811
812                 if (objp->type == OBJ_SHIP)
813                 {
814                         if (!Show_ships)
815                                 return;
816
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;
823                         }
824
825                 } else if (objp->type == OBJ_START) {
826                         r = 0;  g = 127;        b = 0;
827
828                 } else if (objp->type == OBJ_WAYPOINT) {
829                         r = 96; g = 0;  b = 112;
830
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);
835                                 goto skip;
836                         }
837
838                         r = 196;        g = 32; b = 196;
839
840                 } else
841                         SDL_assert(0);
842
843                 if (Fred_outline)
844                         draw_orient_sphere2(Fred_outline, objp, r, g, b);
845                 else
846                         draw_orient_sphere(objp, r, g, b);
847         }
848
849 skip:
850         if (objp->type == OBJ_WAYPOINT)
851                 for (j=0; j<render_count; j++)
852                 {
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);
857                 }
858
859         render_model_x(&objp->pos, The_grid);
860         render_count++;
861 }
862
863 void display_distances()
864 {
865         char buf[20];
866         object *objp, *o2;
867         vector pos;
868         vertex v;
869
870         gr_set_color(255, 0, 0);
871         objp = GET_FIRST(&obj_used_list);
872         while (objp != END_OF_LIST(&obj_used_list))
873         {
874                 if (objp->flags & OF_MARKED)
875                 {
876                         o2 = GET_NEXT(objp);
877                         while (o2 != END_OF_LIST(&obj_used_list))
878                         {
879                                 if (o2->flags & OF_MARKED)
880                                 {
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);
888                                                 }
889                                 }
890
891                                 o2 = GET_NEXT(o2);
892                         }
893                 }
894
895                 objp = GET_NEXT(objp);
896         }
897 }
898
899 void display_ship_info()
900 {
901         char buf[512], pos[80];
902         int render = 1;
903         object *objp;
904         vertex  v;
905
906         objp = GET_FIRST(&obj_used_list);
907         while (objp != END_OF_LIST(&obj_used_list))     {
908                 SDL_assert(objp->type != OBJ_NONE);
909                 Fred_outline = 0;
910                 render = 1;
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;
915                 else
916                         Fred_outline = 0;
917
918                 if ((objp->type == OBJ_WAYPOINT) && !Show_waypoints)
919                         render = 0;
920
921                 if ((objp->type == OBJ_START) && !Show_starts)
922                         render = 0;
923                 
924                 if (objp->type == OBJ_SHIP) {
925                         if (!Show_ships)
926                                 render = 0;
927
928                         if ((Ships[objp->instance].team == TEAM_FRIENDLY) && !Show_friendly)
929                                 render = 0;
930
931                         if ((Ships[objp->instance].team == TEAM_HOSTILE) && !Show_hostile)
932                                 render = 0;
933
934                         if ((Ships[objp->instance].team == TEAM_NEUTRAL) && !Show_neutral)
935                                 render = 0;
936                 }
937
938                 if (objp->flags & OF_HIDDEN)
939                         render = 0;
940                 
941                 g3_rotate_vertex(&v, &objp->pos);
942                 if (!(v.codes & CC_BEHIND) && render)
943                         if (!(g3_project_vertex(&v) & PF_OVERFLOW))     {
944                                 *buf = 0;
945                                 if (Show_ship_info)
946                                 {
947                                         if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) {
948                                                 ship *shipp;
949                                                 int ship_type;
950
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);
955
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);
960
961                                         } else if (objp->type == OBJ_POINT) {
962                                                 if (objp->instance == BRIEFING_LOOKAT_POINT_ID)
963                                                         strcpy(buf, "Camera lookat point");
964                                                 else
965                                                         strcpy(buf, "Briefing icon");
966
967                                         } else if (objp->type == OBJ_JUMP_NODE) {
968                                                 strcpy(buf, "Jump Node");
969                                         } else
970                                                 SDL_assert(0);
971                                 }
972
973                                 if (Show_coordinates)
974                                 {
975                                         sprintf(pos, "( %.0f , %.0f , %.0f )", objp->pos.x, objp->pos.y, objp->pos.z);
976                                         if (*buf)
977                                                 strcat(buf, "\n");
978
979                                         strcat(buf, pos);
980                                 }
981
982                                 if (*buf)
983                                 {
984                                         if (Fred_outline)
985                                                 gr_set_color(Fred_outline >> 16, (Fred_outline >> 8) & 0xff, Fred_outline & 0xff);
986                                         else
987                                                 gr_set_color(160, 160, 160);
988
989                                         gr_string_win((int) v.sx, (int) v.sy, buf);
990                                 }
991                         }
992
993                 objp = GET_NEXT(objp);
994         }
995 }
996
997 void draw_orient_sphere(object *obj, int r, int g, int b)
998 {
999         int             flag = 0;
1000         vertex  v;
1001         vector  v1, v2;
1002         float           size;
1003
1004         size = fl_sqrt(vm_vec_dist(&eye_pos, &obj->pos) / 20.0f);
1005         if (size < LOLLIPOP_SIZE)
1006                 size = LOLLIPOP_SIZE;
1007
1008         if ((obj->type != OBJ_WAYPOINT) && (obj->type != OBJ_POINT))
1009         {
1010                 flag = (vm_vec_dotprod(&eye_orient.fvec, &obj->orient.fvec) < 0.0f);
1011                 v1 = v2 = obj->pos;
1012                 vm_vec_scale_add2(&v1, &obj->orient.fvec, size);
1013                 vm_vec_scale_add2(&v2, &obj->orient.fvec, size * 1.5f);
1014
1015                 if (!flag)      {
1016                         gr_set_color(192, 192, 192);
1017                         rpd_line(&v1, &v2);
1018                 }
1019         }
1020
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);
1026
1027         if (flag)       {
1028                 gr_set_color(192, 192, 192);
1029                 rpd_line(&v1, &v2);
1030         }
1031 }
1032
1033 void draw_orient_sphere2(int col, object *obj, int r, int g, int b)
1034 {
1035         int             flag = 0;
1036         vertex  v;
1037         vector  v1, v2;
1038         float           size;
1039
1040         size = fl_sqrt(vm_vec_dist(&eye_pos, &obj->pos) / 20.0f);
1041         if (size < LOLLIPOP_SIZE)
1042                 size = LOLLIPOP_SIZE;
1043
1044         if ((obj->type != OBJ_WAYPOINT) && (obj->type != OBJ_POINT))
1045         {
1046                 flag = (vm_vec_dotprod(&eye_orient.fvec, &obj->orient.fvec) < 0.0f);
1047
1048                 v1 = v2 = obj->pos;
1049                 vm_vec_scale_add2(&v1, &obj->orient.fvec, size);
1050                 vm_vec_scale_add2(&v2, &obj->orient.fvec, size * 1.5f);
1051
1052                 if (!flag)      {
1053                         gr_set_color(192, 192, 192);
1054                         rpd_line(&v1, &v2);
1055                 }
1056         }
1057
1058         g3_rotate_vertex(&v, &obj->pos);
1059         if (!(v.codes & CC_BEHIND))
1060                 if (!(g3_project_vertex(&v) & PF_OVERFLOW))
1061                 {
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);
1066                 }
1067
1068         if (flag)       {
1069                 gr_set_color(192, 192, 192);
1070                 rpd_line(&v1, &v2);
1071         }
1072 }
1073
1074 void render_model_x(vector *pos, grid *gridp, int col_scheme)
1075 {
1076         vector  gpos;   //      Location of point on grid.
1077         vector  tpos;
1078         float   dxz;
1079         plane   tplane;
1080         vector  *gv;
1081
1082         if (!Show_grid_positions)
1083                 return;
1084
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;
1089
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);
1095         else
1096                 gr_set_color(192, 192, 192);
1097
1098
1099         rpd_line(&gpos, pos);   //      Line from grid to object center.
1100
1101         tpos = gpos;
1102
1103         vm_vec_scale_add2(&gpos, &gridp->gmatrix.rvec, -dxz/2);
1104         vm_vec_scale_add2(&gpos, &gridp->gmatrix.fvec, -dxz/2);
1105         
1106         vm_vec_scale_add2(&tpos, &gridp->gmatrix.rvec, dxz/2);
1107         vm_vec_scale_add2(&tpos, &gridp->gmatrix.fvec, dxz/2);
1108         
1109         rpd_line(&gpos, &tpos);
1110
1111         vm_vec_scale_add2(&gpos, &gridp->gmatrix.rvec, dxz);
1112         vm_vec_scale_add2(&tpos, &gridp->gmatrix.rvec, -dxz);
1113
1114         rpd_line(&gpos, &tpos);
1115 }
1116
1117 void render_active_rect(void)
1118 {
1119         if (box_marking) {
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);
1125         }
1126 }
1127
1128
1129 void process_movement_keys(int key, vector *mvec, angles *angs)
1130 {
1131         int     raw_key;
1132
1133         mvec->x = 0.0f;
1134         mvec->y = 0.0f;
1135         mvec->z = 0.0f;
1136         angs->p = 0.0f;
1137         angs->b = 0.0f;
1138         angs->h = 0.0f;
1139
1140         raw_key = key & 0xff;
1141
1142         switch (raw_key) {
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;
1155
1156         }
1157
1158         if (key & KEY_SHIFTED) {
1159                 vm_vec_scale(mvec, 5.0f);
1160                 angs->p *= 5.0f;
1161                 angs->b *= 5.0f;
1162                 angs->h *= 5.0f;
1163         }
1164 }
1165
1166 void process_controls(vector *pos, matrix *orient, float frametime, int key, int mode)
1167 {
1168         if (Flying_controls_mode)       {
1169                 grid_read_camera_controls(&view_controls, frametime);
1170
1171                 if (key_get_shift_status())
1172                         memset(&view_controls, 0, sizeof(control_info));
1173
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)))
1180                                 Update_window = 1;
1181
1182                 flFrametime = frametime;
1183                 physics_read_flying_controls(orient, &view_physics, &view_controls, flFrametime);
1184                 if (mode)
1185                         physics_sim_editor(pos, orient, &view_physics, frametime);
1186                 else
1187                         physics_sim(pos, orient, &view_physics, frametime);
1188
1189         } else {
1190                 vector          movement_vec, rel_movement_vec;
1191                 angles          rotangs;
1192                 matrix          newmat, rotmat;
1193
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);
1197
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);
1202                 *orient = newmat;
1203                 if (rotangs.h && Universal_heading)
1204                         vm_transpose_matrix(orient);
1205         }
1206 }
1207
1208 int Fred_grid_colors_inited = 0;
1209 color Fred_grid_bright, Fred_grid_dark, Fred_grid_bright_aa, Fred_grid_dark_aa;
1210
1211 //      Renders a grid defined in a grid struct
1212 void fred_render_grid(grid *gridp)
1213 {
1214         int     i, ncols, nrows;
1215
1216         if ( !Fred_grid_colors_inited ) {
1217                 Fred_grid_colors_inited = 1;
1218
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 );
1223         }
1224
1225         ncols = gridp->ncols;
1226         nrows = gridp->nrows;
1227         if (double_fine_gridlines) {
1228                 ncols *= 2;
1229                 nrows *= 2;
1230         }
1231
1232         if (Aa_gridlines)
1233                 gr_set_color_fast(&Fred_grid_dark_aa);
1234         else
1235                 gr_set_color_fast(&Fred_grid_dark);
1236
1237         //      Draw the column lines.
1238         for (i=0; i<=ncols; i++)
1239                 rpd_line(&gridp->gpoints1[i], &gridp->gpoints2[i]);
1240
1241         //      Draw the row lines.
1242         for (i=0; i<=nrows; i++)
1243                 rpd_line(&gridp->gpoints3[i], &gridp->gpoints4[i]);
1244
1245         ncols = gridp->ncols / 2;
1246         nrows = gridp->nrows / 2;
1247
1248         // now draw the larger, brighter gridlines that is x10 the scale of smaller one.
1249         if (Aa_gridlines)
1250                 gr_set_color_fast(&Fred_grid_bright_aa);
1251         else
1252                 gr_set_color_fast(&Fred_grid_bright);
1253         
1254         for (i=0; i<=ncols; i++)
1255                 rpd_line(&gridp->gpoints5[i], &gridp->gpoints6[i]);
1256
1257         for (i=0; i<=nrows; i++)
1258                 rpd_line(&gridp->gpoints7[i], &gridp->gpoints8[i]);
1259 }
1260
1261 void render_frame()
1262 {
1263         char buf[256];
1264         int x, y, w, h, inst;
1265         vector pos;
1266         vertex v;
1267         angles a;
1268
1269         g3_end_frame();
1270
1271         gr_reset_clip();
1272         gr_clear();
1273
1274         if (Briefing_dialog) {
1275                 CRect rect;
1276
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;
1283
1284                 } else {
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);
1287
1288                         } else {  // Fred is wider than briefing window
1289                                 True_rw = (int) ((float) BRIEF_GRID_W * (float) True_rh / (float) BRIEF_GRID_H);
1290                         }
1291                 }
1292
1293                 g3_start_frame(0);
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);
1297                 g3_end_frame();
1298                 gr_set_clip(0, 0, True_rw, True_rh);
1299         }
1300
1301         g3_start_frame(1);              // 1 means use zbuffering
1302         gr_set_font(Fred_font);
1303         light_reset();
1304
1305         g3_set_view_matrix(&eye_pos, &eye_orient, 0.5f);
1306         Viewer_pos = eye_pos;  // for starfield code
1307         
1308         if ( Bg_bitmap_dialog ) {
1309                 stars_draw( Show_stars, 1, Show_stars, 0 );
1310         } else {
1311                 stars_draw( Show_stars, Show_stars, Show_stars, 0 );
1312         }
1313
1314         if (Show_horizon) {
1315                 gr_set_color(128, 128, 64);
1316                 g3_draw_horizon_line();
1317         }
1318
1319         if (Show_asteroid_field) {
1320                 gr_set_color(192, 96, 16);
1321                 draw_asteroid_field();
1322         }
1323
1324         if (Show_grid)
1325                 fred_render_grid(The_grid);
1326         if (Bg_bitmap_dialog)
1327                 hilight_bitmap();
1328
1329         gr_set_color(0, 0, 64);
1330         render_models();
1331         if (Show_distances)
1332                 display_distances();
1333
1334         display_ship_info();
1335         display_active_ship_subsystem();
1336         render_active_rect();
1337
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);
1346
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);
1350
1351                 } else if (Objects[Cursor_over].type == OBJ_POINT) {
1352                         sprintf(buf, "Briefing icon\n( %.1f , %.1f , %.1f )", pos.x, pos.y, pos.z);
1353
1354                 } else
1355                         sprintf(buf, "( %.1f , %.1f , %.1f )", pos.x, pos.y, pos.z);
1356
1357                 g3_rotate_vertex(&v, &pos);
1358                 if (!(v.codes & CC_BEHIND))
1359                         if (!(g3_project_vertex(&v) & PF_OVERFLOW))     {
1360                                 x = (int) v.sx;
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);
1370
1371                                 gr_set_color(0, 0, 0);
1372                                 gr_string_win(x, y, buf);
1373                         }
1374         }
1375
1376         gr_set_color(0, 160, 0);
1377         jumpnode_render_all();
1378
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);
1383
1384         g3_end_frame();
1385         render_compass();
1386         gr_reset_clip();
1387         if (Briefing_dialog)
1388                 gr_set_clip(0, 0, True_rw, True_rh);
1389
1390         g3_start_frame(0);
1391         g3_set_view_matrix(&eye_pos, &eye_orient, 0.5f);
1392 }
1393
1394 void game_do_frame()
1395 {
1396         int key, cmode;
1397         vector viewer_position, control_pos;
1398         object *objp;
1399         matrix control_orient;
1400
1401         inc_mission_time();
1402
1403         viewer_position = my_orient.fvec;
1404         vm_vec_scale(&viewer_position,my_pos.z);
1405
1406         if ((viewpoint == 1) && !query_valid_object(view_obj))
1407                 viewpoint = 0;
1408
1409         key = key_inkey();
1410         process_system_keys(key);
1411         cmode = Control_mode;
1412         if ((viewpoint == 1) && !cmode)
1413                 cmode = 2;
1414
1415         control_pos = Last_control_pos;
1416         control_orient = Last_control_orient;
1417
1418 //      if ((key & KEY_MASK) == key)  // unmodified
1419                 switch (cmode) {
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;
1424                                 break;
1425
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;
1431                                 break;
1432
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;
1437                                         object *leader;
1438                                         
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);
1443
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;
1448
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))) {
1453                                                         if (Group_rotate) {
1454                                                                 matrix rot_trans;
1455                                                                 vector tmpv1, tmpv2;
1456
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);
1460
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);
1465
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);
1469
1470                                                                 // now rotate the point by the transpose from above.
1471                                                                 vm_vec_rotate(&tmpv1, &tmpv2, &rot_trans);
1472
1473                                                                 // convert point back into real-world coordinates
1474                                                                 vm_vec_rotate(&tmpv2, &tmpv1, &leader_transpose);
1475
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);
1479
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
1483                                                                 objp->orient = tmp;
1484
1485                                                         } else {
1486                                                                 vm_vec_add2(&objp->pos, &delta_pos);
1487                                                                 vm_matrix_x_matrix(&tmp, &objp->orient, &view_physics.last_rotmat);
1488                                                                 objp->orient = tmp;
1489                                                         }
1490                                                 }
1491                                                 
1492                                                 objp = GET_NEXT(objp);
1493                                         }
1494
1495                                         objp = GET_FIRST(&obj_used_list);
1496                                         while (objp != END_OF_LIST(&obj_used_list)) {
1497                                                 if (objp->flags & OF_MARKED)
1498                                                         object_moved(objp);
1499                                                 
1500                                                 objp = GET_NEXT(objp);
1501                                         }
1502
1503                                         set_modified();
1504                                 }
1505
1506                                 break;
1507                         
1508                         default:
1509                                 SDL_assert(0);
1510                 }
1511
1512         if (Lookat_mode && query_valid_object()) {
1513                 float dist;
1514
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);
1517         }
1518
1519         switch (viewpoint)
1520         {
1521                 case 0:
1522                         eye_pos = view_pos;
1523                         eye_orient = view_orient;
1524                         break;
1525
1526                 case 1:
1527                         eye_pos = Objects[view_obj].pos;
1528                         eye_orient = Objects[view_obj].orient;
1529                         break;
1530
1531                 default:
1532                         SDL_assert(0);
1533         }
1534
1535         maybe_create_new_grid(The_grid, &eye_pos, &eye_orient);
1536
1537         if (Cursor_over != Last_cursor_over) {
1538                 Last_cursor_over = Cursor_over;
1539                 Update_window = 1;
1540         }
1541
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)) {
1544                 Update_window = 1;
1545                 Last_control_pos = control_pos;
1546                 Last_control_orient = control_orient;
1547         }
1548
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)) {
1551                 Update_window = 1;
1552                 Last_eye_pos = eye_pos;
1553                 Last_eye_orient = eye_orient;
1554         }
1555 }
1556
1557 void hilight_bitmap()
1558 {
1559         /*
1560         int i;
1561         vertex p[4];
1562
1563         if (Starfield_bitmaps[Cur_bitmap].bitmap_index == -1)  // can't draw if no bitmap
1564                 return;
1565
1566         for (i=0; i<4; i++)
1567         {
1568                 g3_rotate_faraway_vertex(&p[i], &Starfield_bitmaps[Cur_bitmap].points[i]);
1569                 if (p[i].codes & CC_BEHIND)
1570                         return;
1571
1572                 g3_project_vertex(&p[i]);
1573                 if (p[i].flags & PF_OVERFLOW)
1574                         return;
1575         }
1576
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]);
1582         */
1583 }
1584
1585 void draw_asteroid_field()
1586 {
1587         int i, j;
1588         vector p[8], ip[8];
1589         vertex v[8], iv[8];
1590
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;
1599
1600                         for (j=0; j<8; j++)
1601                                 g3_rotate_vertex(&v[j], &p[j]);
1602
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]);
1615
1616
1617                         // maybe draw inner box
1618                         if (Asteroid_field.has_inner_bound) {
1619
1620                                 gr_set_color(16, 192, 92);
1621
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;
1628
1629                                 for (j=0; j<8; j++)
1630                                         g3_rotate_vertex(&iv[j], &ip[j]);
1631
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]);
1644                         }
1645
1646                 }
1647 }
1648
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)
1653 {
1654         mc_info mc;
1655
1656         if ((objp->type == OBJ_NONE) || (objp->type == OBJ_POINT))
1657                 return 0;
1658
1659         if ((objp->type == OBJ_WAYPOINT) && !Show_waypoints)
1660                 return 0;
1661
1662         if ((objp->type == OBJ_START) && !Show_starts)
1663                 return 0;
1664
1665         if (objp->type == OBJ_SHIP) {
1666                 if (!Show_ships)
1667                         return 0;
1668
1669                 if ((Ships[objp->instance].team == TEAM_FRIENDLY) && !Show_friendly)
1670                         return 0;
1671
1672                 if ((Ships[objp->instance].team == TEAM_HOSTILE) && !Show_hostile)
1673                         return 0;
1674
1675                 if ((Ships[objp->instance].team == TEAM_NEUTRAL) && !Show_neutral)
1676                         return 0;
1677         }
1678
1679         if (objp->flags & OF_HIDDEN)
1680                 return 0;
1681
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
1684
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
1687
1688         } else
1689                 return fvi_ray_sphere(hitpos, p0, p1, &objp->pos, (objp->radius > 0.1f) ? objp->radius : LOLLIPOP_SIZE);
1690
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
1696         model_collide(&mc);
1697         *hitpos = mc.hit_point_world;
1698         if ( mc.num_hits < 1 )  {
1699                 // check shield
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
1705                 model_collide(&mc);
1706                 *hitpos = mc.hit_point_world;
1707         }
1708
1709         return mc.num_hits;
1710 }
1711
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)
1715 {
1716         int             best = -1;
1717         double  dist, best_dist = 9e99;
1718         vector  p0, p1, v, hitpos;
1719         vertex  vt;
1720         object *ptr;
1721
1722         if (Briefing_dialog) {
1723                 best = Briefing_dialog->check_mouse_hit(cx, cy);
1724                 if (best >= 0)
1725                         return best;
1726         }
1727
1728 /*      gr_reset_clip();
1729         g3_start_frame(0);
1730         g3_set_view_matrix(&eye_pos, &eye_orient, 0.5f);*/
1731
1732         //      Get 3d vector specified by mouse cursor location.
1733         g3_point_to_vec(&v, cx, cy);
1734
1735 //      g3_end_frame();
1736         if (!v.x && !v.y && !v.z)  // zero vector
1737                 return -1;
1738
1739         p0 = view_pos;
1740         vm_vec_scale_add(&p1, &p0, &v, 100.0f);
1741
1742         ptr = GET_FIRST(&obj_used_list);
1743         while (ptr != END_OF_LIST(&obj_used_list))
1744         {
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);
1752                                 best_dist = dist;
1753                         }
1754                 }
1755                 
1756                 ptr = GET_NEXT(ptr);
1757         }
1758
1759         if (best >= 0)
1760                 return best;
1761
1762         ptr = GET_FIRST(&obj_used_list);
1763         while (ptr != END_OF_LIST(&obj_used_list))
1764         {
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);
1773                                         best_dist = dist;
1774                                 }
1775                         }
1776
1777                 ptr = GET_NEXT(ptr);
1778         }
1779
1780         return best;
1781 }
1782
1783 void render_compass(void)
1784 {
1785         vector v, eye = { 0.0f };
1786         
1787         if (!Show_compass)
1788                 return;
1789
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);
1794
1795         v.x = 1.0f;
1796         v.y = v.z = 0.0f;
1797         if (vm_vec_dotprod(&eye, &v) < 0.0f)
1798                 gr_set_color(159, 20, 20);
1799         else
1800                 gr_set_color(255, 32, 32);
1801         draw_compass_arrow(&v);
1802
1803         v.y = 1.0f;
1804         v.x = v.z = 0.0f;
1805         if (vm_vec_dotprod(&eye, &v) < 0.0f)
1806                 gr_set_color(20, 159, 20);
1807         else
1808                 gr_set_color(32, 255, 32);
1809         draw_compass_arrow(&v);
1810
1811         v.z = 1.0f;
1812         v.x = v.y = 0.0f;
1813         if (vm_vec_dotprod(&eye, &v) < 0.0f)
1814                 gr_set_color(20, 20, 159);
1815         else
1816                 gr_set_color(32, 32, 255);
1817         draw_compass_arrow(&v);
1818
1819         g3_end_frame();
1820 }
1821
1822 void draw_compass_arrow(vector *v0)
1823 {
1824         vector  v1 = { 0.0f };
1825         vertex  tv0, tv1;
1826
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);
1834 }
1835
1836
1837 void inc_mission_time()
1838 {
1839         fix thistime;
1840
1841         thistime = timer_get_fixed_seconds();
1842         if (!lasttime)
1843                 Frametime = F1_0 / 30;
1844         else
1845                 Frametime = thistime - lasttime;
1846
1847         if (Frametime > MAX_FRAMETIME)
1848                 Frametime = MAX_FRAMETIME;
1849
1850         if (Frametime < MIN_FRAMETIME)
1851                 Frametime = MIN_FRAMETIME;
1852
1853         Missiontime += Frametime;
1854         lasttime = thistime;
1855 }
1856