]> icculus.org git repositories - btb/d2x.git/blob - main/gamerend.c
formatting
[btb/d2x.git] / main / gamerend.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  *
16  * Stuff for rendering the HUD
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <conf.h>
22 #endif
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27
28 #include "inferno.h"
29 #include "error.h"
30 #include "mono.h"
31 #include "gr.h"
32 #include "vid.h"
33 #include "maths.h"
34 #ifdef OGL
35 #include "ogl_init.h"
36 #endif
37
38
39 extern fix Cruise_speed;
40 extern int LinearSVGABuffer;
41 extern cvar_t r_framerate;
42
43
44 #ifndef NDEBUG
45 extern int Debug_pause; // John's debugging pause system
46 #endif
47
48 #ifndef RELEASE
49 extern int Saving_movie_frames;
50 #else
51 #define Saving_movie_frames 0
52 #endif
53
54
55 // Returns the length of the first 'n' characters of a string.
56 int string_width( char *s, int n )
57 {
58         int w, h, aw;
59         char p;
60
61         p = s[n];
62         s[n] = 0;
63         gr_get_string_size( s, &w, &h, &aw );
64         s[n] = p;
65         return w;
66 }
67
68
69 // Draw string 's' centered on a canvas... if wider than
70 // canvas, then wrap it.
71 void draw_centered_text( int y, char *s )
72 {
73         int i, l;
74         char p;
75
76         l = (int)strlen(s);
77
78         if ( string_width( s, l ) < grd_curcanv->cv_bitmap.bm_w )
79         {
80                 gr_string( 0x8000, y, s );
81                 return;
82         }
83
84         for ( i = 0; i < l; i++ )
85         {
86                 if ( string_width(s, i) > (grd_curcanv->cv_bitmap.bm_w - 16) )
87                 {
88                         p = s[i];
89                         s[i] = 0;
90                         gr_string( 0x8000, y, s );
91                         s[i] = p;
92                         gr_string( 0x8000, y+grd_curcanv->cv_font->ft_h+1, &s[i] );
93                         return;
94                 }
95         }
96 }
97
98
99 extern ubyte DefiningMarkerMessage;
100 extern char Marker_input[];
101
102 #define MAX_MARKER_MESSAGE_LEN 120
103 void game_draw_marker_message(void)
104 {
105         char temp_string[MAX_MARKER_MESSAGE_LEN+25];
106
107         if ( DefiningMarkerMessage)
108         {
109                 gr_set_curfont( GAME_FONT );    //GAME_FONT
110                 gr_set_fontcolor( gr_getcolor(0,63,0), -1 );
111                 sprintf( temp_string, "Marker: %s_", Marker_input );
112                 draw_centered_text(grd_curcanv->cv_bitmap.bm_h/2 - 16, temp_string );
113         }
114 }
115
116
117 #ifdef NETWORK
118 void game_draw_multi_message(void)
119 {
120         char temp_string[MAX_MULTI_MESSAGE_LEN+25];
121
122         if ( (Game_mode&GM_MULTI) && multi_sending_message )
123         {
124                 gr_set_curfont( GAME_FONT );
125                 gr_set_fontcolor( gr_getcolor(0,63,0), -1 );
126                 sprintf( temp_string, "%s: %s_", TXT_MESSAGE, Network_message );
127                 draw_centered_text( grd_curcanv->cv_bitmap.bm_h/2-16, temp_string );
128         }
129
130         if ( (Game_mode&GM_MULTI) && multi_defining_message )
131         {
132                 gr_set_curfont( GAME_FONT );
133                 gr_set_fontcolor( gr_getcolor(0,63,0), -1 );
134                 sprintf( temp_string, "%s #%d: %s_", TXT_MACRO, multi_defining_message, Network_message );
135                 draw_centered_text( grd_curcanv->cv_bitmap.bm_h/2-16, temp_string );
136         }
137 }
138 #endif
139
140
141 //these should be in gr.h
142 #define cv_w  cv_bitmap.bm_w
143 #define cv_h  cv_bitmap.bm_h
144
145 fix frame_time_list[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
146 fix frame_time_total = 0;
147 int frame_time_cntr = 0;
148
149
150 void ftoa(char *string, fix f)
151 {
152         int decimal, fractional;
153
154         decimal = f2i(f);
155         fractional = ((f & 0xffff)*100)/65536;
156         if (fractional < 0 )
157                 fractional *= -1;
158         if (fractional > 99 )
159                 fractional = 99;
160         sprintf( string, "%d.%02d", decimal, fractional );
161 }
162
163
164 void show_framerate(void)
165 {
166         char temp[50];
167 //      static int q;
168         fix rate;
169         int x = 8, y = 5; // position measured from lower right corner
170
171         frame_time_total += RealFrameTime - frame_time_list[frame_time_cntr];
172         frame_time_list[frame_time_cntr] = RealFrameTime;
173         frame_time_cntr = (frame_time_cntr+1) % 8;
174
175         rate = fixdiv(f1_0*8, frame_time_total);
176
177         gr_set_curfont( GAME_FONT );    
178         gr_set_fontcolor( gr_getcolor(0,31,0), -1 );
179
180         ftoa( temp, rate ); // Convert fixed to string
181         if (Game_mode & GM_MULTI)
182                 y = 7;
183         gr_printf(grd_curcanv->cv_w-(x*GAME_FONT->ft_w),grd_curcanv->cv_h-y*(GAME_FONT->ft_h+GAME_FONT->ft_h/4),"FPS: %s ", temp );
184 //      if ( !( q++ % 30 ) )
185 //              mprintf(( 0, "fps: %s\n", temp ));
186 }
187
188
189 #ifndef NDEBUG
190 fix Show_view_text_timer = -1;
191
192 void draw_window_label(void)
193 {
194         if ( Show_view_text_timer > 0 )
195         {
196                 char *viewer_name, *control_name;
197                 char *viewer_id;
198                 Show_view_text_timer -= FrameTime;
199                 gr_set_curfont( GAME_FONT );
200
201                 viewer_id = "";
202                 switch( Viewer->type )
203                 {
204                         case OBJ_FIREBALL:  viewer_name = "Fireball";       break;
205                         case OBJ_ROBOT:     viewer_name = "Robot";
206 #ifdef EDITOR
207                                             viewer_id = Robot_names[Viewer->id];
208 #endif
209                                 break;
210                         case OBJ_HOSTAGE:   viewer_name = "Hostage";        break;
211                         case OBJ_PLAYER:    viewer_name = "Player";         break;
212                         case OBJ_WEAPON:    viewer_name = "Weapon";         break;
213                         case OBJ_CAMERA:    viewer_name = "Camera";         break;
214                         case OBJ_POWERUP:   viewer_name = "Powerup";
215                                             viewer_id = Powerup_names[Viewer->id];
216                                 break;
217                         case OBJ_DEBRIS:    viewer_name = "Debris";         break;
218                         case OBJ_CNTRLCEN:  viewer_name = "Reactor";        break;
219                         default:            viewer_name = "Unknown";        break;
220                 }
221
222                 switch ( Viewer->control_type)
223                 {
224                         case CT_NONE:       control_name = "Stopped";       break;
225                         case CT_AI:         control_name = "AI";            break;
226                         case CT_FLYING:     control_name = "Flying";        break;
227                         case CT_SLEW:       control_name = "Slew";          break;
228                         case CT_FLYTHROUGH: control_name = "Flythrough";    break;
229                         case CT_MORPH:      control_name = "Morphing";      break;
230                         default:            control_name = "Unknown";       break;
231                 }
232
233                 gr_set_fontcolor( gr_getcolor(31, 0, 0), -1 );
234                 gr_printf( 0x8000, 45, "%i: %s [%s] View - %s", OBJECT_NUMBER(Viewer), viewer_name, viewer_id, control_name );
235
236         }
237 }
238 #endif
239
240
241 extern int Game_window_x;
242 extern int Game_window_y;
243 extern int max_window_w;
244 extern int max_window_h;
245
246
247 void render_countdown_gauge(void)
248 {
249         if ( !Endlevel_sequence && Control_center_destroyed && (Countdown_seconds_left>-1)) // && (Countdown_seconds_left<127))
250         {
251                 int     y;
252
253                 if (!is_D2_OEM && !is_MAC_SHARE && !is_SHAREWARE) // no countdown on registered only
254                 {
255                         //      On last level, we don't want a countdown.
256                         if (PLAYING_BUILTIN_MISSION && Current_level_num == Last_level)
257                         {
258                                 if (!(Game_mode & GM_MULTI))
259                                         return;
260                                 if (Game_mode & GM_MULTI_ROBOTS)
261                                         return;
262                         }
263                 }
264
265                 gr_set_curfont( SMALL_FONT );
266                 gr_set_fontcolor( gr_getcolor(0,63,0), -1 );
267                 y = SMALL_FONT->ft_h*4;
268                 if (Cockpit_mode.intval == CM_FULL_SCREEN)
269                         y += SMALL_FONT->ft_h*2;
270
271                 if (Player_is_dead)
272                         y += SMALL_FONT->ft_h*2;
273
274                 //if (!((Cockpit_mode.intval == CM_STATUS_BAR) && (Game_window_y >= 19)))
275                 //      y += 5;
276                 gr_printf( 0x8000, y, "T-%d s", Countdown_seconds_left );
277         }
278 }
279
280
281 void game_draw_hud_stuff(void)
282 {
283         //mprintf((0, "Linear is %d!\n", LinearSVGABuffer));
284
285 #ifndef NDEBUG
286         if (Debug_pause)
287         {
288                 gr_set_curfont( MEDIUM1_FONT );
289                 gr_set_fontcolor( gr_getcolor(31, 31, 31), -1 ); //gr_getcolor(31,0,0));
290                 gr_ustring( 0x8000, 85/2, "Debug Pause - Press P to exit" );
291         }
292
293         draw_window_label();
294 #endif
295
296 #ifdef NETWORK
297         game_draw_multi_message();
298 #endif
299
300         game_draw_marker_message();
301
302 //      if (Game_mode & GM_MULTI)
303 //      {
304 //              if (Netgame.PlayTimeAllowed)
305 //                      game_draw_time_left ();
306 //      }
307
308         if ( (Newdemo_state == ND_STATE_PLAYBACK) || (Newdemo_state == ND_STATE_RECORDING) )
309         {
310                 char message[128];
311                 int h, w, aw;
312
313                 if (Newdemo_state == ND_STATE_PLAYBACK)
314                 {
315                         if (Newdemo_vcr_state != ND_STATE_PRINTSCREEN)
316                                 sprintf(message, "%s (%d%%%% %s)", TXT_DEMO_PLAYBACK, newdemo_get_percent_done(), TXT_DONE);
317                         else
318                                 sprintf(message, " ");
319                 }
320                 else
321                         sprintf(message, "%s", TXT_DEMO_RECORDING);
322
323                 gr_set_curfont( GAME_FONT );
324                 gr_set_fontcolor( gr_getcolor(27,0,0), -1 );
325
326                 gr_get_string_size( message, &w, &h, &aw );
327                 if (Cockpit_mode.intval == CM_FULL_COCKPIT)
328                 {
329                         if (grd_curcanv->cv_bitmap.bm_h > 240)
330                                 h += 40;
331                         else
332                                 h += 15;
333                 }
334                 else if ( Cockpit_mode.intval == CM_LETTERBOX )
335                         h += 7;
336                 if (Cockpit_mode.intval != CM_REAR_VIEW && !Saving_movie_frames)
337                         gr_printf( (grd_curcanv->cv_bitmap.bm_w-w)/2, grd_curcanv->cv_bitmap.bm_h - h - 2, message );
338         }
339
340         render_countdown_gauge();
341
342         if ( Player_num > -1 && Viewer->type==OBJ_PLAYER && Viewer->id==Player_num )
343         {
344                 int     x = 3;
345                 int     y = grd_curcanv->cv_bitmap.bm_h;
346
347                 gr_set_curfont( GAME_FONT );
348                 gr_set_fontcolor( gr_getcolor(0, 31, 0), -1 );
349                 if (Cruise_speed > 0)
350                 {
351                         int line_spacing = GAME_FONT->ft_h + GAME_FONT->ft_h/4;
352
353                         mprintf((0, "line_spacing=%d ", line_spacing));
354
355                         if (Cockpit_mode.intval == CM_FULL_SCREEN)
356                         {
357                                 if (Game_mode & GM_MULTI)
358                                         y -= line_spacing * 11; //64
359                                 else
360                                         y -= line_spacing * 6;  //32
361                         }
362                         else if (Cockpit_mode.intval == CM_STATUS_BAR)
363                         {
364                                 if (Game_mode & GM_MULTI)
365                                         y -= line_spacing * 8;  //48
366                                 else
367                                         y -= line_spacing * 4;  //24
368                         }
369                         else
370                         {
371                                 y = line_spacing * 2;       //12
372                                 x = 20+2;
373                         }
374
375                         gr_printf( x, y, "%s %2d%%", TXT_CRUISE, f2i(Cruise_speed) );
376                 }
377         }
378
379         if (r_framerate.intval)
380                 show_framerate();
381
382         if ( Newdemo_state == ND_STATE_PLAYBACK )
383                 Game_mode = Newdemo_game_mode;
384
385         draw_hud();
386
387         if ( Newdemo_state == ND_STATE_PLAYBACK )
388                 Game_mode = GM_NORMAL;
389
390         if ( Player_is_dead )
391                 player_dead_message();
392 }
393
394
395 extern int gr_bitblt_dest_step_shift;
396 extern int gr_wait_for_retrace;
397 extern int gr_bitblt_double;
398
399
400 #if 0
401 void expand_row(ubyte *dest, ubyte *src, int num_src_pixels );
402 #pragma aux expand_row parm [edi] [esi] [ecx] modify exact [ecx esi edi eax ebx] = \
403         "add    esi, ecx"   \
404         "dec    esi"        \
405         "add    edi, ecx"   \
406         "add    edi, ecx"   \
407         "dec    edi"        \
408         "dec    edi"        \
409 "nextpixel:"            \
410         "mov    al,[esi]"   \
411         "mov    ah, al"     \
412         "dec    esi"        \
413         "mov    [edi], ax"  \
414         "dec    edi"        \
415         "dec    edi"        \
416         "dec    ecx"        \
417         "jnz    nextpixel"  \
418 "done:"
419 #else
420 void expand_row( ubyte *dest, ubyte *src, int num_src_pixels )
421 {
422         int i;
423
424         for (i = 0; i < num_src_pixels; i++)
425         {
426                 *dest++ = *src;
427                 *dest++ = *src++;
428         }
429 }
430 #endif
431
432
433 // doubles the size in x or y of a bitmap in place.
434 void game_expand_bitmap( grs_bitmap *bmp, uint flags )
435 {
436         int i;
437         ubyte *dptr, *sptr;
438
439         switch(flags & 3)
440         {
441         case 2: // expand x
442                 Assert( bmp->bm_rowsize == bmp->bm_w*2 );
443                 dptr = &bmp->bm_data[(bmp->bm_h-1)*bmp->bm_rowsize];
444                 for ( i = bmp->bm_h-1; i >= 0; i-- )
445                 {
446                         expand_row( dptr, dptr, bmp->bm_w );    
447                         dptr -= bmp->bm_rowsize;
448                 }
449                 bmp->bm_w *= 2;
450                 break;
451         case 1: // expand y
452                 dptr = &bmp->bm_data[(2*(bmp->bm_h-1)+1)*bmp->bm_rowsize];
453                 sptr = &bmp->bm_data[(bmp->bm_h-1)*bmp->bm_rowsize];
454                 for ( i = bmp->bm_h-1; i >= 0; i-- )
455                 {
456                         memcpy( dptr, sptr, bmp->bm_w );        
457                         dptr -= bmp->bm_rowsize;
458                         memcpy( dptr, sptr, bmp->bm_w );        
459                         dptr -= bmp->bm_rowsize;
460                         sptr -= bmp->bm_rowsize;
461                 }
462                 bmp->bm_h *= 2;
463                 break;
464         case 3: // expand x & y
465                 Assert( bmp->bm_rowsize == bmp->bm_w*2 );
466                 dptr = &bmp->bm_data[(2*(bmp->bm_h-1)+1)*bmp->bm_rowsize];
467                 sptr = &bmp->bm_data[(bmp->bm_h-1)*bmp->bm_rowsize];
468                 for ( i = bmp->bm_h-1; i >= 0; i-- )
469                 {
470                         expand_row( dptr, sptr, bmp->bm_w );    
471                         dptr -= bmp->bm_rowsize;
472                         expand_row( dptr, sptr, bmp->bm_w );    
473                         dptr -= bmp->bm_rowsize;
474                         sptr -= bmp->bm_rowsize;
475                 }
476                 bmp->bm_w *= 2;
477                 bmp->bm_h *= 2;
478                 break;
479         }
480 }
481
482
483 extern int SW_drawn[2], SW_x[2], SW_y[2], SW_w[2], SW_h[2];
484
485
486 #if 0
487 //render a frame for the game in stereo
488 void game_render_frame_stereo(void)
489 {
490         int dw, dh, sw, sh;
491         fix save_aspect;
492         fix actual_eye_width;
493         int actual_eye_offset;
494         grs_canvas RenderCanvas[2];
495         int no_draw_hud = 0;
496
497         save_aspect = grd_curscreen->sc_aspect;
498         grd_curscreen->sc_aspect *= 2; // Muck with aspect ratio
499
500         sw = dw = VR_render_buffer[0].cv_bitmap.bm_w;
501         sh = dh = VR_render_buffer[0].cv_bitmap.bm_h;
502
503         if (VR_low_res & 1)
504         {
505                 sh /= 2;                                
506                 grd_curscreen->sc_aspect *= 2; // Muck with aspect ratio
507         }
508         if (VR_low_res & 2)
509         {
510                 sw /= 2;                                
511                 grd_curscreen->sc_aspect /= 2; // Muck with aspect ratio
512         }
513
514         gr_init_sub_canvas( &RenderCanvas[0], &VR_render_buffer[0], 0, 0, sw, sh );
515         gr_init_sub_canvas( &RenderCanvas[1], &VR_render_buffer[1], 0, 0, sw, sh );
516
517         // Draw the left eye's view
518         if (VR_eye_switch)
519         {
520                 actual_eye_width = -VR_eye_width;
521                 actual_eye_offset = -VR_eye_offset;
522         }
523         else
524         {
525                 actual_eye_width = VR_eye_width;
526                 actual_eye_offset = VR_eye_offset;
527         }
528
529         if (Guided_missile[Player_num] &&
530                 Guided_missile[Player_num]->type == OBJ_WEAPON &&
531                 Guided_missile[Player_num]->id == GUIDEDMISS_ID &&
532                 Guided_missile[Player_num]->signature == Guided_missile_sig[Player_num] &&
533                 Guided_in_big_window.intval)
534                 actual_eye_offset = 0;
535
536         gr_set_current_canvas(&RenderCanvas[0]);
537
538         if (Guided_missile[Player_num] &&
539                 Guided_missile[Player_num]->type == OBJ_WEAPON &&
540                 Guided_missile[Player_num]->id == GUIDEDMISS_ID &&
541                 Guided_missile[Player_num]->signature == Guided_missile_sig[Player_num] &&
542                 Guided_in_big_window.intval)
543         {
544                 char *msg = "Guided Missile View";
545                 object *viewer_save = Viewer;
546                 int w, h, aw;
547
548                 Viewer = Guided_missile[Player_num];
549
550                 {
551                         update_rendered_data(0, Viewer, 0, 0);
552                         render_frame(0, 0);
553
554                         wake_up_rendered_objects(Viewer, 0);
555                         Viewer = viewer_save;
556
557                         gr_set_curfont( GAME_FONT );
558                         gr_set_fontcolor( gr_getcolor(27,0,0), -1 );
559                         gr_get_string_size( msg, &w, &h, &aw );
560
561                         gr_printf( (grd_curcanv->cv_bitmap.bm_w-w)/2, 3, msg );
562
563                         draw_guided_crosshair();
564                 }
565
566                 HUD_render_message_frame();
567
568                 no_draw_hud = 1;
569         }
570         else if (Rear_view)
571                 render_frame(actual_eye_width, 0);  // switch eye positions for rear view
572         else
573                 render_frame(-actual_eye_width, 0); // Left eye
574
575         if ( VR_low_res )
576                 game_expand_bitmap( &RenderCanvas[0].cv_bitmap, VR_low_res );
577
578         {       // render small window into left eye's canvas
579                 grs_canvas *save = grd_curcanv;
580                 fix save_aspect2 = grd_curscreen->sc_aspect;
581
582                 grd_curscreen->sc_aspect = save_aspect*2;
583                 SW_drawn[0] = SW_drawn[1] = 0;
584                 show_extra_views();
585                 gr_set_current_canvas(save);
586                 grd_curscreen->sc_aspect = save_aspect2;
587         }
588
589 // NEWVR
590         if (actual_eye_offset > 0 )
591         {
592                 gr_setcolor( gr_getcolor(0,0,0) );
593                 gr_rect( grd_curcanv->cv_bitmap.bm_w-labs(actual_eye_offset)*2, 0, grd_curcanv->cv_bitmap.bm_w-1, grd_curcanv->cv_bitmap.bm_h );
594         }
595         else if (actual_eye_offset < 0 )
596         {
597                 gr_setcolor( gr_getcolor(0,0,0) );
598                 gr_rect( 0, 0, labs(actual_eye_offset)*2-1, grd_curcanv->cv_bitmap.bm_h );
599         }
600
601         if ( VR_show_hud && !no_draw_hud )
602         {
603                 grs_canvas tmp;
604
605                 if (actual_eye_offset < 0 )
606                 {
607                         gr_init_sub_canvas( &tmp, grd_curcanv, labs(actual_eye_offset*2), 0, grd_curcanv->cv_bitmap.bm_w-(labs(actual_eye_offset)*2), grd_curcanv->cv_bitmap.bm_h );
608                 }
609                 else
610                 {
611                         gr_init_sub_canvas( &tmp, grd_curcanv, 0, 0, grd_curcanv->cv_bitmap.bm_w-(labs(actual_eye_offset)*2), grd_curcanv->cv_bitmap.bm_h );
612                 }
613                 gr_set_current_canvas( &tmp );
614                 game_draw_hud_stuff();
615         }
616
617         // Draw the right eye's view
618         gr_set_current_canvas(&RenderCanvas[1]);
619
620         if (Guided_missile[Player_num] &&
621                 Guided_missile[Player_num]->type == OBJ_WEAPON &&
622                 Guided_missile[Player_num]->id == GUIDEDMISS_ID &&
623                 Guided_missile[Player_num]->signature == Guided_missile_sig[Player_num] &&
624                 Guided_in_big_window.intval)
625                 gr_bitmap(0, 0, &RenderCanvas[0].cv_bitmap);
626         else
627         {
628                 if (Rear_view)
629                         render_frame(-actual_eye_width, 0); // switch eye positions for rear view
630                 else
631                         render_frame(actual_eye_width, 0);  // Right eye
632
633                 if ( VR_low_res )
634                         game_expand_bitmap( &RenderCanvas[1].cv_bitmap, VR_low_res );
635         }
636
637         {       // copy small window from left eye
638                 grs_canvas temp;
639                 int w;
640
641                 for (w = 0; w < 2; w++)
642                 {
643                         if (SW_drawn[w])
644                         {
645                                 gr_init_sub_canvas(&temp, &RenderCanvas[0], SW_x[w], SW_y[w], SW_w[w], SW_h[w]);
646                                 gr_bitmap(SW_x[w]+actual_eye_offset*2, SW_y[w], &temp.cv_bitmap);
647                         }
648                 }
649         }
650
651 // NEWVR
652         if (actual_eye_offset > 0)
653         {
654                 gr_setcolor( gr_getcolor(0,0,0) );
655                 gr_rect( 0, 0, labs(actual_eye_offset)*2-1, grd_curcanv->cv_bitmap.bm_h );
656         }
657         else if ( actual_eye_offset < 0 )
658         {
659                 gr_setcolor( gr_getcolor(0,0,0) );
660                 gr_rect( grd_curcanv->cv_bitmap.bm_w-labs(actual_eye_offset)*2, 0, grd_curcanv->cv_bitmap.bm_w-1, grd_curcanv->cv_bitmap.bm_h );
661         }
662
663 // NEWVR (Add the next 2 lines)
664         if ( VR_show_hud && !no_draw_hud )
665         {
666                 grs_canvas tmp;
667
668                 if ( actual_eye_offset > 0 )
669                 {
670                         gr_init_sub_canvas( &tmp, grd_curcanv, labs(actual_eye_offset*2), 0, grd_curcanv->cv_bitmap.bm_w-(labs(actual_eye_offset)*2), grd_curcanv->cv_bitmap.bm_h );
671                 }
672                 else
673                 {
674                         gr_init_sub_canvas( &tmp, grd_curcanv, 0, 0, grd_curcanv->cv_bitmap.bm_w-(labs(actual_eye_offset)*2), grd_curcanv->cv_bitmap.bm_h );
675                 }
676                 gr_set_current_canvas( &tmp );
677                 game_draw_hud_stuff();
678         }
679
680         // Draws white and black registration encoding lines
681         // and Accounts for pixel-shift adjustment in upcoming bitblts
682         if (VR_use_reg_code)
683         {
684                 int width, height, quarter;
685
686                 width = RenderCanvas[0].cv_bitmap.bm_w;
687                 height = RenderCanvas[0].cv_bitmap.bm_h;
688                 quarter = width / 4;
689
690                 // black out left-hand side of left page
691
692                 // draw registration code for left eye
693                 if ( VR_eye_switch )
694                         gr_set_current_canvas( &RenderCanvas[1] );
695                 else
696                         gr_set_current_canvas( &RenderCanvas[0] );
697                 gr_setcolor( VR_WHITE_INDEX );
698                 gr_scanline( 0, quarter, height-1 );
699                 gr_setcolor( VR_BLACK_INDEX );
700                 gr_scanline( quarter, width-1, height-1 );
701
702                 if ( VR_eye_switch )
703                         gr_set_current_canvas( &RenderCanvas[0] );
704                 else
705                         gr_set_current_canvas( &RenderCanvas[1] );
706                 gr_setcolor( VR_WHITE_INDEX );
707                 gr_scanline( 0, quarter*3, height-1 );
708                 gr_setcolor( VR_BLACK_INDEX );
709                 gr_scanline( quarter*3, width-1, height-1 );
710    }
711
712         // Copy left eye, then right eye
713         if ( VR_screen_flags&VRF_USE_PAGING )
714                 VR_current_page = !VR_current_page;
715         else 
716                 VR_current_page = 0;
717         gr_set_current_canvas( &VR_screen_pages[VR_current_page] );
718
719 // NEWVR
720
721         if ( VR_eye_offset_changed > 0 )
722         {
723                 VR_eye_offset_changed--;
724                 gr_clear_canvas(0);
725         }
726
727         sw = dw = VR_render_buffer[0].cv_bitmap.bm_w;
728         sh = dh = VR_render_buffer[0].cv_bitmap.bm_h;
729
730         // Copy left eye, then right eye
731         gr_bitblt_dest_step_shift = 1; // Skip every other scanline.
732
733         if ( VR_render_mode == VR_INTERLACED )
734         {
735                 if ( actual_eye_offset > 0 )
736                 {
737                         int xoff = labs(actual_eye_offset);
738                         gr_bm_ubitblt( dw-xoff, dh, xoff, 0, 0, 0, &RenderCanvas[0].cv_bitmap, &VR_screen_pages[VR_current_page].cv_bitmap );
739                         gr_bm_ubitblt( dw-xoff, dh, 0, 1, xoff, 0, &RenderCanvas[1].cv_bitmap, &VR_screen_pages[VR_current_page].cv_bitmap );
740                 }
741                 else if ( actual_eye_offset < 0 )
742                 {
743                         int xoff = labs(actual_eye_offset);
744
745                         gr_bm_ubitblt( dw-xoff, dh, 0, 0, xoff, 0, &RenderCanvas[0].cv_bitmap, &VR_screen_pages[VR_current_page].cv_bitmap );
746                         gr_bm_ubitblt( dw-xoff, dh, xoff, 1, 0, 0, &RenderCanvas[1].cv_bitmap, &VR_screen_pages[VR_current_page].cv_bitmap );
747                 }
748                 else
749                 {
750                         gr_bm_ubitblt( dw, dh, 0, 0, 0, 0, &RenderCanvas[0].cv_bitmap, &VR_screen_pages[VR_current_page].cv_bitmap );
751                         gr_bm_ubitblt( dw, dh, 0, 1, 0, 0, &RenderCanvas[1].cv_bitmap, &VR_screen_pages[VR_current_page].cv_bitmap );
752                 }
753         }
754         else if (VR_render_mode == VR_AREA_DET)
755         {
756                 // VFX copy
757                 gr_bm_ubitblt( dw, dh, 0,  VR_current_page, 0, 0, &RenderCanvas[0].cv_bitmap, &VR_screen_pages[0].cv_bitmap );
758                 gr_bm_ubitblt( dw, dh, dw, VR_current_page, 0, 0, &RenderCanvas[1].cv_bitmap, &VR_screen_pages[0].cv_bitmap );
759         }
760         else
761         {
762                 Int3(); // Huh?
763         }
764
765         gr_bitblt_dest_step_shift = 0;
766
767 //      if ( Game_vfx_flag )
768 //              vfx_set_page(VR_current_page);          // 0 or 1
769 //      else
770         if ( VR_screen_flags&VRF_USE_PAGING )
771         {
772                 gr_wait_for_retrace = 0;
773
774 // Added by Samir from John's code
775                 if ( (VR_screen_pages[VR_current_page].cv_bitmap.bm_type == BM_MODEX) && (Game_3dmax_flag == 3) )
776                 {
777                         int old_x, old_y, new_x;
778
779                         old_x = VR_screen_pages[VR_current_page].cv_bitmap.bm_x;
780                         old_y = VR_screen_pages[VR_current_page].cv_bitmap.bm_y;
781                         new_x = old_y*VR_screen_pages[VR_current_page].cv_bitmap.bm_rowsize;
782                         new_x += old_x/4;
783                         VR_screen_pages[VR_current_page].cv_bitmap.bm_x = new_x;
784                         VR_screen_pages[VR_current_page].cv_bitmap.bm_y = 0;
785                         VR_screen_pages[VR_current_page].cv_bitmap.bm_type = BM_SVGA;
786                         gr_show_canvas( &VR_screen_pages[VR_current_page] );
787                         VR_screen_pages[VR_current_page].cv_bitmap.bm_type = BM_MODEX;
788                         VR_screen_pages[VR_current_page].cv_bitmap.bm_x = old_x;
789                         VR_screen_pages[VR_current_page].cv_bitmap.bm_y = old_y;
790                 }
791                 else
792                         gr_show_canvas( &VR_screen_pages[VR_current_page] );
793                 gr_wait_for_retrace = 1;
794         }
795         grd_curscreen->sc_aspect = save_aspect;
796 }
797 #endif
798
799
800 ubyte RenderingType = 0;
801 ubyte DemoDoingRight = 0, DemoDoingLeft = 0;
802 extern ubyte DemoDoRight, DemoDoLeft;
803 extern object DemoRightExtra, DemoLeftExtra;
804
805 char DemoWBUType[] = { 0, WBU_MISSILE, WBU_MISSILE, WBU_REAR, WBU_ESCORT, WBU_MARKER, WBU_MISSILE };
806 char DemoRearCheck[] = { 0, 0, 0, 1, 0, 0, 0 };
807 char *DemoExtraMessage[] = { "PLAYER", "GUIDED", "MISSILE", "REAR", "GUIDE-BOT", "MARKER", "SHIP" };
808
809 extern char guidebot_name[];
810
811 void show_extra_views()
812 {
813         int did_missile_view = 0;
814         int save_newdemo_state = Newdemo_state;
815         int w;
816
817         if (Newdemo_state == ND_STATE_PLAYBACK)
818         {
819                 if (DemoDoLeft)
820                 {
821                         DemoDoingLeft = DemoDoLeft;
822
823                         if (DemoDoLeft == 3)
824                                 do_cockpit_window_view(0, ConsoleObject, 1, WBU_REAR, "REAR");
825                         else
826                                 do_cockpit_window_view(0, &DemoLeftExtra, DemoRearCheck[DemoDoLeft], DemoWBUType[DemoDoLeft], DemoExtraMessage[DemoDoLeft]);
827                 }
828                 else
829                         do_cockpit_window_view(0, NULL, 0, WBU_WEAPON, NULL);
830
831                 if (DemoDoRight)
832                 {
833                         DemoDoingRight = DemoDoRight;
834
835                         if (DemoDoRight == 3)
836                                 do_cockpit_window_view(1, ConsoleObject, 1, WBU_REAR, "REAR");
837                         else
838                                 do_cockpit_window_view(1, &DemoRightExtra, DemoRearCheck[DemoDoRight], DemoWBUType[DemoDoRight], DemoExtraMessage[DemoDoRight]);
839                 }
840                 else
841                         do_cockpit_window_view(1, NULL, 0, WBU_WEAPON, NULL);
842
843                 DemoDoLeft = DemoDoRight = 0;
844                 DemoDoingLeft = DemoDoingRight = 0;
845
846                 return;
847         }
848
849         if (Guided_missile[Player_num] &&
850                 Guided_missile[Player_num]->type == OBJ_WEAPON &&
851                 Guided_missile[Player_num]->id == GUIDEDMISS_ID &&
852                 Guided_missile[Player_num]->signature == Guided_missile_sig[Player_num])
853         {
854                 if (Guided_in_big_window.intval)
855                 {
856                         RenderingType = 6 + (1<<4);
857                         do_cockpit_window_view(1, Viewer, 0, WBU_MISSILE, "SHIP");
858                 }
859                 else
860                 {
861                         RenderingType = 1 + (1<<4);
862                         do_cockpit_window_view(1, Guided_missile[Player_num], 0, WBU_GUIDED, "GUIDED");
863             }
864
865                 did_missile_view = 1;
866         }
867         else
868         {
869                 if (Guided_missile[Player_num]) // used to be active
870                 {
871                         if (!Guided_in_big_window.intval)
872                                 do_cockpit_window_view(1, NULL, 0, WBU_STATIC, NULL);
873                         Guided_missile[Player_num] = NULL;
874                 }
875
876                 if (Missile_viewer) // do missile view
877                 {
878                         static int mv_sig = -1;
879
880                         if (mv_sig == -1)
881                                 mv_sig = Missile_viewer->signature;
882                         if (Missile_view_enabled.intval &&
883                                 Missile_viewer->type != OBJ_NONE &&
884                                 Missile_viewer->signature == mv_sig)
885                         {
886                                 RenderingType = 2 + (1<<4);
887                                 do_cockpit_window_view(1, Missile_viewer, 0, WBU_MISSILE, "MISSILE");
888                                 did_missile_view = 1;
889                         }
890                         else
891                         {
892                                 Missile_viewer = NULL;
893                                 mv_sig = -1;
894                                 RenderingType = 255;
895                                 do_cockpit_window_view(1, NULL, 0, WBU_STATIC, NULL);
896                         }
897                 }
898         }
899
900         for (w = 0; w < 2; w++)
901         {
902                 if ( w == 1 && did_missile_view )
903                         continue; // if showing missile view in right window, can't show anything else
904
905                 // show special views if selected
906                 switch (Cockpit_3d_view[w].intval)
907                 {
908                         case CV_NONE:
909                                 RenderingType = 255;
910                                 do_cockpit_window_view(w, NULL, 0, WBU_WEAPON, NULL);
911                                 break;
912                         case CV_REAR:
913                                 if (Rear_view) // if big window is rear view, show front here
914                                 {
915                                         RenderingType = 3 + (w<<4);
916                                         do_cockpit_window_view(w, ConsoleObject, 0, WBU_REAR, "FRONT");
917                                 }
918                                 else // show normal rear view
919                                 {
920                                         RenderingType = 3 + (w<<4);
921                                         do_cockpit_window_view(w, ConsoleObject, 1, WBU_REAR, "REAR");
922                                 }
923                                 break;
924                         case CV_ESCORT:
925                         {
926                                 object *buddy;
927                                 buddy = find_escort();
928                                 if (buddy == NULL)
929                                 {
930                                         do_cockpit_window_view(w, NULL, 0, WBU_WEAPON, NULL);
931                                         cvar_setint(&Cockpit_3d_view[w], CV_NONE);
932                                 }
933                                 else
934                                 {
935                                         RenderingType = 4 + (w<<4);
936                                         do_cockpit_window_view(w, buddy, 0, WBU_ESCORT, guidebot_name);
937                                 }
938                                 break;
939                         }
940 #ifdef NETWORK
941                         case CV_COOP:
942                         {
943                                 int player = Coop_view_player[w];
944
945                                 RenderingType = 255; // don't handle coop stuff
946
947                                 if (player != -1 &&
948                                         Players[player].connected &&
949                                         ((Game_mode & GM_MULTI_COOP) || ((Game_mode & GM_TEAM) && (get_team(player) == get_team(Player_num)))))
950                                         do_cockpit_window_view(w, &Objects[Players[Coop_view_player[w]].objnum], 0, WBU_COOP, Players[Coop_view_player[w]].callsign);
951                                 else
952                                 {
953                                         do_cockpit_window_view(w, NULL, 0, WBU_WEAPON, NULL);
954                                         cvar_setint(&Cockpit_3d_view[w], CV_NONE);
955                                 }
956                                 break;
957                         }
958 #endif
959                         case CV_MARKER:
960                         {
961                                 char label[10];
962
963                                 RenderingType = 5 + (w<<4);
964                                 if ( Marker_viewer_num[w] == -1 || MarkerObject[Marker_viewer_num[w]] == -1 )
965                                 {
966                                         cvar_setint(&Cockpit_3d_view[w], CV_NONE);
967                                         break;
968                                 }
969                                 sprintf(label, "Marker %d", Marker_viewer_num[w] + 1);
970                                 do_cockpit_window_view(w, &Objects[MarkerObject[Marker_viewer_num[w]]], 0, WBU_MARKER, label);
971                                 break;
972                         }
973                         default:
974                                 Int3(); // invalid window type
975                 }
976         }
977         RenderingType = 0;
978         Newdemo_state = save_newdemo_state;
979 }
980
981
982 int BigWindowSwitch = 0;
983 extern int force_cockpit_redraw;
984
985 void draw_guided_crosshair(void);
986 void update_cockpits(int force_redraw);
987
988
989 // render a frame for the game
990 void game_render_frame_mono(void)
991 {
992         grs_canvas Screen_3d_window;
993         int no_draw_hud = 0;
994
995         gr_init_sub_canvas( &Screen_3d_window, &VR_screen_pages[0],
996                 VR_render_sub_buffer[0].cv_bitmap.bm_x, 
997                 VR_render_sub_buffer[0].cv_bitmap.bm_y, 
998                 VR_render_sub_buffer[0].cv_bitmap.bm_w, 
999                 VR_render_sub_buffer[0].cv_bitmap.bm_h);
1000
1001         if ( Game_double_buffer )
1002                 gr_set_current_canvas(&VR_render_sub_buffer[0]);
1003         else
1004                 gr_set_current_canvas(&Screen_3d_window);
1005
1006         if (Guided_missile[Player_num] &&
1007                 Guided_missile[Player_num]->type == OBJ_WEAPON &&
1008                 Guided_missile[Player_num]->id == GUIDEDMISS_ID &&
1009                 Guided_missile[Player_num]->signature == Guided_missile_sig[Player_num] &&
1010                 Guided_in_big_window.intval)
1011         {
1012                 char *msg = "Guided Missile View";
1013                 object *viewer_save = Viewer;
1014                 int w, h, aw;
1015
1016                 if (Cockpit_mode.intval == CM_FULL_COCKPIT)
1017                 {
1018                         BigWindowSwitch = 1;
1019                         force_cockpit_redraw = 1;
1020                         cvar_setint(&Cockpit_mode, CM_STATUS_BAR);
1021                         return;
1022                 }
1023
1024                 Viewer = Guided_missile[Player_num];
1025
1026                 {
1027                         update_rendered_data(0, Viewer, 0, 0);
1028                         render_frame(0, 0);
1029   
1030                         wake_up_rendered_objects(Viewer, 0);
1031                         Viewer = viewer_save;
1032
1033                         gr_set_curfont( GAME_FONT );    //GAME_FONT );
1034                         gr_set_fontcolor( gr_getcolor(27,0,0), -1 );
1035                         gr_get_string_size( msg, &w, &h, &aw );
1036
1037                         gr_printf( (grd_curcanv->cv_bitmap.bm_w-w)/2, 3, msg );
1038
1039                         draw_guided_crosshair();
1040                 }
1041
1042                 HUD_render_message_frame();
1043
1044                 no_draw_hud = 1;
1045         }
1046         else
1047         {
1048                 if (BigWindowSwitch)
1049                 {
1050                         force_cockpit_redraw = 1;
1051                         cvar_setint(&Cockpit_mode, CM_FULL_COCKPIT);
1052                         BigWindowSwitch = 0;
1053                         return;
1054                 }
1055                 update_rendered_data(0, Viewer, Rear_view, 0);
1056                 render_frame(0, 0);
1057         }
1058
1059         if ( Game_double_buffer )
1060                 gr_set_current_canvas(&VR_render_sub_buffer[0]);
1061         else
1062                 gr_set_current_canvas(&Screen_3d_window);
1063
1064         if (!no_draw_hud)
1065                 game_draw_hud_stuff();
1066
1067         if (Game_paused) // render pause message over off-screen 3d (to minimize flicker)
1068         {
1069                 extern char *Pause_msg;
1070                 ubyte *save_data = VR_screen_pages[VR_current_page].cv_bitmap.bm_data;
1071
1072                 VR_screen_pages[VR_current_page].cv_bitmap.bm_data=VR_render_buffer[VR_current_page].cv_bitmap.bm_data;
1073                 show_boxed_message(Pause_msg);
1074                 VR_screen_pages[VR_current_page].cv_bitmap.bm_data=save_data;
1075         }
1076
1077         if ( Game_double_buffer ) // copy to visible screen
1078         {
1079 //              if ( !Game_cockpit_copy_code )
1080 //              {
1081                         if ( VR_screen_flags&VRF_USE_PAGING )
1082                         {
1083                                 VR_current_page = !VR_current_page;
1084                                 gr_set_current_canvas( &VR_screen_pages[VR_current_page] );
1085                                 gr_bm_ubitblt( VR_render_sub_buffer[0].cv_w, VR_render_sub_buffer[0].cv_h, VR_render_sub_buffer[0].cv_bitmap.bm_x, VR_render_sub_buffer[0].cv_bitmap.bm_y, 0, 0, &VR_render_sub_buffer[0].cv_bitmap, &VR_screen_pages[VR_current_page].cv_bitmap );
1086                                 gr_wait_for_retrace = 0;
1087                                 gr_show_canvas( &VR_screen_pages[VR_current_page] );
1088                                 gr_wait_for_retrace = 1;
1089                         }
1090                         else
1091                         {
1092                                 gr_bm_ubitblt( VR_render_sub_buffer[0].cv_w, 
1093                                                 VR_render_sub_buffer[0].cv_h, 
1094                                                 VR_render_sub_buffer[0].cv_bitmap.bm_x, 
1095                                                 VR_render_sub_buffer[0].cv_bitmap.bm_y, 
1096                                                 0, 0, 
1097                                                 &VR_render_sub_buffer[0].cv_bitmap, 
1098                                                 &VR_screen_pages[0].cv_bitmap );
1099                         }
1100 //              }
1101 #if 0
1102                 else
1103                 {
1104 #ifdef __MSDOS__
1105                                 gr_ibitblt( &VR_render_buffer[0].cv_bitmap, &VR_screen_pages[0].cv_bitmap, Game_cockpit_copy_code );
1106 #else //def MACINTOSH
1107                                 gr_ibitblt( &VR_render_sub_buffer[0].cv_bitmap, &VR_screen_pages[0].cv_bitmap );
1108 #endif
1109                 }
1110 #endif
1111         }
1112
1113         update_cockpits(0);
1114
1115         show_extra_views(); // missile view, buddy bot, etc.
1116
1117         if ( Cockpit_mode.intval == CM_FULL_COCKPIT || Cockpit_mode.intval == CM_STATUS_BAR )
1118         {
1119                 if ( Newdemo_state == ND_STATE_PLAYBACK )
1120                         Game_mode = Newdemo_game_mode;
1121
1122                 render_gauges();
1123
1124                 if ( Newdemo_state == ND_STATE_PLAYBACK )
1125                         Game_mode = GM_NORMAL;
1126         }
1127
1128         con_draw();
1129
1130         vid_update();
1131 #ifdef OGL
1132         ogl_swap_buffers();
1133 #endif
1134 }
1135
1136
1137 void toggle_cockpit(void)
1138 {
1139         int new_mode;
1140
1141         switch (Cockpit_mode.intval)
1142         {
1143                 case CM_FULL_COCKPIT:
1144                 {
1145                         int max_h = grd_curscreen->sc_h - GameBitmaps[cockpit_bitmap[CM_STATUS_BAR + (SM_HIRES?(Num_cockpits/2):0)].index].bm_h;
1146
1147                         if (Game_window_h.intval > max_h) //too big for statusbar
1148                                 new_mode = CM_FULL_SCREEN;
1149                         else
1150                                 new_mode = CM_STATUS_BAR;
1151                         break;
1152                 }
1153
1154                 case CM_STATUS_BAR:
1155                 case CM_FULL_SCREEN:
1156                         if (Rear_view)
1157                                 return;
1158                         new_mode = CM_FULL_COCKPIT;
1159                         break;
1160
1161                 case CM_REAR_VIEW:
1162                 case CM_LETTERBOX:
1163                 default:
1164                         return; // do nothing
1165                         break;
1166
1167         }
1168
1169         select_cockpit(new_mode);
1170         HUD_clear_messages();
1171         WriteConfigFile();
1172 }
1173
1174
1175 #ifndef MACINTOSH
1176 #define WINDOW_W_DELTA  ((max_window_w / 16)&~1)   //24   //20
1177 #define WINDOW_H_DELTA  ((max_window_h / 16)&~1)   //12   //10
1178
1179 #define WINDOW_MIN_W    ((max_window_w * 10) / 22)        //160
1180 #define WINDOW_MIN_H    ((max_window_h * 10) / 22)
1181 #else
1182 //#define WINDOW_W_DELTA    32
1183 //#define WINDOW_H_DELTA    16
1184
1185 #define WINDOW_W_DELTA  ((max_window_w / 16) & ~15) // double word aligned
1186 #define WINDOW_H_DELTA  ((max_window_h / 16) & ~15) // double word aligned
1187
1188 #define WINDOW_MIN_W    (max_window_w-(WINDOW_W_DELTA*11))
1189 #define WINDOW_MIN_H    (max_window_h-(WINDOW_H_DELTA*11))
1190 #endif
1191
1192
1193 void grow_window(void)
1194 {
1195         if (Cockpit_mode.intval == CM_FULL_COCKPIT)
1196         {
1197                 cvar_setint(&Game_window_h, max_window_h);
1198                 cvar_setint(&Game_window_w, max_window_w);
1199                 toggle_cockpit();
1200                 HUD_init_message("Press F3 to return to Cockpit mode");
1201                 return;
1202         }
1203
1204         if (Cockpit_mode.intval != CM_STATUS_BAR && (VR_screen_flags & VRF_ALLOW_COCKPIT))
1205                 return;
1206
1207         if (Game_window_h.intval >= max_window_h || Game_window_w.intval >= max_window_w)
1208         {
1209                 //cvar_setint(&Game_window_w, max_window_w);
1210                 //cvar_setint(&Game_window_h, max_window_h);
1211                 select_cockpit(CM_FULL_SCREEN);
1212         }
1213         else
1214         {
1215                 //int x,y;
1216
1217                 cvar_setint(&Game_window_w, Game_window_w.intval + WINDOW_W_DELTA);
1218                 cvar_setint(&Game_window_h, Game_window_h.intval + WINDOW_H_DELTA);
1219
1220                 if (Game_window_h.intval > max_window_h)
1221                         cvar_setint(&Game_window_h, max_window_h);
1222
1223                 if (Game_window_w.intval > max_window_w)
1224                         cvar_setint(&Game_window_w, max_window_w);
1225
1226                 Game_window_x = (max_window_w - Game_window_w.intval) / 2;
1227                 Game_window_y = (max_window_h - Game_window_h.intval) / 2;
1228
1229                 game_init_render_sub_buffers( Game_window_x, Game_window_y, Game_window_w.intval, Game_window_h.intval );
1230         }
1231
1232         HUD_clear_messages(); // @mk, 11/11/94
1233
1234         WriteConfigFile();
1235 }
1236
1237
1238 extern grs_bitmap background_bitmap;
1239
1240 void copy_background_rect(int left,int top,int right,int bot)
1241 {
1242         grs_bitmap *bm = &background_bitmap;
1243         int x, y;
1244         int tile_left, tile_right, tile_top, tile_bot;
1245         int ofs_x, ofs_y;
1246         int dest_x, dest_y;
1247
1248         if (right < left || bot < top)
1249                 return;
1250
1251         tile_left = left / bm->bm_w;
1252         tile_right = right / bm->bm_w;
1253         tile_top = top / bm->bm_h;
1254         tile_bot = bot / bm->bm_h;
1255
1256         ofs_y = top % bm->bm_h;
1257         dest_y = top;
1258
1259         for (y = tile_top; y <= tile_bot; y++)
1260         {
1261                 int w, h;
1262
1263                 ofs_x = left % bm->bm_w;
1264                 dest_x = left;
1265
1266                 //h = (bot < dest_y+bm->bm_h)?(bot-dest_y+1):(bm->bm_h-ofs_y);
1267                 h = min(bot-dest_y+1,bm->bm_h-ofs_y);
1268
1269                 for (x = tile_left; x <= tile_right; x++)
1270                 {
1271                         //w = (right < dest_x+bm->bm_w)?(right-dest_x+1):(bm->bm_w-ofs_x);
1272                         w = min(right-dest_x+1, bm->bm_w-ofs_x);
1273
1274                         gr_bm_ubitblt(w, h, dest_x, dest_y, ofs_x, ofs_y, &background_bitmap, &grd_curcanv->cv_bitmap);
1275
1276                         ofs_x = 0;
1277                         dest_x += w;
1278                 }
1279
1280                 ofs_y = 0;
1281                 dest_y += h;
1282         }
1283 }
1284
1285
1286 // fills int the background surrounding the 3d window
1287 void fill_background(void)
1288 {
1289         int x, y, w, h, dx, dy;
1290
1291         x = Game_window_x;
1292         y = Game_window_y;
1293         w = Game_window_w.intval;
1294         h = Game_window_h.intval;
1295
1296         dx = x;
1297         dy = y;
1298
1299         gr_set_current_canvas(&VR_screen_pages[VR_current_page]);
1300         copy_background_rect(x-dx, y-dy, x-1, y+h+dy-1);
1301         copy_background_rect(x+w, y-dy, grd_curcanv->cv_w-1, y+h+dy-1);
1302         copy_background_rect(x, y-dy, x+w-1, y-1);
1303         copy_background_rect(x, y+h, x+w-1, y+h+dy-1);
1304
1305         if (VR_screen_flags & VRF_USE_PAGING)
1306         {
1307                 gr_set_current_canvas(&VR_screen_pages[!VR_current_page]);
1308                 copy_background_rect(x-dx, y-dy, x-1, y+h+dy-1);
1309                 copy_background_rect(x+w, y-dy, x+w+dx-1, y+h+dy-1);
1310                 copy_background_rect(x, y-dy, x+w-1, y-1);
1311                 copy_background_rect(x, y+h, x+w-1, y+h+dy-1);
1312         }
1313 }
1314
1315
1316 void shrink_window(void)
1317 {
1318         mprintf((0, "%d ", FrameCount));
1319
1320 //      mprintf((0, "W=%d H=%d\n", Game_window_w.intval, Game_window_h.intval));
1321
1322         if ( Cockpit_mode.intval == CM_FULL_COCKPIT && (VR_screen_flags & VRF_ALLOW_COCKPIT) )
1323         {
1324                 cvar_setint(&Game_window_h, max_window_h);
1325                 cvar_setint(&Game_window_w, max_window_w);
1326                 //!!toggle_cockpit();
1327                 select_cockpit(CM_STATUS_BAR);
1328 //              shrink_window();
1329 //              shrink_window();
1330                 HUD_init_message("Press F3 to return to Cockpit mode");
1331                 WriteConfigFile();
1332                 return;
1333         }
1334
1335         if (Cockpit_mode.intval == CM_FULL_SCREEN && (VR_screen_flags & VRF_ALLOW_COCKPIT))
1336         {
1337                 //cvar_setint(&Game_window_w, max_window_w);
1338                 //cvar_setint(&Game_window_h, max_window_h);
1339                 select_cockpit(CM_STATUS_BAR);
1340                 WriteConfigFile();
1341                 return;
1342         }
1343
1344         if (Cockpit_mode.intval != CM_STATUS_BAR && (VR_screen_flags & VRF_ALLOW_COCKPIT))
1345                 return;
1346
1347         mprintf((0, "Cockpit mode=%d\n", Cockpit_mode.intval));
1348
1349         if (Game_window_w.intval > WINDOW_MIN_W) {
1350                 //int x, y;
1351
1352                 cvar_setint(&Game_window_w, Game_window_w.intval - WINDOW_W_DELTA);
1353                 cvar_setint(&Game_window_h, Game_window_h.intval - WINDOW_H_DELTA);
1354
1355                 mprintf((0, "NewW=%d NewH=%d VW=%d maxH=%d\n", Game_window_w.intval, Game_window_h.intval, max_window_w, max_window_h));
1356                   
1357                 if ( Game_window_w.intval < WINDOW_MIN_W )
1358                         cvar_setint(&Game_window_w, WINDOW_MIN_W);
1359
1360                 if ( Game_window_h.intval < WINDOW_MIN_H )
1361                         cvar_setint(&Game_window_h, WINDOW_MIN_H);
1362                         
1363                 Game_window_x = (max_window_w - Game_window_w.intval) / 2;
1364                 Game_window_y = (max_window_h - Game_window_h.intval) / 2;
1365
1366                 fill_background();
1367
1368                 game_init_render_sub_buffers( Game_window_x, Game_window_y, Game_window_w.intval, Game_window_h.intval );
1369                 HUD_clear_messages();
1370                 WriteConfigFile();
1371         }
1372
1373 }
1374
1375 int last_drawn_cockpit[2] = { -1, -1 };
1376 extern void ogl_loadbmtexture(grs_bitmap *bm); 
1377
1378 // This actually renders the new cockpit onto the screen.
1379 void update_cockpits(int force_redraw)
1380 {
1381         //int x, y, w, h;
1382
1383         // Redraw the on-screen cockpit bitmaps
1384         if (VR_render_mode != VR_NONE )
1385                 return;
1386
1387         switch( Cockpit_mode.intval )
1388         {
1389         case CM_FULL_COCKPIT:
1390         case CM_REAR_VIEW:
1391                 gr_set_current_canvas(&VR_screen_pages[VR_current_page]);
1392                 PIGGY_PAGE_IN(cockpit_bitmap[Cockpit_mode.intval + (SM_HIRES?(Num_cockpits/2):0)]);
1393                 gr_ubitmapm(0, 0, &GameBitmaps[cockpit_bitmap[Cockpit_mode.intval + (SM_HIRES?(Num_cockpits/2):0)].index]);
1394                 break;
1395
1396         case CM_FULL_SCREEN:
1397                 Game_window_x = (max_window_w - Game_window_w.intval) / 2;
1398                 Game_window_y = (max_window_h - Game_window_h.intval) / 2;
1399                 fill_background();
1400                 break;
1401
1402         case CM_STATUS_BAR:
1403
1404                 gr_set_current_canvas(&VR_screen_pages[VR_current_page]);
1405
1406                 PIGGY_PAGE_IN(cockpit_bitmap[Cockpit_mode.intval + (SM_HIRES?(Num_cockpits/2):0)]);
1407                 gr_ubitmapm(0, max_window_h, &GameBitmaps[cockpit_bitmap[Cockpit_mode.intval + (SM_HIRES?(Num_cockpits/2):0)].index]);
1408         
1409                 Game_window_x = (max_window_w - Game_window_w.intval) / 2;
1410                 Game_window_y = (max_window_h - Game_window_h.intval) / 2;
1411                 fill_background();
1412                 break;
1413
1414         case CM_LETTERBOX:
1415                 gr_set_current_canvas(&VR_screen_pages[VR_current_page]);
1416
1417                 // Clear the top and bottom of the screen
1418                 gr_setcolor(BM_XRGB(0,0,0));
1419                 gr_rect(0,
1420                         VR_render_sub_buffer[VR_current_page].cv_bitmap.bm_y + VR_render_sub_buffer[VR_current_page].cv_bitmap.bm_h,
1421                         GWIDTH-1,GHEIGHT-1);
1422                 gr_rect(0, 0, GWIDTH-1, VR_render_sub_buffer[VR_current_page].cv_bitmap.bm_y);
1423
1424                 // In a modex mode, clear the other buffer.
1425                 if (grd_curcanv->cv_bitmap.bm_type == BM_MODEX)
1426                 {
1427                         gr_set_current_canvas(&VR_screen_pages[VR_current_page^1]);
1428                         gr_clear_canvas( BM_XRGB(0,0,0) );
1429                         gr_set_current_canvas(&VR_screen_pages[VR_current_page]);
1430                 }
1431                 break;
1432
1433         }
1434
1435         gr_set_current_canvas(&VR_screen_pages[VR_current_page]);
1436
1437         if (Cockpit_mode.intval != last_drawn_cockpit[VR_current_page] || force_redraw )
1438                 last_drawn_cockpit[VR_current_page] = Cockpit_mode.intval;
1439         else
1440                 return;
1441
1442         if ( Cockpit_mode.intval == CM_FULL_COCKPIT || Cockpit_mode.intval == CM_STATUS_BAR )
1443                 init_gauges();
1444 }
1445
1446
1447 void game_render_frame(void)
1448 {
1449         set_screen_mode( SCREEN_GAME );
1450
1451 //      update_cockpits(0);
1452
1453         play_homing_warning();
1454
1455         if (VR_render_mode == VR_NONE )
1456                 game_render_frame_mono();        
1457 /*      else
1458                 game_render_frame_stereo();      
1459                 */
1460
1461         // Make sure palette is faded in
1462         stop_time();
1463         gr_palette_fade_in( gr_palette, 32, 0 );
1464         start_time();
1465
1466         FrameCount++;
1467 }
1468
1469
1470 extern int Color_0_31_0;
1471
1472
1473 // draw a crosshair for the guided missile
1474 void draw_guided_crosshair(void)
1475 {
1476         int x, y, w, h;
1477
1478         gr_setcolor(Color_0_31_0);
1479
1480         w = grd_curcanv->cv_w>>5;
1481         if (w < 5)
1482                 w = 5;
1483
1484         h = i2f(w) / grd_curscreen->sc_aspect;
1485
1486         x = grd_curcanv->cv_w / 2;
1487         y = grd_curcanv->cv_h / 2;
1488
1489         gr_scanline(x-w/2, x+w/2, y);
1490         gr_uline(i2f(x), i2f(y-h/2), i2f(x), i2f(y+h/2));
1491
1492 }
1493
1494
1495 typedef struct bkg {
1496         short x, y, w, h;   // The location of the menu.
1497         grs_bitmap * bmp;   // The background under the menu.
1498 } bkg;
1499
1500 bkg bg = { 0, 0, 0, 0, NULL };
1501
1502 #define BOX_BORDER (MenuHires?60:30)
1503
1504
1505 // show a message in a nice little box
1506 void show_boxed_message(char *msg)
1507 {
1508         int w, h, aw;
1509         int x, y;
1510
1511         gr_set_current_canvas(&VR_screen_pages[VR_current_page]);
1512         gr_set_curfont( MEDIUM1_FONT );
1513
1514         gr_get_string_size(msg, &w, &h, &aw);
1515
1516         x = (grd_curscreen->sc_w-w)/2;
1517         y = (grd_curscreen->sc_h-h)/2;
1518
1519         if (bg.bmp)
1520         {
1521                 gr_free_bitmap(bg.bmp);
1522                 bg.bmp = NULL;
1523         }
1524
1525         // Save the background of the display
1526         bg.x=x; bg.y=y; bg.w=w; bg.h=h;
1527
1528         bg.bmp = gr_create_bitmap( w+BOX_BORDER, h+BOX_BORDER );
1529
1530         gr_bm_ubitblt( w+BOX_BORDER, h+BOX_BORDER, 0, 0, x-BOX_BORDER/2, y-BOX_BORDER/2, &(grd_curcanv->cv_bitmap), bg.bmp );
1531
1532         nm_draw_background(x-BOX_BORDER/2, y-BOX_BORDER/2, x+w+BOX_BORDER/2-1, y+h+BOX_BORDER/2-1);
1533
1534         gr_set_fontcolor( gr_getcolor(31, 31, 31), -1 );
1535
1536         gr_ustring( 0x8000, y, msg );
1537 }
1538
1539
1540 void clear_boxed_message(void)
1541 {
1542         if (bg.bmp)
1543         {
1544                 gr_bitmap(bg.x-BOX_BORDER/2, bg.y-BOX_BORDER/2, bg.bmp);
1545
1546                 gr_free_bitmap(bg.bmp);
1547                 bg.bmp = NULL;
1548         }
1549 }