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