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