diff options
Diffstat (limited to 'src/i_scale.c')
-rw-r--r-- | src/i_scale.c | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/src/i_scale.c b/src/i_scale.c new file mode 100644 index 00000000..29bc8731 --- /dev/null +++ b/src/i_scale.c @@ -0,0 +1,404 @@ + +#include "doomdef.h" +#include "doomtype.h" + +#include "z_zone.h" + +// Should be screens[0] + +static byte *src_buffer; + +// Destination buffer, ie. screen->pixels. + +static byte *dest_buffer; + +// Pitch of destination buffer, ie. screen->pitch. + +static int dest_pitch; + +// Lookup tables used for aspect ratio correction stretching code. +// stretch_tables[0] : 20% / 80% +// stretch_tables[1] : 40% / 60% +// All other combinations can be reached from these two tables. + +static byte *stretch_tables[2]; + +void I_InitScale(byte *_src_buffer, byte *_dest_buffer, int _dest_pitch) +{ + src_buffer = _src_buffer; + dest_buffer = _dest_buffer; + dest_pitch = _dest_pitch; +} + +void I_Scale1x(int x1, int y1, int x2, int y2) +{ + byte *bufp, *screenp; + int y; + int w = x2 - x1; + + // Need to byte-copy from buffer into the screen buffer + + bufp = src_buffer + y1 * SCREENWIDTH + x1; + screenp = (byte *) dest_buffer + y1 * dest_pitch + x1; + + for (y=y1; y<y2; ++y) + { + memcpy(screenp, bufp, w); + screenp += dest_pitch; + bufp += SCREENWIDTH; + } +} + +void I_Scale2x(int x1, int y1, int x2, int y2) +{ + byte *bufp, *screenp, *screenp2; + int x, y; + int multi_pitch; + + multi_pitch = dest_pitch * 2; + bufp = src_buffer + y1 * SCREENWIDTH + x1; + screenp = (byte *) dest_buffer + (y1 * dest_pitch + x1) * 2; + screenp2 = screenp + dest_pitch; + + for (y=y1; y<y2; ++y) + { + byte *sp, *sp2, *bp; + sp = screenp; + sp2 = screenp2; + bp = bufp; + + for (x=x1; x<x2; ++x) + { + *sp++ = *bp; *sp++ = *bp; + *sp2++ = *bp; *sp2++ = *bp; + ++bp; + } + screenp += multi_pitch; + screenp2 += multi_pitch; + bufp += SCREENWIDTH; + } +} + +void I_Scale3x(int x1, int y1, int x2, int y2) +{ + byte *bufp, *screenp, *screenp2, *screenp3; + int x, y; + int multi_pitch; + + multi_pitch = dest_pitch * 3; + bufp = src_buffer + y1 * SCREENWIDTH + x1; + screenp = (byte *) dest_buffer + (y1 * dest_pitch + x1) * 3; + screenp2 = screenp + dest_pitch; + screenp3 = screenp + dest_pitch * 2; + + for (y=y1; y<y2; ++y) + { + byte *sp, *sp2, *sp3, *bp; + sp = screenp; + sp2 = screenp2; + sp3 = screenp3; + bp = bufp; + + for (x=x1; x<x2; ++x) + { + *sp++ = *bp; *sp++ = *bp; *sp++ = *bp; + *sp2++ = *bp; *sp2++ = *bp; *sp2++ = *bp; + *sp3++ = *bp; *sp3++ = *bp; *sp3++ = *bp; + ++bp; + } + screenp += multi_pitch; + screenp2 += multi_pitch; + screenp3 += multi_pitch; + bufp += SCREENWIDTH; + } +} + +void I_Scale4x(int x1, int y1, int x2, int y2) +{ + byte *bufp, *screenp, *screenp2, *screenp3, *screenp4; + int x, y; + int multi_pitch; + + multi_pitch = dest_pitch * 4; + bufp = src_buffer + y1 * SCREENWIDTH + x1; + screenp = (byte *) dest_buffer + (y1 * dest_pitch + x1) * 4; + screenp2 = screenp + dest_pitch; + screenp3 = screenp + dest_pitch * 2; + screenp4 = screenp + dest_pitch * 3; + + for (y=y1; y<y2; ++y) + { + byte *sp, *sp2, *sp3, *sp4, *bp; + sp = screenp; + sp2 = screenp2; + sp3 = screenp3; + sp4 = screenp4; + bp = bufp; + + for (x=x1; x<x2; ++x) + { + *sp++ = *bp; *sp++ = *bp; *sp++ = *bp; *sp++ = *bp; + *sp2++ = *bp; *sp2++ = *bp; *sp2++ = *bp; *sp2++ = *bp; + *sp3++ = *bp; *sp3++ = *bp; *sp3++ = *bp; *sp3++ = *bp; + *sp4++ = *bp; *sp4++ = *bp; *sp4++ = *bp; *sp4++ = *bp; + ++bp; + } + screenp += multi_pitch; + screenp2 += multi_pitch; + screenp3 += multi_pitch; + screenp4 += multi_pitch; + bufp += SCREENWIDTH; + } +} + +// Search through the given palette, finding the nearest color that matches +// the given color. + +static int FindNearestColor(byte *palette, int r, int g, int b) +{ + byte *col; + int best; + int best_diff; + int diff; + int i; + + best = 0; + best_diff = INT_MAX; + + for (i=0; i<256; ++i) + { + col = palette + i * 3; + diff = (r - col[0]) * (r - col[0]) + + (g - col[1]) * (g - col[1]) + + (b - col[2]) * (b - col[2]); + + if (diff == 0) + { + return i; + } + else if (diff < best_diff) + { + best = i; + best_diff = diff; + } + } + + return best; +} + +// Create a stretch table. This is a lookup table for blending colors. +// pct specifies the bias between the two colors: 0 = all y, 100 = all x. +// NB: This is identical to the lookup tables used in other ports for +// translucency. + +static byte *GenerateStretchTable(byte *palette, int pct) +{ + byte *result; + int x, y; + int r, g, b; + byte *col1; + byte *col2; + + result = Z_Malloc(256 * 256, PU_STATIC, NULL); + + for (x=0; x<256; ++x) + { + for (y=0; y<256; ++y) + { + col1 = palette + x * 3; + col2 = palette + y * 3; + r = (((int) col1[0]) * pct + ((int) col2[0]) * (100 - pct)) / 100; + g = (((int) col1[1]) * pct + ((int) col2[1]) * (100 - pct)) / 100; + b = (((int) col1[2]) * pct + ((int) col2[2]) * (100 - pct)) / 100; + result[x * 256 + y] = FindNearestColor(palette, r, g, b); + } + } + + return result; +} + +void I_InitStretchTables(byte *palette) +{ + // We only actually need two lookup tables: + // + // mix 0% = just write line 1 + // mix 20% = stretch_tables[0] + // mix 40% = stretch_tables[1] + // mix 60% = stretch_tables[1] used backwards + // mix 80% = stretch_tables[0] used backwards + // mix 100% = just write line 2 + + printf("I_InitStretchTables: Generating lookup tables.."); + fflush(stdout); + stretch_tables[0] = GenerateStretchTable(palette, 20); + printf(".."); fflush(stdout); + stretch_tables[1] = GenerateStretchTable(palette, 40); + puts(""); +} + +static void WriteBlendedLine1x(byte *dest, byte *src1, byte *src2, + byte *stretch_table) +{ + int x; + + for (x=0; x<SCREENWIDTH; ++x) + { + *dest = stretch_table[*src1 * 256 + *src2]; + ++dest; + ++src1; + ++src2; + } +} + +void I_Stretch1x(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; + } + + // Need to byte-copy from buffer into the screen buffer + + bufp = src_buffer + y1 * SCREENWIDTH + x1; + screenp = (byte *) dest_buffer + y1 * dest_pitch + x1; + + // For every 5 lines of src_buffer, 6 lines are written to dest_buffer + // (200 -> 240) + + for (y=0; y<SCREENHEIGHT; y += 5) + { + // 100% line 0 + memcpy(screenp, bufp, SCREENWIDTH); + screenp += dest_pitch; + + // 20% line 0, 80% line 1 + WriteBlendedLine1x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[0]); + screenp += dest_pitch; bufp += SCREENWIDTH; + + // 40% line 1, 60% line 2 + WriteBlendedLine1x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[1]); + screenp += dest_pitch; bufp += SCREENWIDTH; + + // 60% line 2, 40% line 3 + WriteBlendedLine1x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[1]); + screenp += dest_pitch; bufp += SCREENWIDTH; + + // 80% line 3, 20% line 4 + WriteBlendedLine1x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[0]); + screenp += dest_pitch; bufp += SCREENWIDTH; + + // 100% line 4 + memcpy(screenp, bufp, SCREENWIDTH); + screenp += dest_pitch; bufp += SCREENWIDTH; + } +} + +static void WriteLine2x(byte *dest, byte *src) +{ + int x; + + for (x=0; x<SCREENWIDTH; ++x) + { + dest[0] = *src; + dest[1] = *src; + dest += 2; + ++src; + } +} + +static void WriteBlendedLine2x(byte *dest, byte *src1, byte *src2, + byte *stretch_table) +{ + int x; + int val; + + for (x=0; x<SCREENWIDTH; ++x) + { + val = stretch_table[*src1 * 256 + *src2]; + dest[0] = val; + dest[1] = val; + dest += 2; + ++src1; + ++src2; + } +} + +// Scale 2x, correcting aspect ratio in the process + +void I_Stretch2x(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; + } + + // Need to byte-copy from buffer into the screen buffer + + bufp = src_buffer + y1 * SCREENWIDTH + x1; + screenp = (byte *) dest_buffer + y1 * dest_pitch + x1; + + // For every 5 lines of src_buffer, 12 lines are written to dest_buffer. + // (200 -> 480) + + for (y=0; y<SCREENHEIGHT; y += 5) + { + // 100% line 0 + WriteLine2x(screenp, bufp); + screenp += dest_pitch; + + // 100% line 0 + WriteLine2x(screenp, bufp); + screenp += dest_pitch; + + // 40% line 0, 60% line 1 + WriteBlendedLine2x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[1]); + screenp += dest_pitch; bufp += SCREENWIDTH; + + // 100% line 1 + WriteLine2x(screenp, bufp); + screenp += dest_pitch; + + // 80% line 1, 20% line 2 + WriteBlendedLine2x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[0]); + screenp += dest_pitch; bufp += SCREENWIDTH; + + // 100% line 2 + WriteLine2x(screenp, bufp); + screenp += dest_pitch; + + // 100% line 2 + WriteLine2x(screenp, bufp); + screenp += dest_pitch; + + // 20% line 2, 80% line 3 + WriteBlendedLine2x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[0]); + screenp += dest_pitch; bufp += SCREENWIDTH; + + // 100% line 3 + WriteLine2x(screenp, bufp); + screenp += dest_pitch; + + // 60% line 3, 40% line 4 + WriteBlendedLine2x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[1]); + screenp += dest_pitch; bufp += SCREENWIDTH; + + // 100% line 4 + WriteLine2x(screenp, bufp); + screenp += dest_pitch; + + // 100% line 4 + WriteLine2x(screenp, bufp); + screenp += dest_pitch; bufp += SCREENWIDTH; + } +} + |