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