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