diff --git a/src/rendering/r_videoscale.cpp b/src/rendering/r_videoscale.cpp index e1f384d5c9..23e38d8f11 100644 --- a/src/rendering/r_videoscale.cpp +++ b/src/rendering/r_videoscale.cpp @@ -56,16 +56,16 @@ namespace { bool isValid; bool isLinear; - uint32_t(*GetScaledWidth)(uint32_t Width); - uint32_t(*GetScaledHeight)(uint32_t Height); + uint32_t(*GetScaledWidth)(uint32_t Width, uint32_t Height); + uint32_t(*GetScaledHeight)(uint32_t Width, uint32_t Height); bool isScaled43; bool isCustom; }; - float v_MinimumToFill() + float v_MinimumToFill(uint32_t inwidth, uint32_t inheight) { // sx = screen x dimension, sy = same for y - float sx = (float)screen->GetClientWidth(), sy = (float)screen->GetClientHeight(); + float sx = (float)inwidth, sy = (float)inheight; static float lastsx = 0., lastsy = 0., result = 0.; if (lastsx != sx || lastsy != sy) { @@ -79,25 +79,25 @@ namespace } return result; } - inline uint32_t v_mfillX() + inline uint32_t v_mfillX(uint32_t inwidth, uint32_t inheight) { - return screen ? (uint32_t)((float)screen->GetClientWidth() * v_MinimumToFill()) : 640; + return (uint32_t)((float)inwidth * v_MinimumToFill(inwidth, inheight)); } - inline uint32_t v_mfillY() + inline uint32_t v_mfillY(uint32_t inwidth, uint32_t inheight) { - return screen ? (uint32_t)((float)screen->GetClientHeight() * v_MinimumToFill()) : 400; + return (uint32_t)((float)inheight * v_MinimumToFill(inwidth, inheight)); } v_ScaleTable vScaleTable[NUMSCALEMODES] = { - // isValid, isLinear, GetScaledWidth(), GetScaledHeight(), isScaled43, isCustom - { true, false, [](uint32_t Width)->uint32_t { return Width; }, [](uint32_t Height)->uint32_t { return Height; }, false, false }, // 0 - Native - { true, true, [](uint32_t Width)->uint32_t { return Width; }, [](uint32_t Height)->uint32_t { return Height; }, false, false }, // 1 - Native (Linear) - { true, false, [](uint32_t Width)->uint32_t { return 640; }, [](uint32_t Height)->uint32_t { return 400; }, true, false }, // 2 - 640x400 (formerly 320x200) - { true, true, [](uint32_t Width)->uint32_t { return 960; }, [](uint32_t Height)->uint32_t { return 600; }, true, false }, // 3 - 960x600 (formerly 640x400) - { true, true, [](uint32_t Width)->uint32_t { return 1280; }, [](uint32_t Height)->uint32_t { return 800; }, true, false }, // 4 - 1280x800 - { true, true, [](uint32_t Width)->uint32_t { return vid_scale_customwidth; }, [](uint32_t Height)->uint32_t { return vid_scale_customheight; }, true, true }, // 5 - Custom - { true, true, [](uint32_t Width)->uint32_t { return v_mfillX(); }, [](uint32_t Height)->uint32_t { return v_mfillY(); }, false, false }, // 6 - Minimum Scale to Fill Entire Screen + // isValid, isLinear, GetScaledWidth(), GetScaledHeight(), isScaled43, isCustom + { true, false, [](uint32_t Width, uint32_t Height)->uint32_t { return Width; }, [](uint32_t Width, uint32_t Height)->uint32_t { return Height; }, false, false }, // 0 - Native + { true, true, [](uint32_t Width, uint32_t Height)->uint32_t { return Width; }, [](uint32_t Width, uint32_t Height)->uint32_t { return Height; }, false, false }, // 1 - Native (Linear) + { true, false, [](uint32_t Width, uint32_t Height)->uint32_t { return 640; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 400; }, true, false }, // 2 - 640x400 (formerly 320x200) + { true, true, [](uint32_t Width, uint32_t Height)->uint32_t { return 960; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 600; }, true, false }, // 3 - 960x600 (formerly 640x400) + { true, true, [](uint32_t Width, uint32_t Height)->uint32_t { return 1280; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 800; }, true, false }, // 4 - 1280x800 + { true, true, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customwidth; }, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customheight; }, true, true }, // 5 - Custom + { true, true, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillX(Width, Height); }, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillY(Width, Height); }, false, false }, // 6 - Minimum Scale to Fill Entire Screen }; bool isOutOfBounds(int x) { @@ -143,8 +143,11 @@ int ViewportScaledWidth(int width, int height) if (isOutOfBounds(vid_scalemode)) vid_scalemode = 0; if (vid_cropaspect && height > 0) + { width = ((float)width/height > ActiveRatio(width, height)) ? (int)(height * ActiveRatio(width, height)) : width; - return (int)MAX((int32_t)VID_MIN_WIDTH, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledWidth(width))); + height = ((float)width/height < ActiveRatio(width, height)) ? (int)(width / ActiveRatio(width, height)) : height; + } + return (int)MAX((int32_t)VID_MIN_WIDTH, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledWidth(width, height))); } int ViewportScaledHeight(int width, int height) @@ -152,8 +155,11 @@ int ViewportScaledHeight(int width, int height) if (isOutOfBounds(vid_scalemode)) vid_scalemode = 0; if (vid_cropaspect && height > 0) + { height = ((float)width/height < ActiveRatio(width, height)) ? (int)(width / ActiveRatio(width, height)) : height; - return (int)MAX((int32_t)VID_MIN_HEIGHT, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledHeight(height))); + width = ((float)width/height > ActiveRatio(width, height)) ? (int)(height * ActiveRatio(width, height)) : width; + } + return (int)MAX((int32_t)VID_MIN_HEIGHT, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledHeight(width, height))); } bool ViewportIsScaled43() @@ -226,3 +232,29 @@ CCMD (vid_setscale) Printf("Usage: vid_setscale [bool linear] [bool long-pixel-shape]\nThis command will create a custom viewport scaling mode.\n"); } } + +CCMD (vid_scaletolowest) +{ + uint32_t method = 0; + if (argv.argc() > 1) + method = atoi(argv[1]); + switch (method) + { + case 1: // Method 1: set a custom video scaling + vid_scalemode = 5; + vid_scalefactor = 1.0; + vid_scale_customlinear = 1; + vid_scale_customstretched = 0; + vid_scale_customwidth = v_mfillX(screen->GetClientWidth(), screen->GetClientHeight()); + vid_scale_customheight = v_mfillY(screen->GetClientWidth(), screen->GetClientHeight()); + break; + case 2: // Method 2: use the actual downscaling mode directly + vid_scalemode = 6; + vid_scalefactor = 1.0; + break; + default: // Default method: use vid_scalefactor to achieve the result on a default scaling mode + vid_scalemode = 1; + vid_scalefactor = v_MinimumToFill(screen->GetClientWidth(), screen->GetClientHeight()); + break; + } +}