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