summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimon Howard2008-01-20 04:47:52 +0000
committerSimon Howard2008-01-20 04:47:52 +0000
commit142a9488ad2e782d3d699b4f9b2902ffe26aeaa2 (patch)
tree766d38e08a38d95e9cfe794d078f60926c7440b4 /src
parent6805e192226d33c6431b1aaf60e84e1b5ea6f707 (diff)
downloadchocolate-doom-142a9488ad2e782d3d699b4f9b2902ffe26aeaa2.tar.gz
chocolate-doom-142a9488ad2e782d3d699b4f9b2902ffe26aeaa2.tar.bz2
chocolate-doom-142a9488ad2e782d3d699b4f9b2902ffe26aeaa2.zip
Refactor the video mode configuration system.
The previous system was built around the program choosing a screen mode from the user's settings, this is based around choosing settings from the specified screen mode. As such, the old screenmultiply config variable is now gone. Also, aspect ratio correction is now on by default. Add new aspect ratio correction functions for horizontal squashing (as a complement to the existing vertical stretching). Subversion-branch: /trunk/chocolate-doom Subversion-revision: 1005
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},