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