summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/i_scale.c80
-rw-r--r--src/i_video.c384
-rw-r--r--src/i_video.h3
3 files changed, 309 insertions, 158 deletions
diff --git a/src/i_scale.c b/src/i_scale.c
index e320e1cb..a42409e8 100644
--- a/src/i_scale.c
+++ b/src/i_scale.c
@@ -72,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)
-static void I_Scale1x(int x1, int y1, int x2, int y2)
+static boolean I_Scale1x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp;
int y;
@@ -89,6 +89,8 @@ static void I_Scale1x(int x1, int y1, int x2, int y2)
screenp += dest_pitch;
bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_scale_1x = {
@@ -99,7 +101,7 @@ screen_mode_t mode_scale_1x = {
// 2x scale (640x400)
-static void I_Scale2x(int x1, int y1, int x2, int y2)
+static boolean I_Scale2x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp, *screenp2;
int x, y;
@@ -127,6 +129,8 @@ static void I_Scale2x(int x1, int y1, int x2, int y2)
screenp2 += multi_pitch;
bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_scale_2x = {
@@ -137,7 +141,7 @@ screen_mode_t mode_scale_2x = {
// 3x scale (960x600)
-static void I_Scale3x(int x1, int y1, int x2, int y2)
+static boolean I_Scale3x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp, *screenp2, *screenp3;
int x, y;
@@ -169,6 +173,8 @@ static void I_Scale3x(int x1, int y1, int x2, int y2)
screenp3 += multi_pitch;
bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_scale_3x = {
@@ -179,7 +185,7 @@ screen_mode_t mode_scale_3x = {
// 4x scale (1280x800)
-static void I_Scale4x(int x1, int y1, int x2, int y2)
+static boolean I_Scale4x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp, *screenp2, *screenp3, *screenp4;
int x, y;
@@ -215,6 +221,8 @@ static void I_Scale4x(int x1, int y1, int x2, int y2)
screenp4 += multi_pitch;
bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_scale_4x = {
@@ -225,7 +233,7 @@ screen_mode_t mode_scale_4x = {
// 5x scale (1600x1000)
-static void I_Scale5x(int x1, int y1, int x2, int y2)
+static boolean I_Scale5x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp, *screenp2, *screenp3, *screenp4, *screenp5;
int x, y;
@@ -265,6 +273,8 @@ static void I_Scale5x(int x1, int y1, int x2, int y2)
screenp5 += multi_pitch;
bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_scale_5x = {
@@ -396,7 +406,7 @@ static inline void WriteBlendedLine1x(byte *dest, byte *src1, byte *src2,
// 1x stretch (320x240)
-static void I_Stretch1x(int x1, int y1, int x2, int y2)
+static boolean I_Stretch1x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp;
int y;
@@ -405,7 +415,7 @@ static void I_Stretch1x(int x1, int y1, int x2, int y2)
if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
{
- return;
+ return false;
}
// Need to byte-copy from buffer into the screen buffer
@@ -442,6 +452,8 @@ static void I_Stretch1x(int x1, int y1, int x2, int y2)
memcpy(screenp, bufp, SCREENWIDTH);
screenp += dest_pitch; bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_stretch_1x = {
@@ -483,7 +495,7 @@ static inline void WriteBlendedLine2x(byte *dest, byte *src1, byte *src2,
// 2x stretch (640x480)
-static void I_Stretch2x(int x1, int y1, int x2, int y2)
+static boolean I_Stretch2x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp;
int y;
@@ -492,7 +504,7 @@ static void I_Stretch2x(int x1, int y1, int x2, int y2)
if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
{
- return;
+ return false;
}
// Need to byte-copy from buffer into the screen buffer
@@ -553,6 +565,8 @@ static void I_Stretch2x(int x1, int y1, int x2, int y2)
WriteLine2x(screenp, bufp);
screenp += dest_pitch; bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_stretch_2x = {
@@ -595,7 +609,7 @@ static inline void WriteBlendedLine3x(byte *dest, byte *src1, byte *src2,
// 3x stretch (960x720)
-static void I_Stretch3x(int x1, int y1, int x2, int y2)
+static boolean I_Stretch3x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp;
int y;
@@ -604,7 +618,7 @@ static void I_Stretch3x(int x1, int y1, int x2, int y2)
if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
{
- return;
+ return false;
}
// Need to byte-copy from buffer into the screen buffer
@@ -689,6 +703,8 @@ static void I_Stretch3x(int x1, int y1, int x2, int y2)
WriteLine3x(screenp, bufp);
screenp += dest_pitch; bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_stretch_3x = {
@@ -733,7 +749,7 @@ static inline void WriteBlendedLine4x(byte *dest, byte *src1, byte *src2,
// 4x stretch (1280x960)
-static void I_Stretch4x(int x1, int y1, int x2, int y2)
+static boolean I_Stretch4x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp;
int y;
@@ -742,7 +758,7 @@ static void I_Stretch4x(int x1, int y1, int x2, int y2)
if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
{
- return;
+ return false;
}
// Need to byte-copy from buffer into the screen buffer
@@ -851,6 +867,8 @@ static void I_Stretch4x(int x1, int y1, int x2, int y2)
WriteLine4x(screenp, bufp);
screenp += dest_pitch; bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_stretch_4x = {
@@ -877,7 +895,7 @@ static inline void WriteLine5x(byte *dest, byte *src)
// 5x stretch (1600x1200)
-static void I_Stretch5x(int x1, int y1, int x2, int y2)
+static boolean I_Stretch5x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp;
int y;
@@ -886,7 +904,7 @@ static void I_Stretch5x(int x1, int y1, int x2, int y2)
if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
{
- return;
+ return false;
}
// Need to byte-copy from buffer into the screen buffer
@@ -923,6 +941,8 @@ static void I_Stretch5x(int x1, int y1, int x2, int y2)
WriteLine5x(screenp, bufp);
screenp += dest_pitch; bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_stretch_5x = {
@@ -978,7 +998,7 @@ static inline void WriteSquashedLine1x(byte *dest, byte *src)
// 1x squashed (256x200)
-static void I_Squash1x(int x1, int y1, int x2, int y2)
+static boolean I_Squash1x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp;
int y;
@@ -987,7 +1007,7 @@ static void I_Squash1x(int x1, int y1, int x2, int y2)
if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
{
- return;
+ return false;
}
bufp = src_buffer;
@@ -1000,6 +1020,8 @@ static void I_Squash1x(int x1, int y1, int x2, int y2)
screenp += dest_pitch;
bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_squash_1x = {
@@ -1075,7 +1097,7 @@ static inline void WriteSquashedLine2x(byte *dest, byte *src)
// 2x squash (512x400)
-static void I_Squash2x(int x1, int y1, int x2, int y2)
+static boolean I_Squash2x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp;
int y;
@@ -1084,7 +1106,7 @@ static void I_Squash2x(int x1, int y1, int x2, int y2)
if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
{
- return;
+ return false;
}
bufp = src_buffer;
@@ -1097,6 +1119,8 @@ static void I_Squash2x(int x1, int y1, int x2, int y2)
screenp += dest_pitch * 2;
bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_squash_2x = {
@@ -1155,7 +1179,7 @@ static inline void WriteSquashedLine3x(byte *dest, byte *src)
// exactly.
//
-static void I_Squash3x(int x1, int y1, int x2, int y2)
+static boolean I_Squash3x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp;
int y;
@@ -1164,7 +1188,7 @@ static void I_Squash3x(int x1, int y1, int x2, int y2)
if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
{
- return;
+ return false;
}
bufp = src_buffer;
@@ -1177,6 +1201,8 @@ static void I_Squash3x(int x1, int y1, int x2, int y2)
screenp += dest_pitch * 3;
bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_squash_3x = {
@@ -1263,7 +1289,7 @@ static inline void WriteSquashedLine4x(byte *dest, byte *src)
// 4x squashed (1024x800)
//
-static void I_Squash4x(int x1, int y1, int x2, int y2)
+static boolean I_Squash4x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp;
int y;
@@ -1272,7 +1298,7 @@ static void I_Squash4x(int x1, int y1, int x2, int y2)
if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
{
- return;
+ return false;
}
bufp = src_buffer;
@@ -1285,6 +1311,8 @@ static void I_Squash4x(int x1, int y1, int x2, int y2)
screenp += dest_pitch * 4;
bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_squash_4x = {
@@ -1325,7 +1353,7 @@ static inline void WriteSquashedLine5x(byte *dest, byte *src)
// 5x squashed (1280x1000)
//
-static void I_Squash5x(int x1, int y1, int x2, int y2)
+static boolean I_Squash5x(int x1, int y1, int x2, int y2)
{
byte *bufp, *screenp;
int y;
@@ -1334,7 +1362,7 @@ static void I_Squash5x(int x1, int y1, int x2, int y2)
if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
{
- return;
+ return false;
}
bufp = src_buffer;
@@ -1347,6 +1375,8 @@ static void I_Squash5x(int x1, int y1, int x2, int y2)
screenp += dest_pitch * 5;
bufp += SCREENWIDTH;
}
+
+ return true;
}
screen_mode_t mode_squash_5x = {
diff --git a/src/i_video.c b/src/i_video.c
index 0d1b612b..568f0f7d 100644
--- a/src/i_video.c
+++ b/src/i_video.c
@@ -635,20 +635,23 @@ static void UpdateGrab(void)
// Update a small portion of the screen
//
// Does stretching and buffer blitting if neccessary
+//
+// Return true if blit was successful.
-static void BlitArea(int x1, int y1, int x2, int y2)
+static boolean BlitArea(int x1, int y1, int x2, int y2)
{
- void (*scale_function)(int x1, int y1, int x2, int y2);
int x_offset, y_offset;
+ boolean result;
+
+ // No blit needed on native surface
if (native_surface)
{
- return;
+ return true;
}
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)
{
@@ -656,28 +659,37 @@ static void BlitArea(int x1, int y1, int x2, int y2)
(byte *) screen->pixels + (y_offset * screen->pitch)
+ x_offset,
screen->pitch);
- scale_function(x1, y1, x2, y2);
+ result = screen_mode->DrawScreen(x1, y1, x2, y2);
SDL_UnlockSurface(screen);
}
+ else
+ {
+ result = false;
+ }
+
+ return result;
}
static void UpdateRect(int x1, int y1, int x2, int y2)
{
- // Do stretching and blitting
+ int x1_scaled, x2_scaled, y1_scaled, y2_scaled;
- BlitArea(x1, y1, x2, y2);
+ // Do stretching and blitting
- // Update the area
+ if (BlitArea(x1, y1, x2, y2))
+ {
+ // Update the area
-/*
- TODO: fix loading disk
+ x1_scaled = (x1 * screen_mode->width) / SCREENWIDTH;
+ y1_scaled = (y1 * screen_mode->height) / SCREENHEIGHT;
+ x2_scaled = (x2 * screen_mode->width) / SCREENWIDTH;
+ y2_scaled = (y2 * screen_mode->height) / SCREENHEIGHT;
- SDL_UpdateRect(screen,
- x1 * screenmultiply,
- y1 * screenmultiply,
- (x2-x1) * screenmultiply,
- (y2-y1) * screenmultiply);
-*/
+ SDL_UpdateRect(screen,
+ x1_scaled, y1_scaled,
+ x2_scaled - x1_scaled,
+ y2_scaled - y1_scaled);
+ }
}
void I_BeginRead(void)
@@ -852,92 +864,6 @@ void I_SetWindowIcon(void)
SDL_FreeSurface(surface);
}
-static void CheckCommandLine(void)
-{
- int i;
-
- //!
- // @category video
- //
- // Grab the mouse when running in windowed mode.
- //
-
- if (M_CheckParm("-grabmouse"))
- {
- grabmouse = true;
- }
-
- //!
- // @category video
- //
- // Don't grab the mouse when running in windowed mode.
- //
-
- if (M_CheckParm("-nograbmouse"))
- {
- grabmouse = false;
- }
-
- // default to fullscreen mode, allow override with command line
- // nofullscreen because we love prboom
-
- //!
- // @category video
- //
- // Run in a window.
- //
-
- if (M_CheckParm("-window") || M_CheckParm("-nofullscreen"))
- {
- fullscreen = false;
- }
-
- //!
- // @category video
- //
- // Run in fullscreen mode.
- //
-
- if (M_CheckParm("-fullscreen"))
- {
- fullscreen = true;
- }
-
- //!
- // @category video
- //
- // Disable the mouse.
- //
-
- nomouse = M_CheckParm("-nomouse") > 0;
-
- //!
- // @category video
- //
- // Specify the screen width, in pixels.
- //
-
- i = M_CheckParm("-width");
-
- if (i > 0)
- {
- screen_width = atoi(myargv[i + 1]);
- }
-
- //!
- // @category video
- //
- // Specify the screen height, in pixels.
- //
-
- i = M_CheckParm("-height");
-
- if (i > 0)
- {
- screen_height = atoi(myargv[i + 1]);
- }
-}
-
// Pick the modes list to use:
static void GetScreenModes(screen_mode_t ***modes_list, int *num_modes)
@@ -969,13 +895,16 @@ static screen_mode_t *I_FindScreenMode(int w, int h)
// ratio correction is turned on. These modes have non-square
// pixels.
- if (w == SCREENWIDTH && h == SCREENHEIGHT)
- {
- return &mode_scale_1x;
- }
- else if (w == SCREENWIDTH*2 && h == SCREENHEIGHT*2)
+ if (fullscreen)
{
- return &mode_scale_2x;
+ if (w == SCREENWIDTH && h == SCREENHEIGHT)
+ {
+ return &mode_scale_1x;
+ }
+ else if (w == SCREENWIDTH*2 && h == SCREENHEIGHT*2)
+ {
+ return &mode_scale_2x;
+ }
}
GetScreenModes(&modes_list, &modes_list_length);
@@ -1019,7 +948,7 @@ static void I_AutoAdjustSettings(void)
SDL_Rect **modes;
SDL_Rect *best_mode;
screen_mode_t *screen_mode;
- int num_pixels, best_num_pixels;
+ int target_pixels, num_pixels, best_num_pixels;
int i;
modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
@@ -1029,6 +958,7 @@ static void I_AutoAdjustSettings(void)
best_mode = NULL;
best_num_pixels = INT_MAX;
+ target_pixels = screen_width * screen_height;
for (i=0; modes[i] != NULL; ++i)
{
@@ -1056,19 +986,12 @@ static void I_AutoAdjustSettings(void)
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)
+ if (abs(num_pixels - target_pixels)
+ < abs(best_num_pixels - target_pixels))
{
// printf("\tA valid mode\n");
best_num_pixels = num_pixels;
@@ -1080,20 +1003,7 @@ static void I_AutoAdjustSettings(void)
{
// 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;
+ I_Error("Unable to find any valid video mode at all!");
}
printf("I_InitGraphics: %ix%i mode not supported on this machine.\n",
@@ -1115,6 +1025,14 @@ static void I_AutoAdjustSettings(void)
best_mode = I_FindScreenMode(screen_width, screen_height);
+ if (best_mode == NULL)
+ {
+ // Nothing fits within the current settings.
+ // Pick the closest to 320x200 possible.
+
+ best_mode = I_FindScreenMode(SCREENWIDTH, SCREENHEIGHT_4_3);
+ }
+
// Do we have the exact mode already?
if (best_mode->width == screen_width
@@ -1139,6 +1057,208 @@ static void I_AutoAdjustSettings(void)
"configuration file.\n");
}
+// Set video size to a particular scale factor (1x, 2x, 3x, etc.)
+
+static void SetScaleFactor(int factor)
+{
+ if (fullscreen)
+ {
+ // In fullscreen, find a mode that will provide this scale factor
+
+ SDL_Rect **modes;
+ SDL_Rect *best_mode;
+ screen_mode_t *scrmode;
+ int best_num_pixels, num_pixels;
+ int i;
+
+ modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
+
+ best_mode = NULL;
+ best_num_pixels = INT_MAX;
+
+ for (i=0; modes[i] != NULL; ++i)
+ {
+ // What screen_mode_t will this use?
+
+ scrmode = I_FindScreenMode(modes[i]->w, modes[i]->h);
+
+ if (scrmode == NULL)
+ {
+ continue;
+ }
+
+ // Only choose modes that fit the requested scale factor.
+ //
+ // Note that this allows 320x240 as valid for 1x scale, as
+ // 240/200 is rounded down to 1 by integer division.
+
+ if ((scrmode->width / SCREENWIDTH) != factor
+ || (scrmode->height / SCREENHEIGHT) != factor)
+ {
+ continue;
+ }
+
+ // Is this a better mode than what we currently have?
+
+ num_pixels = modes[i]->w * modes[i]->h;
+
+ if (num_pixels < best_num_pixels)
+ {
+ best_num_pixels = num_pixels;
+ best_mode = modes[i];
+ }
+ }
+
+ if (best_mode == NULL)
+ {
+ I_Error("No fullscreen graphics mode available to support "
+ "%ix scale factor!", factor);
+ }
+
+ screen_width = best_mode->w;
+ screen_height = best_mode->h;
+ }
+ else
+ {
+ int w, h;
+
+ // Pick 320x200 or 320x240, depending on aspect ratio correct
+
+ if (aspect_ratio_correct)
+ {
+ w = SCREENWIDTH;
+ h = SCREENHEIGHT_4_3;
+ }
+ else
+ {
+ w = SCREENWIDTH;
+ h = SCREENHEIGHT;
+ }
+
+ screen_width = w * factor;
+ screen_height = h * factor;
+ }
+}
+
+static void CheckCommandLine(void)
+{
+ int i;
+
+ //!
+ // @category video
+ //
+ // Grab the mouse when running in windowed mode.
+ //
+
+ if (M_CheckParm("-grabmouse"))
+ {
+ grabmouse = true;
+ }
+
+ //!
+ // @category video
+ //
+ // Don't grab the mouse when running in windowed mode.
+ //
+
+ if (M_CheckParm("-nograbmouse"))
+ {
+ grabmouse = false;
+ }
+
+ // default to fullscreen mode, allow override with command line
+ // nofullscreen because we love prboom
+
+ //!
+ // @category video
+ //
+ // Run in a window.
+ //
+
+ if (M_CheckParm("-window") || M_CheckParm("-nofullscreen"))
+ {
+ fullscreen = false;
+ }
+
+ //!
+ // @category video
+ //
+ // Run in fullscreen mode.
+ //
+
+ if (M_CheckParm("-fullscreen"))
+ {
+ fullscreen = true;
+ }
+
+ //!
+ // @category video
+ //
+ // Disable the mouse.
+ //
+
+ nomouse = M_CheckParm("-nomouse") > 0;
+
+ //!
+ // @category video
+ //
+ // Specify the screen width, in pixels.
+ //
+
+ i = M_CheckParm("-width");
+
+ if (i > 0)
+ {
+ screen_width = atoi(myargv[i + 1]);
+ }
+
+ //!
+ // @category video
+ //
+ // Specify the screen height, in pixels.
+ //
+
+ i = M_CheckParm("-height");
+
+ if (i > 0)
+ {
+ screen_height = atoi(myargv[i + 1]);
+ }
+
+ //!
+ // @category video
+ //
+ // Don't scale up the screen.
+ //
+
+ if (M_CheckParm("-1"))
+ {
+ SetScaleFactor(1);
+ }
+
+ //!
+ // @category video
+ //
+ // Double up the screen to 2x its normal size.
+ //
+
+ if (M_CheckParm("-2"))
+ {
+ SetScaleFactor(2);
+ }
+
+ //!
+ // @category video
+ //
+ // Double up the screen to 3x its normal size.
+ //
+
+ if (M_CheckParm("-3"))
+ {
+ SetScaleFactor(3);
+ }
+}
+
// Check if we have been invoked as a screensaver by xscreensaver.
void I_CheckIsScreensaver(void)
diff --git a/src/i_video.h b/src/i_video.h
index 99107433..bd5de24a 100644
--- a/src/i_video.h
+++ b/src/i_video.h
@@ -46,8 +46,9 @@ typedef struct
void (*InitMode)(byte *palette);
// Function to call to draw the screen from the source buffer.
+ // Return true if draw was successful.
- void (*DrawScreen)(int x1, int y1, int x2, int y2);
+ boolean (*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