diff options
-rw-r--r-- | src/doomdef.h | 7 | ||||
-rw-r--r-- | src/i_scale.c | 561 | ||||
-rw-r--r-- | src/i_scale.h | 33 | ||||
-rw-r--r-- | src/i_video.c | 569 | ||||
-rw-r--r-- | src/i_video.h | 28 | ||||
-rw-r--r-- | src/m_misc.c | 3 |
6 files changed, 873 insertions, 328 deletions
diff --git a/src/doomdef.h b/src/doomdef.h index 795cc221..acd2a5d6 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -120,12 +120,13 @@ typedef enum #define SCREENWIDTH 320 #define SCREENHEIGHT 200 -// Alternate screenheight for letterbox/aspect ratio corrected mode - -#define SCREENHEIGHT_4_3 240 +// Screen width used for "squash" scale functions +#define SCREENWIDTH_4_3 256 +// Screen height used for "stretch" scale functions. +#define SCREENHEIGHT_4_3 240 // The maximum number of players, multiplayer/networking. #define MAXPLAYERS 4 diff --git a/src/i_scale.c b/src/i_scale.c index cba883a5..e320e1cb 100644 --- a/src/i_scale.c +++ b/src/i_scale.c @@ -26,11 +26,10 @@ // //----------------------------------------------------------------------------- - - #include "doomdef.h" #include "doomtype.h" +#include "i_video.h" #include "z_zone.h" // Should be screens[0] @@ -52,6 +51,10 @@ static int dest_pitch; static byte *stretch_tables[2]; +// 50%/50% stretch table, for 800x600 squash mode + +static byte *half_stretch_table; + // Called to set the source and destination buffers before doing the // scale. @@ -69,7 +72,7 @@ void I_InitScale(byte *_src_buffer, byte *_dest_buffer, int _dest_pitch) // 1x scale doesn't really do any scaling: it just copies the buffer // a line at a time for when pitch != SCREENWIDTH (!native_surface) -void I_Scale1x(int x1, int y1, int x2, int y2) +static void I_Scale1x(int x1, int y1, int x2, int y2) { byte *bufp, *screenp; int y; @@ -88,7 +91,15 @@ void I_Scale1x(int x1, int y1, int x2, int y2) } } -void I_Scale2x(int x1, int y1, int x2, int y2) +screen_mode_t mode_scale_1x = { + SCREENWIDTH, SCREENHEIGHT, + NULL, + I_Scale1x, +}; + +// 2x scale (640x400) + +static void I_Scale2x(int x1, int y1, int x2, int y2) { byte *bufp, *screenp, *screenp2; int x, y; @@ -118,7 +129,15 @@ void I_Scale2x(int x1, int y1, int x2, int y2) } } -void I_Scale3x(int x1, int y1, int x2, int y2) +screen_mode_t mode_scale_2x = { + SCREENWIDTH * 2, SCREENHEIGHT * 2, + NULL, + I_Scale2x, +}; + +// 3x scale (960x600) + +static void I_Scale3x(int x1, int y1, int x2, int y2) { byte *bufp, *screenp, *screenp2, *screenp3; int x, y; @@ -152,7 +171,15 @@ void I_Scale3x(int x1, int y1, int x2, int y2) } } -void I_Scale4x(int x1, int y1, int x2, int y2) +screen_mode_t mode_scale_3x = { + SCREENWIDTH * 3, SCREENHEIGHT * 3, + NULL, + I_Scale3x, +}; + +// 4x scale (1280x800) + +static void I_Scale4x(int x1, int y1, int x2, int y2) { byte *bufp, *screenp, *screenp2, *screenp3, *screenp4; int x, y; @@ -190,7 +217,15 @@ void I_Scale4x(int x1, int y1, int x2, int y2) } } -void I_Scale5x(int x1, int y1, int x2, int y2) +screen_mode_t mode_scale_4x = { + SCREENWIDTH * 4, SCREENHEIGHT * 4, + NULL, + I_Scale4x, +}; + +// 5x scale (1600x1000) + +static void I_Scale5x(int x1, int y1, int x2, int y2) { byte *bufp, *screenp, *screenp2, *screenp3, *screenp4, *screenp5; int x, y; @@ -232,6 +267,13 @@ void I_Scale5x(int x1, int y1, int x2, int y2) } } +screen_mode_t mode_scale_5x = { + SCREENWIDTH * 5, SCREENHEIGHT * 5, + NULL, + I_Scale5x, +}; + + // Search through the given palette, finding the nearest color that matches // the given color. @@ -301,7 +343,7 @@ static byte *GenerateStretchTable(byte *palette, int pct) // Called at startup to generate the lookup tables for aspect ratio // correcting scale up. -void I_InitStretchTables(byte *palette) +static void I_InitStretchTables(byte *palette) { // We only actually need two lookup tables: // @@ -320,6 +362,17 @@ void I_InitStretchTables(byte *palette) puts(""); } +// Create 50%/50% table for 800x600 squash mode + +static void I_InitSquashTable(byte *palette) +{ + printf("I_InitSquashTable: Generating lookup table.."); + fflush(stdout); + half_stretch_table = GenerateStretchTable(palette, 50); + puts(""); +} + + // // Aspect ratio correcting scale up functions. // @@ -327,7 +380,7 @@ void I_InitStretchTables(byte *palette) // screen mode. // -static void WriteBlendedLine1x(byte *dest, byte *src1, byte *src2, +static inline void WriteBlendedLine1x(byte *dest, byte *src1, byte *src2, byte *stretch_table) { int x; @@ -341,7 +394,9 @@ static void WriteBlendedLine1x(byte *dest, byte *src1, byte *src2, } } -void I_Stretch1x(int x1, int y1, int x2, int y2) +// 1x stretch (320x240) + +static void I_Stretch1x(int x1, int y1, int x2, int y2) { byte *bufp, *screenp; int y; @@ -389,7 +444,14 @@ void I_Stretch1x(int x1, int y1, int x2, int y2) } } -static void WriteLine2x(byte *dest, byte *src) +screen_mode_t mode_stretch_1x = { + SCREENWIDTH, SCREENHEIGHT_4_3, + I_InitStretchTables, + I_Stretch1x, + true, +}; + +static inline void WriteLine2x(byte *dest, byte *src) { int x; @@ -402,7 +464,7 @@ static void WriteLine2x(byte *dest, byte *src) } } -static void WriteBlendedLine2x(byte *dest, byte *src1, byte *src2, +static inline void WriteBlendedLine2x(byte *dest, byte *src1, byte *src2, byte *stretch_table) { int x; @@ -419,9 +481,9 @@ static void WriteBlendedLine2x(byte *dest, byte *src1, byte *src2, } } -// Scale 2x, correcting aspect ratio in the process +// 2x stretch (640x480) -void I_Stretch2x(int x1, int y1, int x2, int y2) +static void I_Stretch2x(int x1, int y1, int x2, int y2) { byte *bufp, *screenp; int y; @@ -493,7 +555,13 @@ void I_Stretch2x(int x1, int y1, int x2, int y2) } } -static void WriteLine3x(byte *dest, byte *src) +screen_mode_t mode_stretch_2x = { + SCREENWIDTH * 2, SCREENHEIGHT_4_3 * 2, + I_InitStretchTables, + I_Stretch2x, +}; + +static inline void WriteLine3x(byte *dest, byte *src) { int x; @@ -507,7 +575,7 @@ static void WriteLine3x(byte *dest, byte *src) } } -static void WriteBlendedLine3x(byte *dest, byte *src1, byte *src2, +static inline void WriteBlendedLine3x(byte *dest, byte *src1, byte *src2, byte *stretch_table) { int x; @@ -525,7 +593,9 @@ static void WriteBlendedLine3x(byte *dest, byte *src1, byte *src2, } } -void I_Stretch3x(int x1, int y1, int x2, int y2) +// 3x stretch (960x720) + +static void I_Stretch3x(int x1, int y1, int x2, int y2) { byte *bufp, *screenp; int y; @@ -621,7 +691,13 @@ void I_Stretch3x(int x1, int y1, int x2, int y2) } } -static void WriteLine4x(byte *dest, byte *src) +screen_mode_t mode_stretch_3x = { + SCREENWIDTH * 3, SCREENHEIGHT_4_3 * 3, + I_InitStretchTables, + I_Stretch3x, +}; + +static inline void WriteLine4x(byte *dest, byte *src) { int x; @@ -636,7 +712,7 @@ static void WriteLine4x(byte *dest, byte *src) } } -static void WriteBlendedLine4x(byte *dest, byte *src1, byte *src2, +static inline void WriteBlendedLine4x(byte *dest, byte *src1, byte *src2, byte *stretch_table) { int x; @@ -655,7 +731,9 @@ static void WriteBlendedLine4x(byte *dest, byte *src1, byte *src2, } } -void I_Stretch4x(int x1, int y1, int x2, int y2) +// 4x stretch (1280x960) + +static void I_Stretch4x(int x1, int y1, int x2, int y2) { byte *bufp, *screenp; int y; @@ -775,7 +853,13 @@ void I_Stretch4x(int x1, int y1, int x2, int y2) } } -static void WriteLine5x(byte *dest, byte *src) +screen_mode_t mode_stretch_4x = { + SCREENWIDTH * 4, SCREENHEIGHT_4_3 * 4, + I_InitStretchTables, + I_Stretch4x, +}; + +static inline void WriteLine5x(byte *dest, byte *src) { int x; @@ -791,7 +875,9 @@ static void WriteLine5x(byte *dest, byte *src) } } -void I_Stretch5x(int x1, int y1, int x2, int y2) +// 5x stretch (1600x1200) + +static void I_Stretch5x(int x1, int y1, int x2, int y2) { byte *bufp, *screenp; int y; @@ -839,3 +925,434 @@ void I_Stretch5x(int x1, int y1, int x2, int y2) } } +screen_mode_t mode_stretch_5x = { + SCREENWIDTH * 5, SCREENHEIGHT_4_3 * 5, + I_InitStretchTables, + I_Stretch5x, +}; + +// +// Aspect ratio correcting "squash" functions. +// +// These do the opposite of the "stretch" functions above: while the +// stretch functions increase the vertical dimensions, the squash +// functions decrease the horizontal dimensions for the same result. +// +// The same blend tables from the stretch functions are reused; as +// a result, the dimensions are *slightly* wrong (eg. 320x200 should +// squash to 266x200, but actually squashes to 256x200). +// + +// +// 1x squashed scale (256x200) +// + +static inline void WriteSquashedLine1x(byte *dest, byte *src) +{ + int x; + + for (x=0; x<SCREENWIDTH; ) + { + // Draw in blocks of 5 + + // 80% pixel 0, 20% pixel 1 + + *dest++ = stretch_tables[0][src[1] * 256 + src[0]]; + + // 60% pixel 1, 40% pixel 2 + + *dest++ = stretch_tables[1][src[2] * 256 + src[1]]; + + // 40% pixel 2, 60% pixel 3 + + *dest++ = stretch_tables[1][src[2] * 256 + src[3]]; + + // 20% pixel 3, 80% pixel 4 + + *dest++ = stretch_tables[0][src[3] * 256 + src[4]]; + + x += 5; + src += 5; + } +} + +// 1x squashed (256x200) + +static void I_Squash1x(int x1, int y1, int x2, int y2) +{ + byte *bufp, *screenp; + int y; + + // Only works with full screen update + + if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT) + { + return; + } + + bufp = src_buffer; + screenp = (byte *) dest_buffer; + + for (y=0; y<SCREENHEIGHT; ++y) + { + WriteSquashedLine1x(screenp, bufp); + + screenp += dest_pitch; + bufp += SCREENWIDTH; + } +} + +screen_mode_t mode_squash_1x = { + SCREENWIDTH_4_3, SCREENHEIGHT, + I_InitStretchTables, + I_Squash1x, + true, +}; + + +// +// 2x squashed scale (512x400) +// + +#define DRAW_PIXEL2 \ + *dest++ = *dest2++ = c; + +static inline void WriteSquashedLine2x(byte *dest, byte *src) +{ + byte *dest2; + int x, c; + + dest2 = dest + dest_pitch; + + for (x=0; x<SCREENWIDTH; ) + { + // Draw in blocks of 5 + + // 100% pixel 0 + + c = src[0]; + DRAW_PIXEL2; + + // 60% pixel 0, 40% pixel 1 + + c = stretch_tables[1][src[1] * 256 + src[0]]; + DRAW_PIXEL2; + + // 100% pixel 1 + + c = src[1]; + DRAW_PIXEL2; + + // 20% pixel 1, 80% pixel 2 + + c = stretch_tables[0][src[1] * 256 + src[2]]; + DRAW_PIXEL2; + + // 80% pixel 2, 20% pixel 3 + + c = stretch_tables[0][src[3] * 256 + src[2]]; + DRAW_PIXEL2; + + // 100% pixel 3 + + c = src[3]; + DRAW_PIXEL2; + + // 40% pixel 3, 60% pixel 4 + + c = stretch_tables[1][src[3] * 256 + src[4]]; + DRAW_PIXEL2; + + // 100% pixel 4 + + c = src[4]; + DRAW_PIXEL2; + + x += 5; + src += 5; + } +} + +// 2x squash (512x400) + +static void I_Squash2x(int x1, int y1, int x2, int y2) +{ + byte *bufp, *screenp; + int y; + + // Only works with full screen update + + if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT) + { + return; + } + + bufp = src_buffer; + screenp = (byte *) dest_buffer; + + for (y=0; y<SCREENHEIGHT; ++y) + { + WriteSquashedLine2x(screenp, bufp); + + screenp += dest_pitch * 2; + bufp += SCREENWIDTH; + } +} + +screen_mode_t mode_squash_2x = { + SCREENWIDTH_4_3 * 2, SCREENHEIGHT * 2, + I_InitStretchTables, + I_Squash2x, +}; + + +#define DRAW_PIXEL3 \ + *dest++ = *dest2++ = *dest3++ = c + +static inline void WriteSquashedLine3x(byte *dest, byte *src) +{ + byte *dest2, *dest3; + int x, c; + + dest2 = dest + dest_pitch; + dest3 = dest + dest_pitch * 2; + + for (x=0; x<SCREENWIDTH; ) + { + // Every 2 pixels is expanded to 5 pixels + + // 100% pixel 0 x2 + + c = src[0]; + + DRAW_PIXEL3; + DRAW_PIXEL3; + + // 50% pixel 0, 50% pixel 1 + + c = half_stretch_table[src[0] * 256 + src[1]]; + + DRAW_PIXEL3; + + // 100% pixel 1 + + c = src[1]; + + DRAW_PIXEL3; + DRAW_PIXEL3; + + x += 2; + src += 2; + } +} + + +// +// 3x scale squashed (800x600) +// +// This is a special case that uses the half_stretch_table (50%) rather +// than the normal stretch_tables(20,40%), to scale up to 800x600 +// exactly. +// + +static void I_Squash3x(int x1, int y1, int x2, int y2) +{ + byte *bufp, *screenp; + int y; + + // Only works with full screen update + + if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT) + { + return; + } + + bufp = src_buffer; + screenp = (byte *) dest_buffer; + + for (y=0; y<SCREENHEIGHT; ++y) + { + WriteSquashedLine3x(screenp, bufp); + + screenp += dest_pitch * 3; + bufp += SCREENWIDTH; + } +} + +screen_mode_t mode_squash_3x = { + 800, 600, + I_InitSquashTable, + I_Squash3x, +}; + +#define DRAW_PIXEL4 \ + *dest++ = *dest2++ = *dest3++ = *dest4++ = c; + +static inline void WriteSquashedLine4x(byte *dest, byte *src) +{ + int x; + int c; + byte *dest2, *dest3, *dest4; + + dest2 = dest + dest_pitch; + dest3 = dest + dest_pitch * 2; + dest4 = dest + dest_pitch * 3; + + for (x=0; x<SCREENWIDTH; ) + { + // Draw in blocks of 5 + + // 100% pixel 0 x3 + + c = src[0]; + DRAW_PIXEL4; + DRAW_PIXEL4; + DRAW_PIXEL4; + + // 20% pixel 0, 80% pixel 1 + + c = stretch_tables[0][src[0] * 256 + src[1]]; + DRAW_PIXEL4; + + // 100% pixel 1 x2 + + c = src[1]; + DRAW_PIXEL4; + DRAW_PIXEL4; + + // 40% pixel 1, 60% pixel 2 + + c = stretch_tables[1][src[1] * 256 + src[2]]; + DRAW_PIXEL4; + + // 100% pixel 2 x2 + + c = src[2]; + DRAW_PIXEL4; + DRAW_PIXEL4; + + // 60% pixel 2, 40% pixel 3 + + c = stretch_tables[1][src[3] * 256 + src[2]]; + DRAW_PIXEL4; + + // 100% pixel 3 x2 + + c = src[3]; + DRAW_PIXEL4; + DRAW_PIXEL4; + + // 80% pixel 3, 20% pixel 4 + + c = stretch_tables[0][src[4] * 256 + src[3]]; + DRAW_PIXEL4; + + // 100% pixel 4 + + c = src[4]; + DRAW_PIXEL4; + DRAW_PIXEL4; + DRAW_PIXEL4; + + x += 5; + src += 5; + } +} + +// +// 4x squashed (1024x800) +// + +static void I_Squash4x(int x1, int y1, int x2, int y2) +{ + byte *bufp, *screenp; + int y; + + // Only works with full screen update + + if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT) + { + return; + } + + bufp = src_buffer; + screenp = (byte *) dest_buffer; + + for (y=0; y<SCREENHEIGHT; ++y) + { + WriteSquashedLine4x(screenp, bufp); + + screenp += dest_pitch * 4; + bufp += SCREENWIDTH; + } +} + +screen_mode_t mode_squash_4x = { + SCREENWIDTH_4_3 * 4, SCREENHEIGHT * 4, + I_InitStretchTables, + I_Squash4x, +}; + +#define DRAW_PIXEL5 \ + *dest++ = *dest2++ = *dest3++ = *dest4++ = *dest5++ = c + +static inline void WriteSquashedLine5x(byte *dest, byte *src) +{ + int x; + int c; + byte *dest2, *dest3, *dest4, *dest5; + + dest2 = dest + dest_pitch; + dest3 = dest + dest_pitch * 2; + dest4 = dest + dest_pitch * 3; + dest5 = dest + dest_pitch * 4; + + for (x=0; x<SCREENWIDTH; ++x) + { + // Draw in blocks of 5 + + // 100% pixel 0 x4 + + c = *src++; + DRAW_PIXEL5; + DRAW_PIXEL5; + DRAW_PIXEL5; + DRAW_PIXEL5; + } +} + +// +// 5x squashed (1280x1000) +// + +static void I_Squash5x(int x1, int y1, int x2, int y2) +{ + byte *bufp, *screenp; + int y; + + // Only works with full screen update + + if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT) + { + return; + } + + bufp = src_buffer; + screenp = (byte *) dest_buffer; + + for (y=0; y<SCREENHEIGHT; ++y) + { + WriteSquashedLine5x(screenp, bufp); + + screenp += dest_pitch * 5; + bufp += SCREENWIDTH; + } +} + +screen_mode_t mode_squash_5x = { + SCREENWIDTH_4_3 * 5, SCREENHEIGHT * 5, + I_InitStretchTables, + I_Squash5x, +}; + + diff --git a/src/i_scale.h b/src/i_scale.h index f4c7ff69..3553847f 100644 --- a/src/i_scale.h +++ b/src/i_scale.h @@ -30,24 +30,31 @@ #include "doomtype.h" -void I_InitStretchTables(byte *palette); void I_InitScale(byte *_src_buffer, byte *_dest_buffer, int _dest_pitch); -// Normal pixel-perfect doubling functions. +// Scaled modes (direct multiples of 320x200) -void I_Scale1x(int x1, int y1, int x2, int y2); -void I_Scale2x(int x1, int y1, int x2, int y2); -void I_Scale3x(int x1, int y1, int x2, int y2); -void I_Scale4x(int x1, int y1, int x2, int y2); -void I_Scale5x(int x1, int y1, int x2, int y2); +extern screen_mode_t mode_scale_1x; +extern screen_mode_t mode_scale_2x; +extern screen_mode_t mode_scale_3x; +extern screen_mode_t mode_scale_4x; +extern screen_mode_t mode_scale_5x; -// Aspect ratio correcting scale up functions +// Vertically stretched modes (320x200 -> multiples of 320x240) -void I_Stretch1x(int x1, int y1, int x2, int y2); -void I_Stretch2x(int x1, int y1, int x2, int y2); -void I_Stretch3x(int x1, int y1, int x2, int y2); -void I_Stretch4x(int x1, int y1, int x2, int y2); -void I_Stretch5x(int x1, int y1, int x2, int y2); +extern screen_mode_t mode_stretch_1x; +extern screen_mode_t mode_stretch_2x; +extern screen_mode_t mode_stretch_3x; +extern screen_mode_t mode_stretch_4x; +extern screen_mode_t mode_stretch_5x; + +// Horizontally squashed modes (320x200 -> multiples of 256x200) + +extern screen_mode_t mode_squash_1x; +extern screen_mode_t mode_squash_2x; +extern screen_mode_t mode_squash_3x; +extern screen_mode_t mode_squash_4x; +extern screen_mode_t mode_squash_5x; #endif /* #ifndef __I_SCALE__ */ diff --git a/src/i_video.c b/src/i_video.c index 2ab3dd98..22b4c98c 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -38,10 +38,11 @@ #include "doomstat.h" #include "d_main.h" #include "i_joystick.h" -#include "i_scale.h" #include "i_system.h" #include "i_swap.h" #include "i_timer.h" +#include "i_video.h" +#include "i_scale.h" #include "m_argv.h" #include "s_sound.h" #include "sounds.h" @@ -49,17 +50,35 @@ #include "w_wad.h" #include "z_zone.h" -enum -{ - FULLSCREEN_OFF, - FULLSCREEN_ON, +// Non aspect ratio-corrected modes (direct multiples of 320x200) + +static screen_mode_t *screen_modes[] = { + &mode_scale_1x, + &mode_scale_2x, + &mode_scale_3x, + &mode_scale_4x, + &mode_scale_5x, }; -enum -{ - RATIO_CORRECT_NONE, - RATIO_CORRECT_LETTERBOX, - RATIO_CORRECT_STRETCH, +// Aspect ratio corrected modes (4:3 ratio) + +static screen_mode_t *screen_modes_corrected[] = { + + // Vertically stretched modes (320x200 -> 320x240 and multiples) + + &mode_stretch_1x, + &mode_stretch_2x, + &mode_stretch_3x, + &mode_stretch_4x, + &mode_stretch_5x, + + // Horizontally squashed modes (320x200 -> 256x200 and multiples) + + &mode_squash_1x, + &mode_squash_2x, + &mode_squash_3x, + &mode_squash_4x, + &mode_squash_5x, }; extern void M_QuitDOOM(); @@ -71,6 +90,7 @@ char *video_driver = ""; static SDL_Surface *screen; // palette + static SDL_Color palette[256]; static boolean palette_to_set; @@ -89,6 +109,11 @@ extern int usemouse; static boolean native_surface; +// Screen width and height, from configuration file. + +int screen_width = SCREENWIDTH; +int screen_height = SCREENHEIGHT; + // Automatically adjust video settings if the selected mode is // not a valid video mode. @@ -96,11 +121,11 @@ int autoadjust_video_settings = 1; // Run in full screen mode? (int type for config code) -int fullscreen = FULLSCREEN_ON; +int fullscreen = true; // Aspect ratio correction mode -int aspect_ratio_correct = RATIO_CORRECT_NONE; +int aspect_ratio_correct = true; // Time to wait for the screen to settle on startup before starting the // game (ms) @@ -116,13 +141,6 @@ int grabmouse = true; boolean screenvisible; -// Blocky mode, -// replace each 320x200 pixel with screenmultiply*screenmultiply pixels. -// According to Dave Taylor, it still is a bonehead thing -// to use .... - -int screenmultiply = 1; - // disk image data and background overwritten by the disk to be // restored by EndRead @@ -135,6 +153,10 @@ static boolean window_focused; static SDL_Cursor *cursors[2]; +// The screen mode and scale functions being used + +static screen_mode_t *screen_mode; + // If true, keyboard mapping is ignored, like in Vanilla Doom. // The sensible thing to do is to disable this if you have a non-US // keyboard. @@ -168,7 +190,7 @@ static boolean MouseShouldBeGrabbed() // always grab the mouse when full screen (dont want to // see the mouse pointer) - if (fullscreen != FULLSCREEN_OFF) + if (fullscreen) return true; // Don't grab the mouse if mouse input is disabled @@ -624,72 +646,9 @@ static void BlitArea(int x1, int y1, int x2, int y2) return; } - if (aspect_ratio_correct == RATIO_CORRECT_LETTERBOX) - { - x_offset = (screen->w - SCREENWIDTH * screenmultiply) / 2; - y_offset = (screen->h - SCREENHEIGHT * screenmultiply) / 2; - } - else - { - x_offset = 0; - y_offset = 0; - } - - if (aspect_ratio_correct == RATIO_CORRECT_STRETCH) - { - if (screenmultiply == 1) - { - scale_function = I_Stretch1x; - } - else if (screenmultiply == 2) - { - scale_function = I_Stretch2x; - } - else if (screenmultiply == 3) - { - scale_function = I_Stretch3x; - } - else if (screenmultiply == 4) - { - scale_function = I_Stretch4x; - } - else if (screenmultiply == 5) - { - scale_function = I_Stretch5x; - } - else - { - I_Error("No aspect ratio stretching function for screenmultiply=%i", - screenmultiply); - return; - } - } else { - if (screenmultiply == 1) - { - scale_function = I_Scale1x; - } - else if (screenmultiply == 2) - { - scale_function = I_Scale2x; - } - else if (screenmultiply == 3) - { - scale_function = I_Scale3x; - } - else if (screenmultiply == 4) - { - scale_function = I_Scale4x; - } - else if (screenmultiply == 5) - { - scale_function = I_Scale5x; - } - else - { - I_Error("No scale function found!"); - return; - } - } + x_offset = (screen->w - screen_mode->width) / 2; + y_offset = (screen->h - screen_mode->height) / 2; + scale_function = screen_mode->DrawScreen; if (SDL_LockSurface(screen) >= 0) { @@ -710,11 +669,15 @@ static void UpdateRect(int x1, int y1, int x2, int y2) // Update the area +/* + TODO: fix loading disk + SDL_UpdateRect(screen, x1 * screenmultiply, y1 * screenmultiply, (x2-x1) * screenmultiply, (y2-y1) * screenmultiply); +*/ } void I_BeginRead(void) @@ -889,43 +852,6 @@ void I_SetWindowIcon(void) SDL_FreeSurface(surface); } -// Get window dimensions for the current settings - -static void GetWindowDimensions(int *windowwidth, int *windowheight) -{ - *windowwidth = SCREENWIDTH * screenmultiply; - - if (aspect_ratio_correct == RATIO_CORRECT_NONE) - *windowheight = SCREENHEIGHT * screenmultiply; - else - *windowheight = SCREENHEIGHT_4_3 * screenmultiply; -} - -// Check if the screen mode for the current settings is in the list available -// Not all machines support running in 320x200/640x400 (only support 4:3) -// Some don't even support modes below 640x480. - -static boolean CheckValidFSMode(void) -{ - SDL_Rect **modes; - int i; - int w, h; - - GetWindowDimensions(&w, &h); - - modes = SDL_ListModes(NULL, SDL_FULLSCREEN); - - for (i=0; modes[i]; ++i) - { - if (w == modes[i]->w && h == modes[i]->h) - return true; - } - - // not found - - return false; -} - static void CheckCommandLine(void) { //! @@ -961,7 +887,7 @@ static void CheckCommandLine(void) if (M_CheckParm("-window") || M_CheckParm("-nofullscreen")) { - fullscreen = FULLSCREEN_OFF; + fullscreen = false; } //! @@ -972,7 +898,7 @@ static void CheckCommandLine(void) if (M_CheckParm("-fullscreen")) { - fullscreen = FULLSCREEN_ON; + fullscreen = true; } //! @@ -983,138 +909,207 @@ static void CheckCommandLine(void) nomouse = M_CheckParm("-nomouse") > 0; - // 2x, 3x, 4x, 5x scale mode - - //! - // @category video - // - // Don't scale up the screen. - // +} + +// Pick the modes list to use: - if (M_CheckParm("-1")) +static void GetScreenModes(screen_mode_t ***modes_list, int *num_modes) +{ + if (aspect_ratio_correct) { - screenmultiply = 1; + *modes_list = screen_modes_corrected; + *num_modes = arrlen(screen_modes_corrected); } - - //! - // @category video - // - // Double up the screen to 2x its size. - // - - if (M_CheckParm("-2")) + else { - screenmultiply = 2; + *modes_list = screen_modes; + *num_modes = arrlen(screen_modes); } +} - //! - // @category video - // - // Double up the screen to 3x its size. - // +// Find which screen_mode_t to use for the given width and height. - if (M_CheckParm("-3")) - { - screenmultiply = 3; - } +static screen_mode_t *I_FindScreenMode(int w, int h) +{ + screen_mode_t **modes_list; + screen_mode_t *best_mode; + int modes_list_length; + int num_pixels; + int best_num_pixels; + int i; - //! - // @category video - // - // Double up the screen to 4x its size. - // + // Special case: 320x200 and 640x400 are available even if aspect + // ratio correction is turned on. These modes have non-square + // pixels. - if (M_CheckParm("-4")) + if (w == SCREENWIDTH && h == SCREENHEIGHT) { - screenmultiply = 4; + return &mode_scale_1x; } - - //! - // @category video - // - // Double up the screen to 5x its size. - // - - if (M_CheckParm("-5")) + else if (w == SCREENWIDTH*2 && h == SCREENHEIGHT*2) { - screenmultiply = 5; + return &mode_scale_2x; } - if (screenmultiply < 1) - screenmultiply = 1; - if (screenmultiply > 5) - screenmultiply = 5; -} + GetScreenModes(&modes_list, &modes_list_length); -static void AutoAdjustSettings(void) -{ - int oldw, oldh; - int old_ratio, old_screenmultiply; + // Find the biggest screen_mode_t in the list that fits within these + // dimensions - GetWindowDimensions(&oldw, &oldh); - old_screenmultiply = screenmultiply; - old_ratio = aspect_ratio_correct; + best_mode = NULL; + best_num_pixels = 0; - if (!CheckValidFSMode() && screenmultiply == 1 - && fullscreen == FULLSCREEN_ON - && aspect_ratio_correct == RATIO_CORRECT_NONE) + for (i=0; i<modes_list_length; ++i) { - // 320x200 is not valid. + // Will this fit within the dimensions? If not, ignore. - // Try turning on letterbox mode - avoid doubling up - // the screen if possible + if (modes_list[i]->width > w || modes_list[i]->height > h) + { + continue; + } - aspect_ratio_correct = RATIO_CORRECT_LETTERBOX; + num_pixels = modes_list[i]->width * modes_list[i]->height; - if (!CheckValidFSMode()) + if (num_pixels > best_num_pixels) { - // That doesn't work. Change it back. + // This is a better mode than the current one - aspect_ratio_correct = RATIO_CORRECT_NONE; + best_mode = modes_list[i]; + best_num_pixels = num_pixels; } } - if (!CheckValidFSMode() && screenmultiply == 1) - { - // Try doubling up the screen to 640x400 + return best_mode; +} - screenmultiply = 2; - } +// If the video mode set in the configuration file is not available, +// try to choose a different mode. - if (!CheckValidFSMode() - && fullscreen == FULLSCREEN_ON - && aspect_ratio_correct == RATIO_CORRECT_NONE) +static void I_AutoAdjustSettings(void) +{ + if (fullscreen) { - // This is not a valid mode. Try turning on letterbox mode + SDL_Rect **modes; + SDL_Rect *best_mode; + screen_mode_t *screen_mode; + int num_pixels, best_num_pixels; + int i; - aspect_ratio_correct = RATIO_CORRECT_LETTERBOX; - } + modes = SDL_ListModes(NULL, SDL_FULLSCREEN); + + // Find the best mode that matches the mode specified in the + // configuration file + + best_mode = NULL; + best_num_pixels = INT_MAX; + + for (i=0; modes[i] != NULL; ++i) + { + //printf("%ix%i?\n", modes[i]->w, modes[i]->h); + + // What screen_mode_t would be used for this video mode? + + screen_mode = I_FindScreenMode(modes[i]->w, modes[i]->h); + + // Never choose a screen mode that we cannot run in, or + // is poor quality for fullscreen + + if (screen_mode == NULL || screen_mode->poor_quality) + { + // printf("\tUnsupported / poor quality\n"); + continue; + } + + // Do we have the exact mode? + // If so, no autoadjust needed + + if (screen_width == modes[i]->w && screen_height == modes[i]->h) + { + // printf("\tExact mode!\n"); + return; + } + + // Only use modes bigger than the specified mode + + if (modes[i]->w < screen_width || modes[i]->h < screen_height) + { + // printf("\t< %ix%i\n", screen_width, screen_height); + continue; + } + + // Is this mode better than the current mode? + + num_pixels = modes[i]->w * modes[i]->h; + + if (num_pixels < best_num_pixels) + { + // printf("\tA valid mode\n"); + best_num_pixels = num_pixels; + best_mode = modes[i]; + } + } + + if (best_mode == NULL) + { + // Unable to find a valid mode! + + if (screen_width <= SCREENWIDTH && screen_height <= SCREENHEIGHT) + { + I_Error("Unable to find any valid video mode at all!"); + } + + // Reset back to the original defaults and try to find a + // mode + + screen_width = SCREENWIDTH; + screen_height = SCREENHEIGHT; + + I_AutoAdjustSettings(); + + return; + } + + printf("I_InitGraphics: %ix%i mode not supported on this machine.\n", + screen_width, screen_height); + + screen_width = best_mode->w; + screen_height = best_mode->h; - if (old_ratio != aspect_ratio_correct - || old_screenmultiply != screenmultiply) - { - printf("I_InitGraphics: %ix%i resolution is not supported " - "on this machine. \n", oldw, oldh); - printf("I_InitGraphics: Video settings adjusted to " - "compensate:\n"); - - if (old_ratio != aspect_ratio_correct) - printf("\tletterbox mode on (aspect_ratio_correct=%i)\n", - aspect_ratio_correct); - if (screenmultiply != old_screenmultiply) - printf("\tscreenmultiply=%i\n", screenmultiply); - - printf("NOTE: Your video settings have been adjusted. " - "To disable this behavior,\n" - "set autoadjust_video_settings to 0 in your " - "configuration file.\n"); } - - if (!CheckValidFSMode()) + else { - printf("I_InitGraphics: WARNING: Unable to find a valid " - "fullscreen video mode to run in.\n"); + screen_mode_t *best_mode; + + // + // Windowed mode. + // + // Find a screen_mode_t to fit within the current settings + // + + best_mode = I_FindScreenMode(screen_width, screen_height); + + // Do we have the exact mode already? + + if (best_mode->width == screen_width + && best_mode->height == screen_height) + { + return; + } + + printf("I_InitGraphics: Cannot run at specified mode: %ix%i\n", + screen_width, screen_height); + + screen_width = best_mode->width; + screen_height = best_mode->height; } + + printf("I_InitGraphics: Auto-adjusted to %ix%i.\n", + screen_width, screen_height); + + printf("NOTE: Your video settings have been adjusted. " + "To disable this behavior,\n" + "set autoadjust_video_settings to 0 in your " + "configuration file.\n"); } // Check if we have been invoked as a screensaver by xscreensaver. @@ -1131,24 +1126,6 @@ void I_CheckIsScreensaver(void) } } -// In screensaver mode, pick a screenmultiply value that fits -// inside the screen. It is okay to do this because settings -// are not saved in screensaver mode. - -static void FindScreensaverMultiply(void) -{ - int i; - - for (i=1; i<=4; ++i) - { - if (SCREENWIDTH * i <= screen->w - && SCREENHEIGHT * i <= screen->h) - { - screenmultiply = i; - } - } -} - static void CreateCursors(void) { static Uint8 empty_cursor_data = 0; @@ -1245,47 +1222,56 @@ void I_InitGraphics(void) CheckCommandLine(); - // Don't allow letterbox mode when windowed - - if (!fullscreen && aspect_ratio_correct == RATIO_CORRECT_LETTERBOX) + doompal = W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE); + + if (screensaver_mode) { - aspect_ratio_correct = RATIO_CORRECT_NONE; + windowwidth = 0; + windowheight = 0; } - - if (fullscreen && autoadjust_video_settings) + else { - // Check that the fullscreen mode we are trying to use is valid; - // if not, try to automatically select a more appropriate one. + if (autoadjust_video_settings) + { + I_AutoAdjustSettings(); + } - AutoAdjustSettings(); - } + windowwidth = screen_width; + windowheight = screen_height; - // Generate lookup tables before setting the video mode. + screen_mode = I_FindScreenMode(windowwidth, windowheight); - doompal = W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE); + if (screen_mode == NULL) + { + I_Error("I_InitGraphics: Unable to find a screen mode small " + "enough for %ix%i", windowwidth, windowheight); + } - if (aspect_ratio_correct == RATIO_CORRECT_STRETCH) - { - I_InitStretchTables(doompal); + if (windowwidth != screen_mode->width + || windowheight != screen_mode->height) + { + printf("I_InitGraphics: Letterboxed (%ix%i within %ix%i)\n", + screen_mode->width, screen_mode->height, + windowwidth, windowheight); + } + + // Generate lookup tables before setting the video mode. + + if (screen_mode->InitMode != NULL) + { + screen_mode->InitMode(doompal); + } } // Set the video mode. - GetWindowDimensions(&windowwidth, &windowheight); - flags |= SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF; - if (fullscreen != FULLSCREEN_OFF) + if (fullscreen) { flags |= SDL_FULLSCREEN; } - if (screensaver_mode) - { - windowwidth = 0; - windowheight = 0; - } - screen = SDL_SetVideoMode(windowwidth, windowheight, 8, flags); if (screen == NULL) @@ -1293,14 +1279,6 @@ void I_InitGraphics(void) I_Error("Error setting video mode: %s\n", SDL_GetError()); } - // In screensaver mode, screenmultiply as large as possible - // and set a blank cursor. - - if (screensaver_mode) - { - FindScreensaverMultiply(); - } - // Start with a clear black screen // (screen will be flipped after we set the palette) @@ -1316,7 +1294,7 @@ void I_InitGraphics(void) SDL_UnlockSurface(screen); } - + // Set the palette I_SetPalette(doompal); @@ -1332,6 +1310,26 @@ void I_InitGraphics(void) UpdateFocus(); UpdateGrab(); + // In screensaver mode, now find a screen_mode to use. + + if (screensaver_mode) + { + screen_mode = I_FindScreenMode(screen->w, screen->h); + + if (screen_mode == NULL) + { + I_Error("I_InitGraphics: Unable to find a screen mode small " + "enough for %ix%i", screen->w, screen->h); + } + + // Generate lookup tables before setting the video mode. + + if (screen_mode->InitMode != NULL) + { + screen_mode->InitMode(doompal); + } + } + // On some systems, it takes a second or so for the screen to settle // after changing modes. We include the option to add a delay when // setting the screen mode, so that the game doesn't start immediately @@ -1348,36 +1346,33 @@ void I_InitGraphics(void) // If we have to multiply, drawing is done to a separate 320x200 buf native_surface = !SDL_MUSTLOCK(screen) - && screenmultiply == 1 + && screen_mode == &mode_scale_1x && screen->pitch == SCREENWIDTH - && (aspect_ratio_correct == RATIO_CORRECT_NONE - || aspect_ratio_correct == RATIO_CORRECT_LETTERBOX); + && aspect_ratio_correct; // If not, allocate a buffer and copy from that buffer to the // screen when we do an update if (native_surface) { - screens[0] = (unsigned char *) (screen->pixels); + screens[0] = (unsigned char *) screen->pixels; - if (aspect_ratio_correct == RATIO_CORRECT_LETTERBOX) - { - screens[0] += ((SCREENHEIGHT_4_3 - SCREENHEIGHT) * screen->pitch) / 2; - } + screens[0] += (screen->h - SCREENHEIGHT) / 2; } else { - screens[0] = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); + screens[0] = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT, + PU_STATIC, NULL); + + // Clear the screen to black. + + memset(screens[0], 0, SCREENWIDTH * SCREENHEIGHT); } // "Loading from disk" icon LoadDiskImage(); - // Clear the screen to black. - - memset(screens[0], 0, SCREENWIDTH * SCREENHEIGHT); - // We need SDL to give us translated versions of keys as well SDL_EnableUNICODE(1); diff --git a/src/i_video.h b/src/i_video.h index 2eeb8343..99107433 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -31,7 +31,30 @@ #include "doomtype.h" +typedef struct +{ + // Screen width and height + int width; + int height; + + // Initialisation function to call when using this mode. + // Called with a pointer to the Doom palette. + // + // If NULL, no init function is called. + + void (*InitMode)(byte *palette); + + // Function to call to draw the screen from the source buffer. + + void (*DrawScreen)(int x1, int y1, int x2, int y2); + + // If true, this is a "poor quality" mode. The autoadjust + // code should always attempt to use a different mode to this + // mode in fullscreen. + + boolean poor_quality; +} screen_mode_t; // Called by D_DoomMain, // determines the hardware configuration @@ -63,13 +86,14 @@ void I_CheckIsScreensaver(void); extern char *video_driver; extern int autoadjust_video_settings; extern boolean screenvisible; -extern int screenmultiply; +extern int screen_width, screen_height; extern int fullscreen; extern int aspect_ratio_correct; -extern boolean grabmouse; +extern int grabmouse; extern float mouse_acceleration; extern int mouse_threshold; extern int startup_delay; extern int vanilla_keyboard_mapping; #endif + diff --git a/src/m_misc.c b/src/m_misc.c index 3181be5d..9601b0de 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -415,7 +415,8 @@ static default_t extra_defaults_list[] = {"fullscreen", &fullscreen, DEFAULT_INT, 0, 0}, {"aspect_ratio_correct", &aspect_ratio_correct, DEFAULT_INT, 0, 0}, {"startup_delay", &startup_delay, DEFAULT_INT, 0, 0}, - {"screenmultiply", &screenmultiply, DEFAULT_INT, 0, 0}, + {"screen_width", &screen_width, DEFAULT_INT, 0, 0}, + {"screen_height", &screen_height, DEFAULT_INT, 0, 0}, {"grabmouse", &grabmouse, DEFAULT_INT, 0, 0}, {"novert", &novert, DEFAULT_INT, 0, 0}, {"mouse_acceleration", &mouse_acceleration, DEFAULT_FLOAT, 0, 0}, |