summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/doomdef.h7
-rw-r--r--src/i_scale.c561
-rw-r--r--src/i_scale.h33
-rw-r--r--src/i_video.c569
-rw-r--r--src/i_video.h28
-rw-r--r--src/m_misc.c3
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},