diff --git a/sc2/TODO b/sc2/TODO index d71cb631e..e79362635 100644 --- a/sc2/TODO +++ b/sc2/TODO @@ -69,7 +69,11 @@ Glitches (don't crash the game, medium priority): but it will hang on termination Implementation bugs (low priority): - +- Scaling code problems: + - sai, supersai doesn't work for >16bpp + - bilinear is only implemented under opengl + - opengl misses all other modes than bilinear + - do them with software and/or pixel shader hw? Stuff still to do (large): - add a Key Jamming program diff --git a/sc2/doc/users/manual.txt b/sc2/doc/users/manual.txt index a0587f9a3..b42a817dd 100644 --- a/sc2/doc/users/manual.txt +++ b/sc2/doc/users/manual.txt @@ -22,7 +22,7 @@ command line options to customize your experience: Sets the screen resolution. Unless --opengl is set, the only valid values are 640x480 and 320x240 - -d 24 (or --bpp) + -d 24 (or --bpp) Sets the color depth. If you don't set this, the game should autodetect an appropriate value. Valid values are 16, 24, and 32. @@ -37,20 +37,22 @@ combine with -r 320x240. Use OpenGL drivers. This produces higher-quality graphics, and may be faster as well -- but it also may not work on older cards. - -b (or --bilinear) + -c (or --scale=mode) -Enable bilinear filtering in OpenGL mode. Produces less pixelated -graphics with a bit of a performance penalty. +Graphics scaling mode (bilinear, sai or supersai). Default is none. +Try these to get smoother graphics with cost on performance. +Sai and supersai only works with depth of 16bpp for now. +Under OpenGL, bilinear is only one that's implemented currently. + + -s (or --scanlines) + +Simulates interlaced displays. -p (or --fps) Print fps information in the status window. - -s (or --scanlines) - -Simulates interlaced displays. - - -c (or --contentdir) + -n (or --contentdir) Set the directory where the game will seek its data. diff --git a/sc2/src/msvc++/UrQuanMasters.dsp b/sc2/src/msvc++/UrQuanMasters.dsp index 13e40ae59..7ec30f1f1 100644 --- a/sc2/src/msvc++/UrQuanMasters.dsp +++ b/sc2/src/msvc++/UrQuanMasters.dsp @@ -190,6 +190,14 @@ SOURCE=..\sc2code\libs\graphics\sdl\sdl_common.c SOURCE=..\sc2code\libs\graphics\sdl\sdl_common.h # End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\graphics\sdl\2xsai.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\graphics\sdl\2xsai.h +# End Source File # End Group # Begin Source File diff --git a/sc2/src/sc2code/libs/graphics/gfx_common.h b/sc2/src/sc2code/libs/graphics/gfx_common.h index 540a6c628..f6941b1a4 100644 --- a/sc2/src/sc2code/libs/graphics/gfx_common.h +++ b/sc2/src/sc2code/libs/graphics/gfx_common.h @@ -37,9 +37,11 @@ enum // flags for TFB_InitGraphics #define TFB_GFXFLAGS_FULLSCREEN (1<<0) -#define TFB_GFXFLAGS_BILINEAR_FILTERING (1<<1) -#define TFB_GFXFLAGS_SHOWFPS (1<<2) -#define TFB_GFXFLAGS_SCANLINES (1<<3) +#define TFB_GFXFLAGS_SHOWFPS (1<<1) +#define TFB_GFXFLAGS_SCANLINES (1<<2) +#define TFB_GFXFLAGS_SCALE_BILINEAR (1<<3) +#define TFB_GFXFLAGS_SCALE_SAI (1<<4) +#define TFB_GFXFLAGS_SCALE_SUPERSAI (1<<5) int TFB_InitGraphics (int driver, int flags, int width, int height, int bpp); diff --git a/sc2/src/sc2code/libs/graphics/sdl/2xsai.c b/sc2/src/sc2code/libs/graphics/sdl/2xsai.c new file mode 100644 index 000000000..c68b4a018 --- /dev/null +++ b/sc2/src/sc2code/libs/graphics/sdl/2xsai.c @@ -0,0 +1,852 @@ +/* + * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + * + * (c) Copyright 1996 - 2001 Gary Henderson (gary@daniver.demon.co.uk) and + * Jerremy Koot (jkoot@snes9x.com) + * + * Super FX C emulator code + * (c) Copyright 1997 - 1999 Ivar (Ivar@snes9x.com) and + * Gary Henderson. + * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. + * + * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. + * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. + * C4 C code (c) Copyright 2001 Gary Henderson (gary@daniver.demon.co.uk). + * + * DOS port code contains the works of other authors. See headers in + * individual files. + * + * Snes9x homepage: www.snes9x.com + * + * Permission to use, copy, modify and distribute Snes9x in both binary and + * source form, for non-commercial purposes, is hereby granted without fee, + * providing that this license information and copyright notice appear with + * all copies and any derived work. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event shall the authors be held liable for any damages + * arising from the use of this software. + * + * Snes9x is freeware for PERSONAL USE only. Commercial users should + * seek permission of the copyright holders first. Commercial use includes + * charging money for Snes9x or software derived from Snes9x. + * + * The copyright holders request that bug fixes and improvements to the code + * should be forwarded to them so everyone can benefit from the modifications + * in future versions. + * + * Super NES and Super Nintendo Entertainment System are trademarks of + * Nintendo Co., Limited and its subsidiary companies. + */ + +#include +#include +#include +#include + +static Uint32 colorMask = 0xF7DEF7DE; +static Uint32 lowPixelMask = 0x08210821; +static Uint32 qcolorMask = 0xE79CE79C; +static Uint32 qlowpixelMask = 0x18631863; +static Uint32 redblueMask = 0xF81F; +static Uint32 greenMask = 0x7E0; + + +int Init_2xSaI (Uint32 BitFormat) +{ + if (BitFormat == 565) + { + colorMask = 0xF7DEF7DE; + lowPixelMask = 0x08210821; + qcolorMask = 0xE79CE79C; + qlowpixelMask = 0x18631863; + redblueMask = 0xF81F; + greenMask = 0x7E0; + } + else if (BitFormat == 555) + { + colorMask = 0x7BDE7BDE; + lowPixelMask = 0x04210421; + qcolorMask = 0x739C739C; + qlowpixelMask = 0x0C630C63; + redblueMask = 0x7C1F; + greenMask = 0x3E0; + } + else + { + return 0; + } + + return 1; +} + +int GetResult1 (Uint32 A, Uint32 B, Uint32 C, Uint32 D, Uint32 E) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r += 1; + if (y <= 1) + r -= 1; + return r; +} + +int GetResult2 (Uint32 A, Uint32 B, Uint32 C, Uint32 D, Uint32 E) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r -= 1; + if (y <= 1) + r += 1; + return r; +} + +int GetResult (Uint32 A, Uint32 B, Uint32 C, Uint32 D) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r += 1; + if (y <= 1) + r -= 1; + return r; +} + +Uint32 INTERPOLATE (Uint32 A, Uint32 B) +{ + if (A != B) + { + return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + + (A & B & lowPixelMask)); + } + else + return A; +} + +Uint32 Q_INTERPOLATE (Uint32 A, Uint32 B, Uint32 C, Uint32 D) +{ + register Uint32 x = ((A & qcolorMask) >> 2) + + ((B & qcolorMask) >> 2) + + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2); + register Uint32 y = (A & qlowpixelMask) + + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask); + + y = (y >> 2) & qlowpixelMask; + return x + y; +} + +#define BLUE_MASK565 0x001F001F +#define RED_MASK565 0xF800F800 +#define GREEN_MASK565 0x07E007E0 + +#define BLUE_MASK555 0x001F001F +#define RED_MASK555 0x7C007C00 +#define GREEN_MASK555 0x03E003E0 + +void Super2xSaI(Uint8 *srcPtr, Uint32 srcPitch, + Uint8 *dstPtr, Uint32 dstPitch, + int width, int height) +{ + Uint16 *bP; + Uint8 *dP; + Uint32 inc_bP; + Uint32 Nextline = srcPitch >> 1; + + Uint32 finish; + inc_bP = 1; + + for (; height; height--) + { + bP = (Uint16 *) srcPtr; + dP = (Uint8 *) dstPtr; + + for (finish = width; finish; finish -= inc_bP) + { + Uint32 color4, color5, color6; + Uint32 color1, color2, color3; + Uint32 colorA0, colorA1, colorA2, colorA3, + colorB0, colorB1, colorB2, colorB3, colorS1, colorS2; + Uint32 product1a, product1b, product2a, product2b; + +//--------------------------------------- B1 B2 +// 4 5 6 S2 +// 1 2 3 S1 +// A1 A2 + + colorB0 = *(bP - Nextline - 1); + colorB1 = *(bP - Nextline); + colorB2 = *(bP - Nextline + 1); + colorB3 = *(bP - Nextline + 2); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + Nextline - 1); + color2 = *(bP + Nextline); + color3 = *(bP + Nextline + 1); + colorS1 = *(bP + Nextline + 2); + + colorA0 = *(bP + Nextline + Nextline - 1); + colorA1 = *(bP + Nextline + Nextline); + colorA2 = *(bP + Nextline + Nextline + 1); + colorA3 = *(bP + Nextline + Nextline + 2); + +//-------------------------------------- + if (color2 == color6 && color5 != color3) + { + product2b = product1b = color2; + } + else if (color5 == color3 && color2 != color6) + { + product2b = product1b = color5; + } + else if (color5 == color3 && color2 == color6) + { + register int r = 0; + + r += GetResult (color6, color5, color1, colorA1); + r += GetResult (color6, color5, color4, colorB1); + r += GetResult (color6, color5, colorA2, colorS1); + r += GetResult (color6, color5, colorB2, colorS2); + + if (r > 0) + product2b = product1b = color6; + else if (r < 0) + product2b = product1b = color5; + else + { + product2b = product1b = INTERPOLATE (color5, color6); + } + } + else + { + if (color6 == color3 && color3 == colorA1 + && color2 != colorA2 && color3 != colorA0) + product2b = + Q_INTERPOLATE (color3, color3, color3, color2); + else if (color5 == color2 && color2 == colorA2 + && colorA1 != color3 && color2 != colorA3) + product2b = + Q_INTERPOLATE (color2, color2, color2, color3); + else + product2b = INTERPOLATE (color2, color3); + + if (color6 == color3 && color6 == colorB1 + && color5 != colorB2 && color6 != colorB0) + product1b = + Q_INTERPOLATE (color6, color6, color6, color5); + else if (color5 == color2 && color5 == colorB2 + && colorB1 != color6 && color5 != colorB3) + product1b = + Q_INTERPOLATE (color6, color5, color5, color5); + else + product1b = INTERPOLATE (color5, color6); + } + + if (color5 == color3 && color2 != color6 && color4 == color5 + && color5 != colorA2) + product2a = INTERPOLATE (color2, color5); + else + if (color5 == color1 && color6 == color5 + && color4 != color2 && color5 != colorA0) + product2a = INTERPOLATE (color2, color5); + else + product2a = color2; + + if (color2 == color6 && color5 != color3 && color1 == color2 + && color2 != colorB2) + product1a = INTERPOLATE (color2, color5); + else + if (color4 == color2 && color3 == color2 + && color1 != color5 && color2 != colorB0) + product1a = INTERPOLATE (color2, color5); + else + product1a = color5; + + product1a = product1a | (product1b << 16); + product2a = product2a | (product2b << 16); + + *((Uint32 *) dP) = product1a; + *((Uint32 *) (dP + dstPitch)) = product2a; + + bP += inc_bP; + dP += sizeof (Uint32); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; + } // endof: for (; height; height--) +} + +void SuperEagle(Uint8 *srcPtr, Uint32 srcPitch, /* Uint8 *deltaPtr, */ + Uint8 *dstPtr, Uint32 dstPitch, int width, int height) +{ + Uint8 *dP; + Uint16 *bP; + Uint32 inc_bP; + + + + Uint32 finish; + Uint32 Nextline = srcPitch >> 1; + + inc_bP = 1; + + for (; height ; height--) + { + bP = (Uint16 *) srcPtr; + dP = dstPtr; + for (finish = width; finish; finish -= inc_bP) + { + Uint32 color4, color5, color6; + Uint32 color1, color2, color3; + Uint32 colorA1, colorA2, colorB1, colorB2, colorS1, colorS2; + Uint32 product1a, product1b, product2a, product2b; + colorB1 = *(bP - Nextline); + colorB2 = *(bP - Nextline + 1); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + Nextline - 1); + color2 = *(bP + Nextline); + color3 = *(bP + Nextline + 1); + colorS1 = *(bP + Nextline + 2); + + colorA1 = *(bP + Nextline + Nextline); + colorA2 = *(bP + Nextline + Nextline + 1); + // -------------------------------------- + if (color2 == color6 && color5 != color3) + { + product1b = product2a = color2; + if ((color1 == color2) || (color6 == colorB2)) + { + product1a = INTERPOLATE (color2, color5); + product1a = INTERPOLATE (color2, product1a); +// product1a = color2; + } + else + { + product1a = INTERPOLATE (color5, color6); + } + + if ((color6 == colorS2) || (color2 == colorA1)) + { + product2b = INTERPOLATE (color2, color3); + product2b = INTERPOLATE (color2, product2b); +// product2b = color2; + } + else + { + product2b = INTERPOLATE (color2, color3); + } + } + else if (color5 == color3 && color2 != color6) + { + product2b = product1a = color5; + + if ((colorB1 == color5) || (color3 == colorS1)) + { + product1b = INTERPOLATE (color5, color6); + product1b = INTERPOLATE (color5, product1b); +// product1b = color5; + } + else + { + product1b = INTERPOLATE (color5, color6); + } + + if ((color3 == colorA2) || (color4 == color5)) + { + product2a = INTERPOLATE (color5, color2); + product2a = INTERPOLATE (color5, product2a); +// product2a = color5; + } + else + { + product2a = INTERPOLATE (color2, color3); + } + + } + else if (color5 == color3 && color2 == color6) + { + register int r = 0; + + r += GetResult (color6, color5, color1, colorA1); + r += GetResult (color6, color5, color4, colorB1); + r += GetResult (color6, color5, colorA2, colorS1); + r += GetResult (color6, color5, colorB2, colorS2); + + if (r > 0) + { + product1b = product2a = color2; + product1a = product2b = INTERPOLATE (color5, color6); + } + else if (r < 0) + { + product2b = product1a = color5; + product1b = product2a = INTERPOLATE (color5, color6); + } + else + { + product2b = product1a = color5; + product1b = product2a = color2; + } + } + else + { + product2b = product1a = INTERPOLATE (color2, color6); + product2b = + Q_INTERPOLATE (color3, color3, color3, product2b); + product1a = + Q_INTERPOLATE (color5, color5, color5, product1a); + + product2a = product1b = INTERPOLATE (color5, color3); + product2a = + Q_INTERPOLATE (color2, color2, color2, product2a); + product1b = + Q_INTERPOLATE (color6, color6, color6, product1b); + +// product1a = color5; +// product1b = color6; +// product2a = color2; +// product2b = color3; + } + product1a = product1a | (product1b << 16); + product2a = product2a | (product2b << 16); + + *((Uint32 *) dP) = product1a; + *((Uint32 *) (dP + dstPitch)) = product2a; + + bP += inc_bP; + dP += sizeof (Uint32); + } // end of for ( finish= width etc..) + srcPtr += srcPitch; + dstPtr += dstPitch * 2; + } // endof: for (height; height; height--) +} + +void _2xSaI (Uint8 *srcPtr, Uint32 srcPitch, + Uint8 *dstPtr, Uint32 dstPitch, int width, int height) +{ + Uint8 *dP; + Uint16 *bP; + Uint32 inc_bP; + + + Uint32 finish; + Uint32 Nextline = srcPitch >> 1; + inc_bP = 1; + + + for (; height; height--) + { + bP = (Uint16 *) srcPtr; + dP = dstPtr; + + for (finish = width; finish; finish -= inc_bP) + { + + register Uint32 colorA, colorB; + Uint32 colorC, colorD, + colorE, colorF, colorG, colorH, + colorI, colorJ, colorK, colorL, + + colorM, colorN, colorO, colorP; + Uint32 product, product1, product2; + +//--------------------------------------- +// Map of the pixels: I|E F|J +// G|A B|K +// H|C D|L +// M|N O|P + colorI = *(bP - Nextline - 1); + colorE = *(bP - Nextline); + colorF = *(bP - Nextline + 1); + colorJ = *(bP - Nextline + 2); + + colorG = *(bP - 1); + colorA = *(bP); + colorB = *(bP + 1); + colorK = *(bP + 2); + + colorH = *(bP + Nextline - 1); + colorC = *(bP + Nextline); + colorD = *(bP + Nextline + 1); + colorL = *(bP + Nextline + 2); + + colorM = *(bP + Nextline + Nextline - 1); + colorN = *(bP + Nextline + Nextline); + colorO = *(bP + Nextline + Nextline + 1); + colorP = *(bP + Nextline + Nextline + 2); + + if ((colorA == colorD) && (colorB != colorC)) + { + if (((colorA == colorE) && (colorB == colorL)) || + ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ))) + { + product = colorA; + } + else + { + product = INTERPOLATE (colorA, colorB); + } + + if (((colorA == colorG) && (colorC == colorO)) || + ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM))) + { + product1 = colorA; + } + else + { + product1 = INTERPOLATE (colorA, colorC); + } + product2 = colorA; + } + else if ((colorB == colorC) && (colorA != colorD)) + { + if (((colorB == colorF) && (colorA == colorH)) || + ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI))) + { + product = colorB; + } + else + { + product = INTERPOLATE (colorA, colorB); + } + + if (((colorC == colorH) && (colorA == colorF)) || + ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI))) + { + product1 = colorC; + } + else + { + product1 = INTERPOLATE (colorA, colorC); + } + product2 = colorB; + } + else if ((colorA == colorD) && (colorB == colorC)) + { + if (colorA == colorB) + { + product = colorA; + product1 = colorA; + product2 = colorA; + } + else + { + register int r = 0; + + product1 = INTERPOLATE (colorA, colorC); + product = INTERPOLATE (colorA, colorB); + + r += + GetResult1 (colorA, colorB, colorG, colorE, + colorI); + r += + GetResult2 (colorB, colorA, colorK, colorF, + colorJ); + r += + GetResult2 (colorB, colorA, colorH, colorN, + colorM); + r += + GetResult1 (colorA, colorB, colorL, colorO, + colorP); + + if (r > 0) + product2 = colorA; + else if (r < 0) + product2 = colorB; + else + { + product2 = + Q_INTERPOLATE (colorA, colorB, colorC, + colorD); + } + } + } + else + { + product2 = Q_INTERPOLATE (colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ)) + { + product = colorA; + } + else + if ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI)) + { + product = colorB; + } + else + { + product = INTERPOLATE (colorA, colorB); + } + + if ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM)) + { + product1 = colorA; + } + else + if ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI)) + { + product1 = colorC; + } + else + { + product1 = INTERPOLATE (colorA, colorC); + } + } + + product = colorA | (product << 16); + product1 = product1 | (product2 << 16); + *((Uint32 *) dP) = product; + *((Uint32 *) (dP + dstPitch)) = product1; + + bP += inc_bP; + dP += sizeof (Uint32); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; + } // endof: for (height; height; height--) +} + + +Uint32 Bilinear(Uint32 A, Uint32 B, Uint32 x) +{ + unsigned long areaA, areaB; + unsigned long result; + + if (A == B) + return A; + + areaB = (x >> 11) & 0x1f; // reduce 16 bit fraction to 5 bits + areaA = 0x20 - areaB; + + A = (A & redblueMask) | ((A & greenMask) << 16); + B = (B & redblueMask) | ((B & greenMask) << 16); + + result = ((areaA * A) + (areaB * B)) >> 5; + + return (result & redblueMask) | ((result >> 16) & greenMask); + +} + +static Uint32 Bilinear4 (Uint32 A, Uint32 B, Uint32 C, Uint32 D, Uint32 x, + Uint32 y) +{ + unsigned long areaA, areaB, areaC, areaD; + unsigned long result, xy; + + x = (x >> 11) & 0x1f; + y = (y >> 11) & 0x1f; + xy = (x * y) >> 5; + + A = (A & redblueMask) | ((A & greenMask) << 16); + B = (B & redblueMask) | ((B & greenMask) << 16); + C = (C & redblueMask) | ((C & greenMask) << 16); + D = (D & redblueMask) | ((D & greenMask) << 16); + + areaA = 0x20 + xy - x - y; + areaB = x - xy; + areaC = y - xy; + areaD = xy; + + result = ((areaA * A) + (areaB * B) + (areaC * C) + (areaD * D)) >> 5; + + return (result & redblueMask) | ((result >> 16) & greenMask); +} + +void Scale_2xSaI (Uint8 *srcPtr, Uint32 srcPitch, /* Uint8 * deltaPtr ,*/ + Uint8 *dstPtr, Uint32 dstPitch, + Uint32 dstWidth, Uint32 dstHeight, int width, int height) +{ + Uint8 *dP; + Uint16 *bP; + + Uint32 w; + Uint32 h; + Uint32 dw; + Uint32 dh; + Uint32 hfinish; + Uint32 wfinish; + + Uint32 Nextline = srcPitch >> 1; + + wfinish = (width - 1) << 16; // convert to fixed point + dw = wfinish / (dstWidth - 1); + hfinish = (height - 1) << 16; // convert to fixed point + dh = hfinish / (dstHeight - 1); + + for (h = 0; h < hfinish; h += dh) + { + Uint32 y1, y2; + + y1 = h & 0xffff; // fraction part of fixed point + bP = (Uint16 *) (srcPtr + ((h >> 16) * srcPitch)); + dP = dstPtr; + y2 = 0x10000 - y1; + + w = 0; + + for (; w < wfinish;) + { + Uint32 A, B, C, D; + Uint32 E, F, G, H; + Uint32 I, J, K, L; + Uint32 x1, x2, a1, f1, f2; + Uint32 position, product1; + + position = w >> 16; + A = bP[position]; // current pixel + B = bP[position + 1]; // next pixel + C = bP[position + Nextline]; + D = bP[position + Nextline + 1]; + E = bP[position - Nextline]; + F = bP[position - Nextline + 1]; + G = bP[position - 1]; + H = bP[position + Nextline - 1]; + I = bP[position + 2]; + J = bP[position + Nextline + 2]; + K = bP[position + Nextline + Nextline]; + L = bP[position + Nextline + Nextline + 1]; + + x1 = w & 0xffff; // fraction part of fixed point + x2 = 0x10000 - x1; + + /*0*/ + if (A == B && C == D && A == C) + product1 = A; + else + /*1*/ + if (A == D && B != C) + { + f1 = (x1 >> 1) + (0x10000 >> 2); + f2 = (y1 >> 1) + (0x10000 >> 2); + if (y1 <= f1 && A == J && A != E) // close to B + { + a1 = f1 - y1; + product1 = Bilinear (A, B, a1); + } + else if (y1 >= f1 && A == G && A != L) // close to C + { + a1 = y1 - f1; + product1 = Bilinear (A, C, a1); + } + else if (x1 >= f2 && A == E && A != J) // close to B + { + a1 = x1 - f2; + product1 = Bilinear (A, B, a1); + } + else if (x1 <= f2 && A == L && A != G) // close to C + { + a1 = f2 - x1; + product1 = Bilinear (A, C, a1); + } + else if (y1 >= x1) // close to C + { + a1 = y1 - x1; + product1 = Bilinear (A, C, a1); + } + else if (y1 <= x1) // close to B + { + a1 = x1 - y1; + product1 = Bilinear (A, B, a1); + } + } + else + /*2*/ + if (B == C && A != D) + { + f1 = (x1 >> 1) + (0x10000 >> 2); + f2 = (y1 >> 1) + (0x10000 >> 2); + if (y2 >= f1 && B == H && B != F) // close to A + { + a1 = y2 - f1; + product1 = Bilinear (B, A, a1); + } + else if (y2 <= f1 && B == I && B != K) // close to D + { + a1 = f1 - y2; + product1 = Bilinear (B, D, a1); + } + else if (x2 >= f2 && B == F && B != H) // close to A + { + a1 = x2 - f2; + product1 = Bilinear (B, A, a1); + } + else if (x2 <= f2 && B == K && B != I) // close to D + { + a1 = f2 - x2; + product1 = Bilinear (B, D, a1); + } + else if (y2 >= x1) // close to A + { + a1 = y2 - x1; + product1 = Bilinear (B, A, a1); + } + else if (y2 <= x1) // close to D + { + a1 = x1 - y2; + product1 = Bilinear (B, D, a1); + } + } + /*3*/ + else + { + product1 = Bilinear4 (A, B, C, D, x1, y1); + } + +//end First Pixel + *(Uint32 *) dP = product1; + dP += 2; + w += dw; + } + dstPtr += dstPitch; + } +} diff --git a/sc2/src/sc2code/libs/graphics/sdl/2xsai.h b/sc2/src/sc2code/libs/graphics/sdl/2xsai.h new file mode 100644 index 000000000..aa0b2b842 --- /dev/null +++ b/sc2/src/sc2code/libs/graphics/sdl/2xsai.h @@ -0,0 +1,10 @@ +#ifndef __2XSAI_H__ +#define __2XSAI_H__ + +extern int Init_2xSaI(Uint32); +extern void Super2xSaI(Uint8*srcPtr,Uint32 srcPitch,Uint8 *dstPtr,Uint32 dstPitch,int width,int height); +extern void SuperEagle(Uint8*srcPtr,Uint32 srcPitch,Uint8 *dstPtr,Uint32 dstPitch,int width,int height); +extern void _2xSaI(Uint8*,Uint32,Uint8*,Uint32,int,int); +extern void Scale_2xSaI(Uint8*,Uint32,Uint8*,Uint32,Uint32,Uint32,int,int); + +#endif diff --git a/sc2/src/sc2code/libs/graphics/sdl/Makefile.am b/sc2/src/sc2code/libs/graphics/sdl/Makefile.am index 1adb19593..03f81f8e4 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/Makefile.am +++ b/sc2/src/sc2code/libs/graphics/sdl/Makefile.am @@ -8,8 +8,8 @@ INCLUDES = @SDL_CFLAGS@ \ noinst_LTLIBRARIES = libsdl.la libsdl_la_SOURCES = 3do_blt.c 3do_funcs.c 3do_getbody.c dcqueue.c opengl.c \ - primitives.c pure.c rotozoom.c sdl_common.c + primitives.c pure.c rotozoom.c sdl_common.c 2xsai.c noinst_HEADERS = opengl.h primitives.h pure.h rotozoom.h sdl_common.h \ - dcqueue.h + dcqueue.h 2xsai.h diff --git a/sc2/src/sc2code/libs/graphics/sdl/opengl.c b/sc2/src/sc2code/libs/graphics/sdl/opengl.c index 36fff6bc3..7928265f2 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/opengl.c +++ b/sc2/src/sc2code/libs/graphics/sdl/opengl.c @@ -149,7 +149,14 @@ TFB_GL_InitGraphics (int driver, int flags, int width, int height, int bpp) exit(-1); } - if (flags & TFB_GFXFLAGS_BILINEAR_FILTERING) + // TODO: implement SaI and SuperSaI scaling for OpenGL too (fallback to bilinear for now) + if ((GfxFlags & TFB_GFXFLAGS_SCALE_SAI) || (GfxFlags & TFB_GFXFLAGS_SCALE_SUPERSAI)) + { + GfxFlags &= ~(TFB_GFXFLAGS_SCALE_SAI|TFB_GFXFLAGS_SCALE_SUPERSAI); + GfxFlags |= TFB_GFXFLAGS_SCALE_BILINEAR; + } + + if (GfxFlags & TFB_GFXFLAGS_SCALE_BILINEAR) ScreenFilterMode = GL_LINEAR; else ScreenFilterMode = GL_NEAREST; diff --git a/sc2/src/sc2code/libs/graphics/sdl/pure.c b/sc2/src/sc2code/libs/graphics/sdl/pure.c index 86ab2d2a0..0d3810ca0 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/pure.c +++ b/sc2/src/sc2code/libs/graphics/sdl/pure.c @@ -18,12 +18,13 @@ #ifdef GFXMODULE_SDL -#include "libs/graphics/sdl/pure.h" +#include "pure.h" +#include "2xsai.h" static SDL_Surface *fade_black; static SDL_Surface *fade_white; static SDL_Surface *fade_temp; - +static SDL_Surface *sai_temp; int TFB_Pure_InitGraphics (int driver, int flags, int width, int height, int bpp) @@ -92,7 +93,6 @@ TFB_Pure_InitGraphics (int driver, int flags, int width, int height, int bpp) fprintf (stderr, "Set the resolution to: %ix%ix%i\n", SDL_GetVideoSurface()->w, SDL_GetVideoSurface()->h, SDL_GetVideoSurface()->format->BitsPerPixel); - } test_extra = SDL_CreateRGBSurface(SDL_SWSURFACE, ScreenWidth, ScreenHeight, 32, @@ -113,10 +113,48 @@ TFB_Pure_InitGraphics (int driver, int flags, int width, int height, int bpp) fade_black = SDL_DisplayFormat (test_extra); SDL_FillRect (fade_black, NULL, SDL_MapRGB (fade_black->format, 0, 0, 0)); fade_temp = SDL_DisplayFormat (test_extra); - + SDL_FreeSurface (test_extra); + test_extra = SDL_CreateRGBSurface(SDL_SWSURFACE, ScreenWidth, ScreenHeight + 4, 32, + 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000); + if (test_extra == NULL) + { + fprintf (stderr, "Couldn't create sai back buffer: %s\n", SDL_GetError()); + exit(-1); + } + sai_temp = SDL_DisplayFormat (test_extra); + SDL_FillRect (sai_temp, NULL, SDL_MapRGB (sai_temp->format, 0, 0, 0)); + SDL_FreeSurface (test_extra); + + // TODO: implement bilinear scaling for pure sdl too (fallback to sai for now) + if (GfxFlags & TFB_GFXFLAGS_SCALE_BILINEAR) + { + GfxFlags &= ~TFB_GFXFLAGS_SCALE_BILINEAR; + GfxFlags |= TFB_GFXFLAGS_SCALE_SAI; + } + { + int result; + + if (SDL_GetVideoSurface()->format->BitsPerPixel == 15) + { + result = Init_2xSaI (555); + } + else if (SDL_GetVideoSurface()->format->BitsPerPixel == 16) + { + result = Init_2xSaI (565); + } + else + { + result = Init_2xSaI (888); + } + + if (!result) + { + GfxFlags &= ~(TFB_GFXFLAGS_SCALE_SAI|TFB_GFXFLAGS_SCALE_SUPERSAI); + } + } if (SDL_Video->format->BytesPerPixel != SDL_Screen->format->BytesPerPixel) { @@ -128,6 +166,126 @@ TFB_Pure_InitGraphics (int driver, int flags, int width, int height, int bpp) return 0; } +static void Scale2x_Nearest (Uint8 bytesperpixel, Uint8 *src_p, Uint8 *dst_p, const int numlines) +{ + int x, y; + Uint8 *src_p2; + + switch (bytesperpixel) + { + case 1: + { + Uint8 pixval_8; + for (y = 0; y < numlines; ++y) + { + src_p2 = dst_p; + for (x = 0; x < 320; ++x) + { + pixval_8 = *src_p++; + + *dst_p++ = pixval_8; + *dst_p++ = pixval_8; + } + for (x = 0; x < 160; ++x) + { + *(Uint32*)dst_p = *(Uint32*)src_p2; + dst_p += 4; + src_p2 += 4; + } + } + break; + } + case 2: + { + Uint16 pixval_16; + for (y = 0; y < numlines; ++y) + { + src_p2 = dst_p; + for (x = 0; x < 320; ++x) + { + pixval_16 = *(Uint16*)src_p; + src_p += 2; + + *(Uint16*)dst_p = pixval_16; + dst_p += 2; + *(Uint16*)dst_p = pixval_16; + dst_p += 2; + } + for (x = 0; x < 320; ++x) + { + *(Uint32*)dst_p = *(Uint32*)src_p2; + dst_p += 4; + src_p2 += 4; + } + } + break; + } + case 3: + { + // FIXME: this one might have endian issues + + Uint32 pixval_32; + for (y = 0; y < numlines; ++y) + { + src_p2 = src_p; + for (x = 0; x < 320; ++x) + { + pixval_32 = *(Uint32*)src_p; + src_p += 3; + + *(Uint32*)dst_p = pixval_32; + dst_p += 3; + *(Uint32*)dst_p = pixval_32; + dst_p += 3; + } + src_p = src_p2; + for (x = 0; x < 320; ++x) + { + pixval_32 = *(Uint32*)src_p; + src_p += 3; + + *(Uint32*)dst_p = pixval_32; + dst_p += 3; + *(Uint32*)dst_p = pixval_32; + dst_p += 3; + } + } + break; + } + case 4: + { + Uint32 pixval_32; + for (y = 0; y < numlines; ++y) + { + src_p2 = src_p; + for (x = 0; x < 320; ++x) + { + pixval_32 = *(Uint32*)src_p; + src_p += 4; + + *(Uint32*)dst_p = pixval_32; + dst_p += 4; + *(Uint32*)dst_p = pixval_32; + dst_p += 4; + } + src_p = src_p2; + for (x = 0; x < 320; ++x) + + { + pixval_32 = *(Uint32*)src_p; + src_p += 4; + + *(Uint32*)dst_p = pixval_32; + dst_p += 4; + *(Uint32*)dst_p = pixval_32; + dst_p += 4; + } + } + break; + } + } +} + void TFB_Pure_SwapBuffers () { @@ -139,8 +297,6 @@ TFB_Pure_SwapBuffers () { // scales 320x240 backbuffer to 640x480 - int x, y; - Uint8 *src_p, *src_p2, *dst_p; SDL_Surface *backbuffer = SDL_Screen; if (transition_amount != 255) @@ -173,126 +329,42 @@ TFB_Pure_SwapBuffers () } SDL_LockSurface (SDL_Video); - SDL_LockSurface (backbuffer); - src_p = backbuffer->pixels; - dst_p = SDL_Video->pixels; - - switch (backbuffer->format->BytesPerPixel) + if (GfxFlags & TFB_GFXFLAGS_SCALE_SAI) { - case 1: + SDL_Rect r; + Uint8 *src_p, *dst_p; + + r.x = 0; + r.y = 2; + SDL_BlitSurface (backbuffer, NULL, sai_temp, &r); + + src_p = sai_temp->pixels; + src_p += sai_temp->pitch << 1; + dst_p = SDL_Video->pixels; + _2xSaI (src_p, sai_temp->pitch, dst_p, SDL_Video->pitch, ScreenWidth, ScreenHeight); + } + else if (GfxFlags & TFB_GFXFLAGS_SCALE_SUPERSAI) { - Uint8 pixval_8; - for (y = 0; y < 240; ++y) - { - src_p2 = dst_p; - for (x = 0; x < 320; ++x) - { - pixval_8 = *src_p++; - - *dst_p++ = pixval_8; - *dst_p++ = pixval_8; - } - for (x = 0; x < 160; ++x) - { - *(Uint32*)dst_p = *(Uint32*)src_p2; - dst_p += 4; - src_p2 += 4; - } - } - break; + SDL_Rect r; + Uint8 *src_p, *dst_p; + + r.x = 0; + r.y = 2; + SDL_BlitSurface (backbuffer, NULL, sai_temp, &r); + + src_p = sai_temp->pixels; + src_p += sai_temp->pitch << 1; + dst_p = SDL_Video->pixels; + Super2xSaI (src_p, sai_temp->pitch, dst_p, SDL_Video->pitch, ScreenWidth, ScreenHeight); } - case 2: + else { - Uint16 pixval_16; - for (y = 0; y < 240; ++y) - { - src_p2 = dst_p; - for (x = 0; x < 320; ++x) - { - pixval_16 = *(Uint16*)src_p; - src_p += 2; - - *(Uint16*)dst_p = pixval_16; - dst_p += 2; - *(Uint16*)dst_p = pixval_16; - dst_p += 2; - } - for (x = 0; x < 320; ++x) - { - *(Uint32*)dst_p = *(Uint32*)src_p2; - dst_p += 4; - src_p2 += 4; - } - } - break; + SDL_LockSurface (backbuffer); + Scale2x_Nearest (SDL_Screen->format->BytesPerPixel, backbuffer->pixels, SDL_Video->pixels, 240); + SDL_UnlockSurface (backbuffer); } - case 3: - { - // FIXME: this one might have endian issues - - Uint32 pixval_32; - for (y = 0; y < 240; ++y) - { - src_p2 = src_p; - for (x = 0; x < 320; ++x) - { - pixval_32 = *(Uint32*)src_p; - src_p += 3; - - *(Uint32*)dst_p = pixval_32; - dst_p += 3; - *(Uint32*)dst_p = pixval_32; - dst_p += 3; - } - src_p = src_p2; - for (x = 0; x < 320; ++x) - { - pixval_32 = *(Uint32*)src_p; - src_p += 3; - - *(Uint32*)dst_p = pixval_32; - dst_p += 3; - *(Uint32*)dst_p = pixval_32; - dst_p += 3; - } - } - break; - } - case 4: - { - Uint32 pixval_32; - for (y = 0; y < 240; ++y) - { - src_p2 = src_p; - for (x = 0; x < 320; ++x) - { - pixval_32 = *(Uint32*)src_p; - src_p += 4; - - *(Uint32*)dst_p = pixval_32; - dst_p += 4; - *(Uint32*)dst_p = pixval_32; - dst_p += 4; - } - src_p = src_p2; - for (x = 0; x < 320; ++x) - - { - pixval_32 = *(Uint32*)src_p; - src_p += 4; - - *(Uint32*)dst_p = pixval_32; - dst_p += 4; - *(Uint32*)dst_p = pixval_32; - dst_p += 4; - } - } - break; - } - } - - SDL_UnlockSurface (backbuffer); + SDL_UnlockSurface (SDL_Video); } else diff --git a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c index 3a3c33c1b..33d386bda 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c +++ b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c @@ -36,7 +36,7 @@ SDL_Surface *TransitionScreen; volatile int TransitionAmount = 255; SDL_Rect TransitionClipRect; -BOOLEAN ShowFPS = FALSE; +int GfxFlags = 0; volatile int continuity_break; @@ -54,6 +54,8 @@ TFB_InitGraphics (int driver, int flags, int width, int height, int bpp) atexit (TFB_UninitGraphics); + GfxFlags = flags; + if (driver == TFB_GFXDRIVER_SDL_OPENGL) { #ifdef HAVE_OPENGL @@ -73,9 +75,6 @@ TFB_InitGraphics (int driver, int flags, int width, int height, int bpp) sprintf (caption, "The Ur-Quan Masters v%d.%d", UQM_MAJOR_VERSION, UQM_MINOR_VERSION); SDL_WM_SetCaption (caption, NULL); - if (flags & TFB_GFXFLAGS_SHOWFPS) - ShowFPS = TRUE; - //if (flags & TFB_GFXFLAGS_FULLSCREEN) // SDL_ShowCursor (SDL_DISABLE); @@ -563,7 +562,7 @@ TFB_FlushGraphics () // Only call from main thread!! } continuity_break = 0; - if (ShowFPS) + if (GfxFlags & TFB_GFXFLAGS_SHOWFPS) TFB_ComputeFPS (); commands_handled = 0; diff --git a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.h b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.h index 50e1a2fef..8d52010fc 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.h +++ b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.h @@ -37,7 +37,7 @@ extern volatile int TransitionAmount; extern SDL_Rect TransitionClipRect; extern volatile int continuity_break; -extern BOOLEAN ShowFPS; +extern int GfxFlags; void ScreenOrigin (FRAME Display, COORD sx, COORD sy); void LoadDisplay (PDISPLAY_INTERFACE *pDisplay); diff --git a/sc2/src/starcon2.c b/sc2/src/starcon2.c index 577c221d2..c4c775345 100644 --- a/sc2/src/starcon2.c +++ b/sc2/src/starcon2.c @@ -67,10 +67,10 @@ main (int argc, char *argv[]) {"bpp", 1, NULL, 'd'}, {"fullscreen", 0, NULL, 'f'}, {"opengl", 0, NULL, 'o'}, - {"bilinear", 0, NULL, 'b'}, - {"fps", 0, NULL, 'p'}, + {"scale", 1, NULL, 'c'}, {"scanlines", 0, NULL, 's'}, - {"contentdir", 1, NULL, 'c'}, + {"fps", 0, NULL, 'p'}, + {"contentdir", 1, NULL, 'n'}, {"help", 0, NULL, 'h'}, {"musicvol", 1, NULL, 'M'}, {"sfxvol", 1, NULL, 'S'}, @@ -85,7 +85,7 @@ main (int argc, char *argv[]) strcpy (contentdir, "content"); - while ((c = getopt_long(argc, argv, "r:d:fob:psc:?hM:S:T:emq:", long_options, &option_index)) != -1) + while ((c = getopt_long(argc, argv, "r:d:foc:spn:?hM:S:T:emq:", long_options, &option_index)) != -1) { switch (c) { case 'r': @@ -100,16 +100,28 @@ main (int argc, char *argv[]) case 'o': gfxdriver = TFB_GFXDRIVER_SDL_OPENGL; break; - case 'b': - gfxflags |= TFB_GFXFLAGS_BILINEAR_FILTERING; - break; - case 'p': - gfxflags |= TFB_GFXFLAGS_SHOWFPS; + case 'c': + sscanf(optarg, "%s", str); + if (!strcmp (str, "bilinear")) + { + gfxflags |= TFB_GFXFLAGS_SCALE_BILINEAR; + } + else if (!strcmp (str, "sai")) + { + gfxflags |= TFB_GFXFLAGS_SCALE_SAI; + } + else if (!strcmp (str, "supersai")) + { + gfxflags |= TFB_GFXFLAGS_SCALE_SUPERSAI; + } break; case 's': gfxflags |= TFB_GFXFLAGS_SCANLINES; break; - case 'c': + case 'p': + gfxflags |= TFB_GFXFLAGS_SHOWFPS; + break; + case 'n': sscanf(optarg, "%s", contentdir); break; case 'M': @@ -165,14 +177,14 @@ main (int argc, char *argv[]) case '?': case 'h': printf("\nOptions:\n"); - printf(" -r, --res=WIDTHxHEIGHT (default 640x480, others work only with --opengl)\n"); - printf(" -d, --bpp=BITSPERPIXEL (default 16, use 24 or 32 for better gfx quality)\n"); + printf(" -r, --res=WIDTHxHEIGHT (default 640x480, bigger works only with --opengl)\n"); + printf(" -d, --bpp=BITSPERPIXEL (default 16)\n"); printf(" -f, --fullscreen (default off)\n"); - printf(" -o, --opengl (default off, usage recommended if TNT2 or better gfx card)\n"); - printf(" -b, --bilinear (default off, only works with --opengl)\n"); - printf(" -p, --fps (default off)\n"); + printf(" -o, --opengl (default off)\n"); + printf(" -c, --scale=mode (bilinear, sai or supersai, default is none)\n"); printf(" -s, --scanlines (default off, only works with --opengl\n"); - printf(" -c, --contentdir=CONTENTDIR\n"); + printf(" -p, --fps (default off)\n"); + printf(" -n, --contentdir=CONTENTDIR\n"); printf(" -M, --musicvol=VOLUME (0-100, default 100)\n"); printf(" -S, --sfxvol=VOLUME (0-100, default 100)\n"); printf(" -T, --speechvol=VOLUME (0-100, default 100)\n");