Initial commit
This commit is contained in:
83
graphics/scaler/Normal2xARM.s
Normal file
83
graphics/scaler/Normal2xARM.s
Normal file
@@ -0,0 +1,83 @@
|
||||
@ ScummVM - Graphic Adventure Engine
|
||||
@
|
||||
@ ScummVM is the legal property of its developers, whose names
|
||||
@ are too numerous to list here. Please refer to the COPYRIGHT
|
||||
@ file distributed with this source distribution.
|
||||
@
|
||||
@ This program is free software: you can redistribute it and/or modify
|
||||
@ it under the terms of the GNU General Public License as published by
|
||||
@ the Free Software Foundation, either version 3 of the License, or
|
||||
@ (at your option) any later version.
|
||||
@
|
||||
@ This program is distributed in the hope that it will be useful,
|
||||
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
@ GNU General Public License for more details.
|
||||
@
|
||||
@ You should have received a copy of the GNU General Public License
|
||||
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@
|
||||
@ @author Robin Watts (robin@wss.co.uk)
|
||||
|
||||
.text
|
||||
|
||||
.global Normal2xARM
|
||||
|
||||
|
||||
@ Assumes dst is aligned (so did the C)
|
||||
@ Assumes 16bit (so did the C)
|
||||
.align 2
|
||||
Normal2xARM:
|
||||
@ r0 = src
|
||||
@ r1 = srcPitch
|
||||
@ r2 = dst
|
||||
@ r3 = dstPitch
|
||||
@ r4 = w
|
||||
@ r5 = h
|
||||
STMFD r13!,{r4-r11,r14}
|
||||
LDR r4, [r13,#4*9] @ r4 = w
|
||||
LDR r5, [r13,#4*10] @ r5 = h
|
||||
ADD r12,r2, r3
|
||||
SUB r1, r1, r4, LSL #1
|
||||
SUB r6, r3, r4, LSL #2
|
||||
ADD r3, r3, r6
|
||||
yloop:
|
||||
SUBS r14,r4, #4
|
||||
ADDLT r14,r14, #4
|
||||
BLT thin
|
||||
xloop:
|
||||
LDRH r6, [r0], #2
|
||||
LDRH r7, [r0], #2
|
||||
LDRH r8, [r0], #2
|
||||
LDRH r9, [r0], #2
|
||||
ORR r6, r6, r6, LSL #16
|
||||
ORR r7, r7, r7, LSL #16
|
||||
ORR r8, r8, r8, LSL #16
|
||||
ORR r9, r9, r9, LSL #16
|
||||
STMIA r2!, {r6-r9}
|
||||
STMIA r12!,{r6-r9}
|
||||
SUBS r14,r14,#4
|
||||
BGE xloop
|
||||
ADDS r14,r14,#4
|
||||
BNE thin
|
||||
ADD r0, r0, r1
|
||||
ADD r2, r2, r3
|
||||
ADD r12,r12,r3
|
||||
SUBS r5, r5, #1
|
||||
BGT yloop
|
||||
|
||||
LDMFD r13!,{r4-r11,PC}
|
||||
thin:
|
||||
LDRH r6, [r0], #2
|
||||
ORR r6, r6, r6, LSL #16
|
||||
STR r6, [r2], #4
|
||||
STR r6, [r12],#4
|
||||
SUBS r14,r14,#1
|
||||
BGT thin
|
||||
ADD r0, r0, r1
|
||||
ADD r2, r2, r3
|
||||
ADD r12,r12,r3
|
||||
SUBS r5, r5, #1
|
||||
BGT yloop
|
||||
|
||||
LDMFD r13!,{r4-r11,PC}
|
||||
272
graphics/scaler/aspect.cpp
Normal file
272
graphics/scaler/aspect.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "graphics/scaler/intern.h"
|
||||
#include "graphics/scaler/aspect.h"
|
||||
|
||||
#ifdef USE_ARM_NEON_ASPECT_CORRECTOR
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
#define kSuperFastAndUglyAspectMode 0 // No interpolation at all, but super-fast
|
||||
#define kVeryFastAndGoodAspectMode 1 // Good quality with very good speed
|
||||
#define kFastAndVeryGoodAspectMode 2 // Very good quality with good speed
|
||||
#define kSlowAndPerfectAspectMode 3 // Accurate but slow code
|
||||
|
||||
#define ASPECT_MODE kVeryFastAndGoodAspectMode
|
||||
|
||||
|
||||
#if ASPECT_MODE == kSlowAndPerfectAspectMode
|
||||
|
||||
template<typename ColorMask, int scale>
|
||||
static inline uint16 interpolate5(uint16 A, uint16 B) {
|
||||
uint16 r = (uint16)(((A & ColorMask::kRedBlueMask & 0xFF00) * scale + (B & ColorMask::kRedBlueMask & 0xFF00) * (5 - scale)) / 5);
|
||||
uint16 g = (uint16)(((A & ColorMask::kGreenMask) * scale + (B & ColorMask::kGreenMask) * (5 - scale)) / 5);
|
||||
uint16 b = (uint16)(((A & ColorMask::kRedBlueMask & 0x00FF) * scale + (B & ColorMask::kRedBlueMask & 0x00FF) * (5 - scale)) / 5);
|
||||
|
||||
return (uint16)((r & ColorMask::kRedBlueMask & 0xFF00) | (g & ColorMask::kGreenMask) | (b & ColorMask::kRedBlueMask & 0x00FF));
|
||||
}
|
||||
|
||||
|
||||
template<typename ColorMask, int scale>
|
||||
static inline void interpolate5Line(uint16 *dst, const uint16 *srcA, const uint16 *srcB, int width) {
|
||||
// Accurate but slightly slower code
|
||||
while (width--) {
|
||||
*dst++ = interpolate5<ColorMask, scale>(*srcA++, *srcB++);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ASPECT_MODE == kVeryFastAndGoodAspectMode
|
||||
|
||||
#ifdef USE_ARM_NEON_ASPECT_CORRECTOR
|
||||
|
||||
template<typename ColorMask>
|
||||
static void interpolate5LineNeon(uint16 *dst, const uint16 *srcA, const uint16 *srcB, int width, int k1, int k2) {
|
||||
uint16x4_t kRedBlueMask_4 = vdup_n_u16(ColorMask::kRedBlueMask);
|
||||
uint16x4_t kGreenMask_4 = vdup_n_u16(ColorMask::kGreenMask);
|
||||
uint16x4_t k1_4 = vdup_n_u16(k1);
|
||||
uint16x4_t k2_4 = vdup_n_u16(k2);
|
||||
while (width >= 4) {
|
||||
uint16x4_t srcA_4 = vld1_u16(srcA);
|
||||
uint16x4_t srcB_4 = vld1_u16(srcB);
|
||||
uint16x4_t p1_4 = srcB_4;
|
||||
uint16x4_t p2_4 = srcA_4;
|
||||
|
||||
uint16x4_t p1_rb_4 = vand_u16(p1_4, kRedBlueMask_4);
|
||||
uint16x4_t p1_g_4 = vand_u16(p1_4, kGreenMask_4);
|
||||
uint16x4_t p2_rb_4 = vand_u16(p2_4, kRedBlueMask_4);
|
||||
uint16x4_t p2_g_4 = vand_u16(p2_4, kGreenMask_4);
|
||||
|
||||
uint32x4_t tmp_rb_4 = vshrq_n_u32(vmlal_u16(vmull_u16(p2_rb_4, k2_4), p1_rb_4, k1_4), 3);
|
||||
uint32x4_t tmp_g_4 = vshrq_n_u32(vmlal_u16(vmull_u16(p2_g_4, k2_4), p1_g_4, k1_4), 3);
|
||||
uint16x4_t p_rb_4 = vmovn_u32(tmp_rb_4);
|
||||
p_rb_4 = vand_u16(p_rb_4, kRedBlueMask_4);
|
||||
uint16x4_t p_g_4 = vmovn_u32(tmp_g_4);
|
||||
p_g_4 = vand_u16(p_g_4, kGreenMask_4);
|
||||
|
||||
uint16x4_t result_4 = p_rb_4 | p_g_4;
|
||||
vst1_u16(dst, result_4);
|
||||
|
||||
dst += 4;
|
||||
srcA += 4;
|
||||
srcB += 4;
|
||||
width -= 4;
|
||||
}
|
||||
}
|
||||
#endif // USE_ARM_NEON_ASPECT_CORRECTOR
|
||||
|
||||
template<typename ColorMask, int scale>
|
||||
static void interpolate5Line(uint16 *dst, const uint16 *srcA, const uint16 *srcB, int width) {
|
||||
if (scale == 1) {
|
||||
#ifdef USE_NEON_ASPECT_CORRECTOR
|
||||
int width4 = width & ~3;
|
||||
interpolate5LineNeon<ColorMask>(dst, srcA, srcB, width4, 7, 1);
|
||||
srcA += width4;
|
||||
srcB += width4;
|
||||
dst += width4;
|
||||
width -= width4;
|
||||
#endif // USE_ARM_NEON_ASPECT_CORRECTOR
|
||||
while (width--) {
|
||||
*dst++ = interpolate16_7_1<ColorMask>(*srcB++, *srcA++);
|
||||
}
|
||||
} else {
|
||||
#ifdef USE_ARM_NEON_ASPECT_CORRECTOR
|
||||
int width4 = width & ~3;
|
||||
interpolate5LineNeon<ColorMask>(dst, srcA, srcB, width4, 5, 3);
|
||||
srcA += width4;
|
||||
srcB += width4;
|
||||
dst += width4;
|
||||
width -= width4;
|
||||
#endif // USE_ARM_NEON_ASPECT_CORRECTOR
|
||||
while (width--) {
|
||||
*dst++ = interpolate16_5_3<ColorMask>(*srcB++, *srcA++);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ASPECT_MODE == kFastAndVeryGoodAspectMode
|
||||
|
||||
template<typename ColorMask, int scale>
|
||||
static inline void interpolate5Line(uint16 *dst, const uint16 *srcA, const uint16 *srcB, int width) {
|
||||
// For efficiency reasons we blit two pixels at a time, so it is important
|
||||
// that makeRectStretchable() guarantees that the width is even and that
|
||||
// the rect starts on a well-aligned address. (Even where unaligned memory
|
||||
// access is allowed there may be a speed penalty for it.)
|
||||
|
||||
// These asserts are disabled for maximal speed; but I leave them in here
|
||||
// in case other people want to test if the memory alignment (to an
|
||||
// address divisible by 4) is really working properly.
|
||||
//assert(((int)dst & 3) == 0);
|
||||
//assert(((int)srcA & 3) == 0);
|
||||
//assert(((int)srcB & 3) == 0);
|
||||
//assert((width & 1) == 0);
|
||||
|
||||
width /= 2;
|
||||
const uint32 *sA = (const uint32 *)srcA;
|
||||
const uint32 *sB = (const uint32 *)srcB;
|
||||
uint32 *d = (uint32 *)dst;
|
||||
if (scale == 1) {
|
||||
while (width--) {
|
||||
*d++ = interpolate32_3_1<ColorMask>(*sB++, *sA++);
|
||||
}
|
||||
} else {
|
||||
while (width--) {
|
||||
*d++ = interpolate32_1_1<ColorMask>(*sB++, *sA++);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void makeRectStretchable(int &x, int &y, int &w, int &h, bool interpolate) {
|
||||
#if ASPECT_MODE != kSuperFastAndUglyAspectMode
|
||||
if (!interpolate)
|
||||
return;
|
||||
int m = real2Aspect(y) % 6;
|
||||
|
||||
// Ensure that the rect will start on a line that won't have its
|
||||
// colors changed by the stretching function.
|
||||
if (m != 0 && m != 5) {
|
||||
y -= m;
|
||||
h += m;
|
||||
}
|
||||
|
||||
#if ASPECT_MODE == kVeryFastAndGoodAspectMode
|
||||
// Force x to be even, to ensure aligned memory access (this assumes
|
||||
// that each line starts at an even memory location, but that should
|
||||
// be the case on every target anyway).
|
||||
if (x & 1) {
|
||||
x--;
|
||||
w++;
|
||||
}
|
||||
|
||||
// Finally force the width to be even, since we blit 2 pixels at a time.
|
||||
// While this means we may sometimes blit one column more than necessary,
|
||||
// this should actually be faster than having the check for the
|
||||
if (w & 1)
|
||||
w++;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Stretch a 16bpp image vertically by factor 1.2. Used to correct the
|
||||
* aspect-ratio in games using 320x200 pixel graphics with non-qudratic
|
||||
* pixels. Applying this method effectively turns that into 320x240, which
|
||||
* provides the correct aspect-ratio on modern displays.
|
||||
*
|
||||
* The image would normally have occupied y coordinates origSrcY through
|
||||
* origSrcY + height - 1.
|
||||
*
|
||||
* However, we have already placed it at srcY - the aspect-corrected y
|
||||
* coordinate - to allow in-place stretching.
|
||||
*
|
||||
* Therefore, the source image now occupies Y coordinates srcY through
|
||||
* srcY + height - 1, and it should be stretched to Y coordinates srcY
|
||||
* through real2Aspect(srcY + height - 1).
|
||||
*/
|
||||
|
||||
int stretch200To240Nearest(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY, const Graphics::PixelFormat &format) {
|
||||
int maxDstY = real2Aspect(origSrcY + height - 1);
|
||||
int y;
|
||||
const uint8 *startSrcPtr = buf + srcX * format.bytesPerPixel + (srcY - origSrcY) * pitch;
|
||||
uint8 *dstPtr = buf + srcX * format.bytesPerPixel + maxDstY * pitch;
|
||||
|
||||
for (y = maxDstY; y >= srcY; y--) {
|
||||
const uint8 *srcPtr = startSrcPtr + aspect2Real(y) * pitch;
|
||||
if (srcPtr == dstPtr)
|
||||
break;
|
||||
memcpy(dstPtr, srcPtr, format.bytesPerPixel * width);
|
||||
dstPtr -= pitch;
|
||||
}
|
||||
|
||||
return 1 + maxDstY - srcY;
|
||||
}
|
||||
|
||||
template<typename ColorMask>
|
||||
int stretch200To240Interpolated(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY) {
|
||||
int maxDstY = real2Aspect(origSrcY + height - 1);
|
||||
int y;
|
||||
const uint8 *startSrcPtr = buf + srcX * 2 + (srcY - origSrcY) * pitch;
|
||||
uint8 *dstPtr = buf + srcX * 2 + maxDstY * pitch;
|
||||
|
||||
for (y = maxDstY; y >= srcY; y--) {
|
||||
const uint8 *srcPtr = startSrcPtr + aspect2Real(y) * pitch;
|
||||
switch (y % 6) {
|
||||
case 0:
|
||||
case 5:
|
||||
if (srcPtr != dstPtr)
|
||||
memcpy(dstPtr, srcPtr, sizeof(uint16) * width);
|
||||
break;
|
||||
case 1:
|
||||
interpolate5Line<ColorMask, 1>((uint16 *)dstPtr, (const uint16 *)(srcPtr - pitch), (const uint16 *)srcPtr, width);
|
||||
break;
|
||||
case 2:
|
||||
interpolate5Line<ColorMask, 2>((uint16 *)dstPtr, (const uint16 *)(srcPtr - pitch), (const uint16 *)srcPtr, width);
|
||||
break;
|
||||
case 3:
|
||||
interpolate5Line<ColorMask, 2>((uint16 *)dstPtr, (const uint16 *)srcPtr, (const uint16 *)(srcPtr - pitch), width);
|
||||
break;
|
||||
case 4:
|
||||
interpolate5Line<ColorMask, 1>((uint16 *)dstPtr, (const uint16 *)srcPtr, (const uint16 *)(srcPtr - pitch), width);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
dstPtr -= pitch;
|
||||
}
|
||||
|
||||
return 1 + maxDstY - srcY;
|
||||
}
|
||||
|
||||
int stretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY, bool interpolate, const Graphics::PixelFormat &format) {
|
||||
#if ASPECT_MODE != kSuperFastAndUglyAspectMode
|
||||
if (interpolate && format.bytesPerPixel == 2) {
|
||||
if (format.gLoss == 2)
|
||||
return stretch200To240Interpolated<Graphics::ColorMasks<565> >(buf, pitch, width, height, srcX, srcY, origSrcY);
|
||||
else if (format.gLoss == 3)
|
||||
return stretch200To240Interpolated<Graphics::ColorMasks<555> >(buf, pitch, width, height, srcX, srcY, origSrcY);
|
||||
}
|
||||
#endif
|
||||
|
||||
return stretch200To240Nearest(buf, pitch, width, height, srcX, srcY, origSrcY, format);
|
||||
}
|
||||
63
graphics/scaler/aspect.h
Normal file
63
graphics/scaler/aspect.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_SCALER_ASPECT_H
|
||||
#define GRAPHICS_SCALER_ASPECT_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "graphics/scaler.h"
|
||||
|
||||
/**
|
||||
* TODO: explain
|
||||
*/
|
||||
FORCEINLINE int real2Aspect(int y) {
|
||||
return y + (y + 1) / 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: explain
|
||||
*/
|
||||
FORCEINLINE int aspect2Real(int y) {
|
||||
return (y * 5 + 4) / 6;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: explain
|
||||
*/
|
||||
void makeRectStretchable(int &x, int &y, int &w, int &h, bool interpolate);
|
||||
|
||||
/**
|
||||
* TODO: explain
|
||||
*/
|
||||
|
||||
int stretch200To240(uint8 *buf,
|
||||
uint32 pitch,
|
||||
int width,
|
||||
int height,
|
||||
int srcX,
|
||||
int srcY,
|
||||
int origSrcY,
|
||||
bool interpolate,
|
||||
const Graphics::PixelFormat &format);
|
||||
|
||||
int stretch200To240Nearest(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY, const Graphics::PixelFormat &format);
|
||||
|
||||
#endif
|
||||
129
graphics/scaler/dotmatrix.cpp
Normal file
129
graphics/scaler/dotmatrix.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "graphics/scaler/dotmatrix.h"
|
||||
#include "graphics/scaler.h"
|
||||
|
||||
DotMatrixScaler::DotMatrixScaler(const Graphics::PixelFormat &format) : Scaler(format) {
|
||||
_factor = 2;
|
||||
|
||||
if (format.bytesPerPixel == 2) {
|
||||
uint16 *lookup16 = (uint16 *)lookup;
|
||||
lookup16[0] = lookup16[10] = format.RGBToColor(0, 63, 0);
|
||||
lookup16[1] = lookup16[11] = format.RGBToColor(0, 0, 63);
|
||||
lookup16[2] = lookup16[8] = format.RGBToColor(63, 0, 0);
|
||||
lookup16[4] = lookup16[6] =
|
||||
lookup16[12] = lookup16[14] = format.RGBToColor(63, 63, 63);
|
||||
lookup16[3] = lookup16[5] = lookup16[7] =
|
||||
lookup16[9] = lookup16[13] =
|
||||
lookup16[15] = lookup16[16] = format.RGBToColor(0, 0, 0);
|
||||
} else {
|
||||
uint32 *lookup32 = (uint32 *)lookup;
|
||||
lookup32[0] = lookup32[10] = format.ARGBToColor(0, 0, 63, 0);
|
||||
lookup32[1] = lookup32[11] = format.ARGBToColor(0, 0, 0, 63);
|
||||
lookup32[2] = lookup32[8] = format.ARGBToColor(0, 63, 0, 0);
|
||||
lookup32[4] = lookup32[6] =
|
||||
lookup32[12] = lookup32[14] = format.ARGBToColor(0, 63, 63, 63);
|
||||
lookup32[3] = lookup32[5] = lookup32[7] =
|
||||
lookup32[9] = lookup32[13] =
|
||||
lookup32[15] = lookup32[16] = format.ARGBToColor(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DotMatrixScaler::scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
|
||||
if (_format.bytesPerPixel == 2) {
|
||||
scaleIntern<uint16>(srcPtr, srcPitch, dstPtr, dstPitch, width, height, x, y);
|
||||
} else {
|
||||
scaleIntern<uint32>(srcPtr, srcPitch, dstPtr, dstPitch, width, height, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
uint DotMatrixScaler::increaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
uint DotMatrixScaler::decreaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
template<typename Pixel>
|
||||
static inline Pixel DOT(const Pixel *dotmatrix, Pixel c, int j, int i) {
|
||||
return c - ((c >> 2) & dotmatrix[((j & 3) << 2) + (i & 3)]);
|
||||
}
|
||||
|
||||
template<typename Pixel>
|
||||
void DotMatrixScaler::scaleIntern(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
||||
int width, int height, int x, int y) {
|
||||
|
||||
const Pixel *dotmatrix = (Pixel *)lookup;
|
||||
|
||||
const uint32 nextlineSrc = srcPitch / sizeof(Pixel);
|
||||
const Pixel *p = (const Pixel *)srcPtr;
|
||||
|
||||
const uint32 nextlineDst = dstPitch / sizeof(Pixel);
|
||||
Pixel *q = (Pixel *)dstPtr;
|
||||
|
||||
int ja = (y * 2) & 3;
|
||||
int ia = (x * 2) & 3;
|
||||
|
||||
for (int j = 0, jj = 0; j < height; ++j, jj += 2) {
|
||||
for (int i = 0, ii = 0; i < width; ++i, ii += 2) {
|
||||
Pixel c = *(p + i);
|
||||
*(q + ii) = DOT<Pixel>(dotmatrix, c, jj + ja, ii + ia);
|
||||
*(q + ii + 1) = DOT<Pixel>(dotmatrix, c, jj + ja, ii + ia + 1);
|
||||
*(q + ii + nextlineDst) = DOT<Pixel>(dotmatrix, c, jj + ja + 1, ii + ia);
|
||||
*(q + ii + nextlineDst + 1) = DOT<Pixel>(dotmatrix, c, jj + ja + 1, ii + ia+ 1);
|
||||
}
|
||||
p += nextlineSrc;
|
||||
q += nextlineDst << 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DotMatrixPlugin final : public ScalerPluginObject {
|
||||
public:
|
||||
DotMatrixPlugin();
|
||||
|
||||
Scaler *createInstance(const Graphics::PixelFormat &format) const override;
|
||||
|
||||
bool canDrawCursor() const override { return false; }
|
||||
uint extraPixels() const override { return 0; }
|
||||
const char *getName() const override;
|
||||
const char *getPrettyName() const override;
|
||||
};
|
||||
|
||||
DotMatrixPlugin::DotMatrixPlugin() {
|
||||
_factors.push_back(2);
|
||||
}
|
||||
|
||||
Scaler *DotMatrixPlugin::createInstance(const Graphics::PixelFormat &format) const {
|
||||
return new DotMatrixScaler(format);
|
||||
}
|
||||
|
||||
const char *DotMatrixPlugin::getName() const {
|
||||
return "dotmatrix";
|
||||
}
|
||||
|
||||
const char *DotMatrixPlugin::getPrettyName() const {
|
||||
return "DotMatrix";
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(DOTMATRIX, PLUGIN_TYPE_SCALER, DotMatrixPlugin);
|
||||
43
graphics/scaler/dotmatrix.h
Normal file
43
graphics/scaler/dotmatrix.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_SCALER_DOTMATRIX_H
|
||||
#define GRAPHICS_SCALER_DOTMATRIX_H
|
||||
|
||||
#include "graphics/scalerplugin.h"
|
||||
|
||||
class DotMatrixScaler : public Scaler {
|
||||
public:
|
||||
DotMatrixScaler(const Graphics::PixelFormat &format);
|
||||
uint increaseFactor() override;
|
||||
uint decreaseFactor() override;
|
||||
protected:
|
||||
virtual void scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) override;
|
||||
private:
|
||||
// Allocate enough for 32bpp formats
|
||||
uint32 lookup[17];
|
||||
template<typename Pixel>
|
||||
void scaleIntern(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr,
|
||||
uint32 dstPitch, int width, int height, int x, int y);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
146
graphics/scaler/downscaler.cpp
Normal file
146
graphics/scaler/downscaler.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "common/debug.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/scaler/downscaler.h"
|
||||
#include "graphics/scaler/intern.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
#ifdef USE_ARM_SCALER_ASM
|
||||
extern "C" {
|
||||
void downscaleAllByHalfARM(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height, int mask, int round);
|
||||
}
|
||||
|
||||
void downscaleAllByHalf(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height, int gBitFormat) {
|
||||
// Rounding constants and masks used for different pixel formats
|
||||
static const int roundingconstants[] = { 0x00200802, 0x00201002 };
|
||||
static const int redbluegreenMasks[] = { 0x03E07C1F, 0x07E0F81F };
|
||||
|
||||
const int maskUsed = (gBitFormat == 565);
|
||||
downscaleAllByHalfARM(srcPtr, srcPitch, dstPtr, dstPitch, width, height, redbluegreenMasks[maskUsed], roundingconstants[maskUsed]);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<typename ColorMask>
|
||||
void downscaleAllByHalfTemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
|
||||
uint8 *work;
|
||||
uint16 srcPitch16 = (uint16)(srcPitch / sizeof(uint16));
|
||||
|
||||
while ((height -= 2) >= 0) {
|
||||
work = dstPtr;
|
||||
|
||||
for (int i=0; i<width; i+=2) {
|
||||
// Another lame filter attempt :)
|
||||
uint16 color1 = *(((const uint16 *)srcPtr) + i);
|
||||
uint16 color2 = *(((const uint16 *)srcPtr) + (i + 1));
|
||||
uint16 color3 = *(((const uint16 *)srcPtr) + (i + srcPitch16));
|
||||
uint16 color4 = *(((const uint16 *)srcPtr) + (i + srcPitch16 + 1));
|
||||
*(((uint16 *)work) + 0) = interpolate16_1_1_1_1<ColorMask>(color1, color2, color3, color4);
|
||||
|
||||
work += sizeof(uint16);
|
||||
}
|
||||
srcPtr += 2 * srcPitch;
|
||||
dstPtr += dstPitch;
|
||||
}
|
||||
}
|
||||
|
||||
void downscaleAllByHalf(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height, int gBitFormat) {
|
||||
if (gBitFormat == 565)
|
||||
downscaleAllByHalfTemplate<Graphics::ColorMasks<565> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
else
|
||||
downscaleAllByHalfTemplate<Graphics::ColorMasks<555> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
uint32 getBrightness(byte col, const byte *pal) {
|
||||
return pal[3 * col] * pal[3 * col] + pal[3 * col + 1] * pal[3 * col + 1] + pal[3 * col + 2] * pal[3 * col + 2];
|
||||
}
|
||||
|
||||
void downscaleCLUT8ByHalf(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int maxX, int maxY, const byte *palette) {
|
||||
const byte *src1 = srcPtr;
|
||||
const byte *src2 = srcPtr + srcPitch;
|
||||
byte *dst = dstPtr;
|
||||
int32 srcSkip = 2 * srcPitch - maxX * 2;
|
||||
int32 dstSkip = dstPitch - maxX;
|
||||
for (int y = 0; y < maxY; y++) {
|
||||
for (int x = 0; x < maxX; x++) {
|
||||
// Choose the brightest pixel. Writing often is bright on
|
||||
// a dark background, so this preserves text as much as we can.
|
||||
byte colors[4] = {
|
||||
*src1++,
|
||||
*src1++,
|
||||
*src2++,
|
||||
*src2++
|
||||
};
|
||||
|
||||
byte col = colors[0];
|
||||
uint32 bri = getBrightness(col, palette);
|
||||
for (uint i = 1; i < 4; i++) {
|
||||
uint32 nbri = getBrightness(colors[i], palette);
|
||||
if (nbri > bri) {
|
||||
bri = nbri;
|
||||
col = colors[i];
|
||||
}
|
||||
}
|
||||
|
||||
*dst++ = col;
|
||||
}
|
||||
src1 += srcSkip;
|
||||
src2 += srcSkip;
|
||||
dst += dstSkip;
|
||||
}
|
||||
}
|
||||
|
||||
} // end of anonymous namespsce
|
||||
|
||||
void downscaleSurfaceByHalf(Surface *out, const Surface *in, const byte *palette) {
|
||||
if (in->format.isCLUT8() && out->format.isCLUT8() && palette != nullptr) {
|
||||
downscaleCLUT8ByHalf((const byte *) in->getBasePtr(0, 0), in->pitch, (byte *) out->getBasePtr(0, 0), out->pitch,
|
||||
MIN<int>(out->w, in->w / 2), MIN<int>(out->h, in->h / 2), palette);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((in->format == PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)
|
||||
&& out->format == PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0))
|
||||
|| (in->format == PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0)
|
||||
&& out->format == PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0))) {
|
||||
downscaleAllByHalf((const byte *) in->getBasePtr(0, 0), in->pitch, (byte *) out->getBasePtr(0, 0), out->pitch,
|
||||
MIN<int>(in->w, out->w * 2), MIN<int>(in->h, out->h * 2), 565);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((in->format == PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)
|
||||
&& out->format == PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0))
|
||||
|| (in->format == PixelFormat(2, 5, 5, 5, 0, 0, 5, 10, 0)
|
||||
&& out->format == PixelFormat(2, 5, 5, 5, 0, 0, 5, 10, 0))) {
|
||||
downscaleAllByHalf((const byte *) in->getBasePtr(0, 0), in->pitch, (byte *) out->getBasePtr(0, 0), out->pitch,
|
||||
MIN<int>(in->w, out->w * 2), MIN<int>(in->h, out->h * 2), 555);
|
||||
return;
|
||||
}
|
||||
|
||||
error("downscaleCLUT8ByHalf(): Unsupported downscale format %s->%s", in->format.toString().c_str(), out->format.toString().c_str());
|
||||
}
|
||||
|
||||
} // end of namespace Graphics
|
||||
40
graphics/scaler/downscaler.h
Normal file
40
graphics/scaler/downscaler.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_SCALER_DOWNSCALER_H
|
||||
#define GRAPHICS_SCALER_DOWNSCALER_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Graphics {
|
||||
/**
|
||||
* This filter (down)scales the source image by a factor of 1/2.
|
||||
* For example, a 320x200 image is scaled to 160x100.
|
||||
*/
|
||||
extern void downscaleAllByHalf(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr,
|
||||
uint32 dstPitch, int width, int height, int gBits = 565);
|
||||
|
||||
void downscaleSurfaceByHalf(Surface *out, const Surface *in, const byte *palette);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
184
graphics/scaler/downscalerARM.s
Normal file
184
graphics/scaler/downscalerARM.s
Normal file
@@ -0,0 +1,184 @@
|
||||
@ ScummVM - Graphic Adventure Engine
|
||||
@
|
||||
@ ScummVM is the legal property of its developers, whose names
|
||||
@ are too numerous to list here. Please refer to the COPYRIGHT
|
||||
@ file distributed with this source distribution.
|
||||
@
|
||||
@ This program is free software: you can redistribute it and/or modify
|
||||
@ it under the terms of the GNU General Public License as published by
|
||||
@ the Free Software Foundation, either version 3 of the License, or
|
||||
@ (at your option) any later version.
|
||||
@
|
||||
@ This program is distributed in the hope that it will be useful,
|
||||
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
@ GNU General Public License for more details.
|
||||
@
|
||||
@ You should have received a copy of the GNU General Public License
|
||||
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@
|
||||
@ @author Robin Watts (robin@wss.co.uk)
|
||||
|
||||
.text
|
||||
|
||||
.global downscaleAllByHalfARM
|
||||
|
||||
@ ARM implementation of DownscaleAllByHalf scaler.
|
||||
@ Scales a width x height block of 16bpp pixels from srcPtr to
|
||||
@ dstPtr. srcPitch and dstPitch identify how to reach subsequent
|
||||
@ lines. redblueMask and round allow for one routine to do both
|
||||
@ 565 and 555 formats.
|
||||
.align 2
|
||||
downscaleAllByHalfARM:
|
||||
@ r0 = srcPtr
|
||||
@ r1 = srcPitch
|
||||
@ r2 = dstPtr
|
||||
@ r3 = dstPitch
|
||||
MOV r12,r13
|
||||
STMFD r13!,{r4-r11,r14}
|
||||
LDMIA r12,{r4-r7}
|
||||
@ r4 = width
|
||||
@ r5 = height
|
||||
@ r6 = redblueMask
|
||||
@ r7 = round
|
||||
|
||||
SUB r3,r3,r4 @ dstPitch -= width
|
||||
SUBS r5,r5,#2 @ while ((height-=2) >= 0)
|
||||
BLT end
|
||||
height_loop:
|
||||
|
||||
SUBS r11, r4, #8 @ r11= width_minus_8
|
||||
BLT thin
|
||||
|
||||
width_loop:
|
||||
@ unroll loop 4 times here
|
||||
LDRH r8,[r0],r1 @ r8 = A = srcPtr[0]
|
||||
LDRH r9,[r0],#2 @ r9 = C = srcPtr[dstPitch]
|
||||
LDRH r12,[r0],-r1 @ r12= D = srcPtr[dstPitch+2]
|
||||
LDRH r14,[r0],#2 @ r14= B = srcPtr[2]
|
||||
|
||||
ORR r8, r8, r8, LSL #16 @ r8 = b | g | r | b | g | r
|
||||
ORR r9, r9, r9, LSL #16 @ r9 = b | g | r | b | g | r
|
||||
ORR r12,r12,r12,LSL #16 @ r12= b | g | r | b | g | r
|
||||
ORR r14,r14,r14,LSL #16 @ r14= b | g | r | b | g | r
|
||||
AND r8, r8, r6 @ r8 = 0 | g | 0 | b | 0 | r
|
||||
AND r9, r9, r6 @ r9 = 0 | g | 0 | b | 0 | r
|
||||
AND r12,r12,r6 @ r12= 0 | g | 0 | b | 0 | r
|
||||
AND r14,r14,r6 @ r14= 0 | g | 0 | b | 0 | r
|
||||
ADD r8, r8, r9
|
||||
ADD r8, r8, r12
|
||||
ADD r8, r8, r14
|
||||
ADD r8, r8, r7 @ r8 = summed pixels + rounding
|
||||
AND r8, r6, r8, LSR #2 @ r8 = 0 | g | 0 | b | 0 | r
|
||||
ORR r10,r8, r8, LSR #16 @ r10= 0 | g | 0 | b | g | r
|
||||
|
||||
LDRH r8,[r0],r1 @ r8 = A = srcPtr[0]
|
||||
LDRH r9,[r0],#2 @ r9 = C = srcPtr[dstPitch]
|
||||
LDRH r12,[r0],-r1 @ r12= D = srcPtr[dstPitch+2]
|
||||
LDRH r14,[r0],#2 @ r14= B = srcPtr[2]
|
||||
|
||||
STRH r10,[r2],#2 @ *dstPtr++
|
||||
|
||||
ORR r8, r8, r8, LSL #16 @ r8 = b | g | r | b | g | r
|
||||
ORR r9, r9, r9, LSL #16 @ r9 = b | g | r | b | g | r
|
||||
ORR r12,r12,r12,LSL #16 @ r12= b | g | r | b | g | r
|
||||
ORR r14,r14,r14,LSL #16 @ r14= b | g | r | b | g | r
|
||||
AND r8, r8, r6 @ r8 = 0 | g | 0 | b | 0 | r
|
||||
AND r9, r9, r6 @ r9 = 0 | g | 0 | b | 0 | r
|
||||
AND r12,r12,r6 @ r12= 0 | g | 0 | b | 0 | r
|
||||
AND r14,r14,r6 @ r14= 0 | g | 0 | b | 0 | r
|
||||
ADD r8, r8, r9
|
||||
ADD r8, r8, r12
|
||||
ADD r8, r8, r14
|
||||
ADD r8, r8, r7 @ r8 = summed pixels + rounding
|
||||
AND r8, r6, r8, LSR #2 @ r8 = 0 | g | 0 | b | 0 | r
|
||||
ORR r10,r8, r8, LSR #16 @ r10= 0 | g | 0 | b | g | r
|
||||
|
||||
LDRH r8,[r0],r1 @ r8 = A = srcPtr[0]
|
||||
LDRH r9,[r0],#2 @ r9 = C = srcPtr[dstPitch]
|
||||
LDRH r12,[r0],-r1 @ r12= D = srcPtr[dstPitch+2]
|
||||
LDRH r14,[r0],#2 @ r14= B = srcPtr[2]
|
||||
|
||||
STRH r10,[r2],#2 @ *dstPtr++
|
||||
|
||||
ORR r8, r8, r8, LSL #16 @ r8 = b | g | r | b | g | r
|
||||
ORR r9, r9, r9, LSL #16 @ r9 = b | g | r | b | g | r
|
||||
ORR r12,r12,r12,LSL #16 @ r12= b | g | r | b | g | r
|
||||
ORR r14,r14,r14,LSL #16 @ r14= b | g | r | b | g | r
|
||||
AND r8, r8, r6 @ r8 = 0 | g | 0 | b | 0 | r
|
||||
AND r9, r9, r6 @ r9 = 0 | g | 0 | b | 0 | r
|
||||
AND r12,r12,r6 @ r12= 0 | g | 0 | b | 0 | r
|
||||
AND r14,r14,r6 @ r14= 0 | g | 0 | b | 0 | r
|
||||
ADD r8, r8, r9
|
||||
ADD r8, r8, r12
|
||||
ADD r8, r8, r14
|
||||
ADD r8, r8, r7 @ r8 = summed pixels + rounding
|
||||
AND r8, r6, r8, LSR #2 @ r8 = 0 | g | 0 | b | 0 | r
|
||||
ORR r10,r8, r8, LSR #16 @ r10= 0 | g | 0 | b | g | r
|
||||
|
||||
LDRH r8,[r0],r1 @ r8 = A = srcPtr[0]
|
||||
LDRH r9,[r0],#2 @ r9 = C = srcPtr[dstPitch]
|
||||
LDRH r12,[r0],-r1 @ r12= D = srcPtr[dstPitch+2]
|
||||
LDRH r14,[r0],#2 @ r14= B = srcPtr[2]
|
||||
|
||||
STRH r10,[r2],#2 @ *dstPtr++
|
||||
|
||||
ORR r8, r8, r8, LSL #16 @ r8 = b | g | r | b | g | r
|
||||
ORR r9, r9, r9, LSL #16 @ r9 = b | g | r | b | g | r
|
||||
ORR r12,r12,r12,LSL #16 @ r12= b | g | r | b | g | r
|
||||
ORR r14,r14,r14,LSL #16 @ r14= b | g | r | b | g | r
|
||||
AND r8, r8, r6 @ r8 = 0 | g | 0 | b | 0 | r
|
||||
AND r9, r9, r6 @ r9 = 0 | g | 0 | b | 0 | r
|
||||
AND r12,r12,r6 @ r12= 0 | g | 0 | b | 0 | r
|
||||
AND r14,r14,r6 @ r14= 0 | g | 0 | b | 0 | r
|
||||
ADD r8, r8, r9
|
||||
ADD r8, r8, r12
|
||||
ADD r8, r8, r14
|
||||
ADD r8, r8, r7 @ r8 = summed pixels + rounding
|
||||
AND r8, r6, r8, LSR #2 @ r8 = 0 | g | 0 | b | 0 | r
|
||||
ORR r10, r8, r8, LSR #16 @ r8 = 0 | g | 0 | b | g | r
|
||||
|
||||
STRH r10,[r2],#2 @ *dstPtr++
|
||||
|
||||
SUBS r11,r11,#8 @ width_minus_8 -= 8
|
||||
BGE width_loop @ (width_minus_8 >= 0) => do 8+ more
|
||||
|
||||
thin:
|
||||
ADDS r11,r11,#8 @ r11= width
|
||||
BEQ width_end @ if no more left to do, then bail
|
||||
thin_lp:
|
||||
@ single output pixels done in this bit
|
||||
LDRH r8,[r0],r1 @ r8 = A = srcPtr[0]
|
||||
LDRH r9,[r0],#2 @ r9 = C = srcPtr[dstPitch]
|
||||
LDRH r12,[r0],-r1 @ r12= D = srcPtr[dstPitch+2]
|
||||
LDRH r14,[r0],#2 @ r14= B = srcPtr[2]
|
||||
|
||||
ORR r8, r8, r8, LSL #16 @ r8 = b | g | r | b | g | r
|
||||
ORR r9, r9, r9, LSL #16 @ r9 = b | g | r | b | g | r
|
||||
ORR r12,r12,r12,LSL #16 @ r12= b | g | r | b | g | r
|
||||
ORR r14,r14,r14,LSL #16 @ r14= b | g | r | b | g | r
|
||||
AND r8, r8, r6 @ r8 = 0 | g | 0 | b | 0 | r
|
||||
AND r9, r9, r6 @ r9 = 0 | g | 0 | b | 0 | r
|
||||
AND r12,r12,r6 @ r12= 0 | g | 0 | b | 0 | r
|
||||
AND r14,r14,r6 @ r14= 0 | g | 0 | b | 0 | r
|
||||
ADD r8, r8, r9
|
||||
ADD r8, r8, r12
|
||||
ADD r8, r8, r14
|
||||
ADD r8, r8, r7 @ r8 = summed pixels + rounding
|
||||
AND r8, r6, r8, LSR #2 @ r8 = 0 | g | 0 | b | 0 | r
|
||||
ORR r8, r8, r8, LSR #16 @ r8 = 0 | g | 0 | b | g | r
|
||||
|
||||
STRH r8,[r2],#2 @ *dstPtr++
|
||||
|
||||
SUBS r11,r11,#2
|
||||
BGT thin_lp
|
||||
width_end:
|
||||
ADD r2,r2,r3 @ dstPtr += dstPitch
|
||||
ADD r0,r0,r1,LSL #1 @ srcPtr += 2*srcPitch
|
||||
SUB r0,r0,r4,LSL #1 @ srcPtr -= 2*width
|
||||
|
||||
SUBS r5,r5,#2
|
||||
BGE height_loop
|
||||
|
||||
end:
|
||||
LDMFD r13!,{r4-r11,PC}
|
||||
3643
graphics/scaler/edge.cpp
Normal file
3643
graphics/scaler/edge.cpp
Normal file
File diff suppressed because it is too large
Load Diff
173
graphics/scaler/edge.h
Normal file
173
graphics/scaler/edge.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_SCALER_EDGE_H
|
||||
#define GRAPHICS_SCALER_EDGE_H
|
||||
|
||||
#include "graphics/scalerplugin.h"
|
||||
|
||||
class EdgeScaler : public SourceScaler {
|
||||
public:
|
||||
|
||||
EdgeScaler(const Graphics::PixelFormat &format);
|
||||
uint increaseFactor() override;
|
||||
uint decreaseFactor() override;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void internScale(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch,
|
||||
const uint8 *oldSrcPtr, uint32 oldSrcPitch,
|
||||
int width, int height, const uint8 *buffer, uint32 bufferPitch) override;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Choose greyscale bitplane to use, return diff array. Exit early and
|
||||
* return NULL for a block of solid color (all diffs zero).
|
||||
*
|
||||
* No matter how you do it, mapping 3 bitplanes into a single greyscale
|
||||
* bitplane will always result in colors which are very different mapping to
|
||||
* the same greyscale value. Inevitably, these pixels will appear next to
|
||||
* each other at some point in some image, and edge detection on a single
|
||||
* bitplane will behave quite strangely due to them having the same or nearly
|
||||
* the same greyscale values. Calculating distances between pixels using all
|
||||
* three RGB bitplanes is *way* too time consuming, so single bitplane
|
||||
* edge detection is used for speed's sake. In order to try to avoid the
|
||||
* color mapping problems of using a single bitplane, 3 different greyscale
|
||||
* mappings are tested for each 3x3 grid, and the one with the most "signal"
|
||||
* (sum of squares difference from center pixel) is chosen. This usually
|
||||
* results in useable contrast within the 3x3 grid.
|
||||
*
|
||||
* This results in a whopping 25% increase in overall runtime of the filter
|
||||
* over simply using luma or some other single greyscale bitplane, but it
|
||||
* does greatly reduce the amount of errors due to greyscale mapping
|
||||
* problems. I think this is the best compromise between accuracy and
|
||||
* speed, and is still a lot faster than edge detecting over all three RGB
|
||||
* bitplanes. The increase in image quality is well worth the speed hit.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
int16 *chooseGreyscale(typename ColorMask::PixelType *pixels);
|
||||
|
||||
/**
|
||||
* Calculate the distance between pixels in RGB space. Greyscale isn't
|
||||
* accurate enough for choosing nearest-neighbors :( Luma-like weighting
|
||||
* of the individual bitplane distances prior to squaring gives the most
|
||||
* useful results.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
int32 calcPixelDiffNosqrt(typename ColorMask::PixelType pixel1, typename ColorMask::PixelType pixel2);
|
||||
|
||||
/**
|
||||
* Create vectors of all delta grey values from center pixel, with magnitudes
|
||||
* ranging from [1.0, 0.0] (zero difference, maximum difference). Find
|
||||
* the two principle axes of the grid by calculating the eigenvalues and
|
||||
* eigenvectors of the inertia tensor. Use the eigenvectors to calculate the
|
||||
* edge direction. In other words, find the angle of the line that optimally
|
||||
* passes through the 3x3 pattern of pixels.
|
||||
*
|
||||
* Return horizontal (-), vertical (|), diagonal (/,\), multi (*), or none '0'
|
||||
*
|
||||
* Don't replace any of the double math with integer-based approximations,
|
||||
* since everything I have tried has lead to slight mis-detection errors.
|
||||
*/
|
||||
int findPrincipleAxis(int16 *diffs, int16 *bplane,
|
||||
int8 *sim,
|
||||
int32 *return_angle);
|
||||
|
||||
/**
|
||||
* Check for mis-detected arrow patterns. Return 1 (good), 0 (bad).
|
||||
*/
|
||||
template<typename Pixel>
|
||||
int checkArrows(int best_dir, Pixel *pixels, int8 *sim, int half_flag);
|
||||
|
||||
/**
|
||||
* Take original direction, refine it by testing different pixel difference
|
||||
* patterns based on the initial gross edge direction.
|
||||
*
|
||||
* The angle value is not currently used, but may be useful for future
|
||||
* refinement algorithms.
|
||||
*/
|
||||
template<typename Pixel>
|
||||
int refineDirection(char edge_type, Pixel *pixels, int16 *bptr,
|
||||
int8 *sim, double angle);
|
||||
|
||||
/**
|
||||
* "Chess Knight" patterns can be mis-detected, fix easy cases.
|
||||
*/
|
||||
template<typename Pixel>
|
||||
int fixKnights(int sub_type, Pixel *pixels, int8 *sim);
|
||||
|
||||
/**
|
||||
* Initialize various lookup tables
|
||||
*/
|
||||
void initTables(const uint8 *srcPtr, uint32 srcPitch,
|
||||
int width, int height);
|
||||
|
||||
/**
|
||||
* Fill pixel grid with or without interpolation, using the detected edge
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
void antiAliasGrid2x(uint8 *dptr, int dstPitch,
|
||||
typename ColorMask::PixelType *pixels, int sub_type, int16 *bptr,
|
||||
int8 *sim,
|
||||
int interpolate_2x);
|
||||
|
||||
/**
|
||||
* Fill pixel grid without interpolation, using the detected edge
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
void antiAliasGridClean3x(uint8 *dptr, int dstPitch,
|
||||
typename ColorMask::PixelType *pixels, int sub_type, int16 *bptr);
|
||||
|
||||
/**
|
||||
* Perform edge detection, draw the new 2x pixels
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
void antiAliasPass2x(const uint8 *src, uint8 *dst,
|
||||
int w, int h,
|
||||
int srcPitch, int dstPitch,
|
||||
int interpolate_2x,
|
||||
bool haveOldSrc,
|
||||
const uint8 *oldSrc, int oldSrcPitch,
|
||||
const uint8 *buffer, int bufferPitch);
|
||||
|
||||
/**
|
||||
* Perform edge detection, draw the new 3x pixels
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
void antiAliasPass3x(const uint8 *src, uint8 *dst,
|
||||
int w, int h,
|
||||
int srcPitch, int dstPitch,
|
||||
bool haveOldSrc,
|
||||
const uint8* oldSrc, int oldPitch,
|
||||
const uint8 *buffer, int bufferPitch);
|
||||
|
||||
int16 _rgbTable[65536][3]; ///< table lookup for RGB
|
||||
int16 _greyscaleTable[3][65536]; ///< greyscale tables
|
||||
int16 *_chosenGreyscale; ///< pointer to chosen greyscale table
|
||||
int16 *_bptr; ///< too awkward to pass variables
|
||||
int8 _simSum; ///< sum of similarity matrix
|
||||
int16 _greyscaleDiffs[3][8];
|
||||
int16 _bplanes[3][9];
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
5103
graphics/scaler/hq.cpp
Normal file
5103
graphics/scaler/hq.cpp
Normal file
File diff suppressed because it is too large
Load Diff
54
graphics/scaler/hq.h
Normal file
54
graphics/scaler/hq.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_SCALER_HQ_H
|
||||
#define GRAPHICS_SCALER_HQ_H
|
||||
|
||||
#include "graphics/scalerplugin.h"
|
||||
|
||||
#ifdef USE_NASM
|
||||
struct hqx_parameters;
|
||||
#endif
|
||||
|
||||
class HQScaler : public Scaler {
|
||||
public:
|
||||
HQScaler(const Graphics::PixelFormat &format);
|
||||
~HQScaler();
|
||||
uint increaseFactor() override;
|
||||
uint decreaseFactor() override;
|
||||
protected:
|
||||
virtual void scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) override;
|
||||
|
||||
void initLUT(Graphics::PixelFormat format);
|
||||
inline void HQ2x16(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
|
||||
inline void HQ3x16(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
|
||||
inline void HQ2x32(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
|
||||
inline void HQ3x32(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
|
||||
|
||||
uint32 *_RGBtoYUV;
|
||||
#ifdef USE_NASM
|
||||
hqx_parameters *_hqx_params;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
1930
graphics/scaler/hq2x_i386.asm
Normal file
1930
graphics/scaler/hq2x_i386.asm
Normal file
File diff suppressed because it is too large
Load Diff
2509
graphics/scaler/hq3x_i386.asm
Normal file
2509
graphics/scaler/hq3x_i386.asm
Normal file
File diff suppressed because it is too large
Load Diff
526
graphics/scaler/intern.h
Normal file
526
graphics/scaler/intern.h
Normal file
@@ -0,0 +1,526 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_SCALER_INTERN_H
|
||||
#define GRAPHICS_SCALER_INTERN_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "graphics/colormasks.h"
|
||||
|
||||
|
||||
/**
|
||||
* Interpolate two 16 bit pixel *pairs* at once with equal weights 1.
|
||||
* In particular, p1 and p2 can contain two pixels each in the upper
|
||||
* and lower halves.
|
||||
*
|
||||
* This also works for 32 bit pixels.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline uint32 interpolate32_1_1(uint32 p1, uint32 p2) {
|
||||
// Clear the low bit of each channel,
|
||||
// divide each channel by 2,
|
||||
// add the two pixels together,
|
||||
// add 1 to each channel if the lowbits would have added to 2
|
||||
return (((p1 & ColorMask::kHighBitsMask) >> 1) +
|
||||
((p2 & ColorMask::kHighBitsMask) >> 1) +
|
||||
(p1 & p2 & ColorMask::kLowBitsMask));
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate two 16 bit pixel *pairs* at once with weights 3 resp. 1.
|
||||
* In particular, p1 and p2 can contain two pixels/each in the upper
|
||||
* and lower halves.
|
||||
*
|
||||
* This also works for 32 bit pixels.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline uint32 interpolate32_3_1(uint32 p1, uint32 p2) {
|
||||
// Clear the 2 lowest bits of each channel,
|
||||
// divide each channel by 4, multiply p1 by 3
|
||||
// add the two pixels together,
|
||||
uint32 x = ((p1 & ColorMask::qhighBits) >> 2) * 3 + ((p2 & ColorMask::qhighBits) >> 2);
|
||||
// Get 2 lowest bits of each channel,
|
||||
// multiply p1 by 3, add them together, then divide by 4
|
||||
uint32 y = ((p1 & ColorMask::qlowBits) * 3 + (p2 & ColorMask::qlowBits)) >> 2;
|
||||
|
||||
// Use only the low bits of the second result to add to the first result
|
||||
y &= ColorMask::qlowBits;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate two 32 bit pixels with weights 2 and 1 and 1, i.e., (2*p1+p2)/3.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
uint32 interpolate32_2_1(uint32 pixel1, uint32 pixel2) {
|
||||
uint32 rsum, gsum, bsum, asum;
|
||||
|
||||
rsum = ((pixel1 & ColorMask::kRedMask) >> ColorMask::kRedShift) << 1;
|
||||
rsum += ((pixel2 & ColorMask::kRedMask) >> ColorMask::kRedShift);
|
||||
rsum /= 3;
|
||||
rsum <<= ColorMask::kRedShift;
|
||||
|
||||
gsum = ((pixel1 & ColorMask::kGreenMask) >> ColorMask::kGreenShift) << 1;
|
||||
gsum += ((pixel2 & ColorMask::kGreenMask) >> ColorMask::kGreenShift);
|
||||
gsum /= 3;
|
||||
gsum <<= ColorMask::kGreenShift;
|
||||
|
||||
bsum = ((pixel1 & ColorMask::kBlueMask) >> ColorMask::kBlueShift) << 1;
|
||||
bsum += ((pixel2 & ColorMask::kBlueMask) >> ColorMask::kBlueShift);
|
||||
bsum /= 3;
|
||||
bsum <<= ColorMask::kBlueShift;
|
||||
|
||||
asum = ((pixel1 & ColorMask::kAlphaMask) >> ColorMask::kAlphaShift) << 1;
|
||||
asum += ((pixel2 & ColorMask::kAlphaMask) >> ColorMask::kAlphaShift);
|
||||
asum /= 3;
|
||||
asum <<= ColorMask::kAlphaShift;
|
||||
|
||||
return (rsum & ColorMask::kRedMask) | (gsum & ColorMask::kGreenMask) | (bsum & ColorMask::kBlueMask) | (asum & ColorMask::kAlphaMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate two 32 bit pixels with weights 5 and 3 and 1, i.e., (5*p1+3*p2)/8.
|
||||
* @see interpolate_32_3_1 for similar method
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline uint32 interpolate32_5_3(uint32 p1, uint32 p2) {
|
||||
uint32 x = ((p1 & ~ColorMask::kLow3Bits) >> 3) * 5 + ((p2 & ~ColorMask::kLow3Bits) >> 3) * 3;
|
||||
uint32 y = ((p1 & ColorMask::kLow3Bits) * 5 + (p2 & ColorMask::kLow3Bits) * 3) >> 3;
|
||||
|
||||
y &= ColorMask::kLow3Bits;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate two 32 bit pixels with weights 7 and 1, i.e., (7*p1+p2)/8.
|
||||
*
|
||||
* @see interpolate32_3_1 for similar method
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline uint32 interpolate32_7_1(uint32 p1, uint32 p2) {
|
||||
uint32 x = ((p1 & ~ColorMask::kLow3Bits) >> 3) * 7 + ((p2 & ~ColorMask::kLow3Bits) >> 3);
|
||||
uint32 y = ((p1 & ColorMask::kLow3Bits) * 7 + (p2 & ColorMask::kLow3Bits)) >> 3;
|
||||
|
||||
y &= ColorMask::kLow3Bits;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 32 bit pixels with weights 2, 1, and 1, i.e., (2*p1+p2+p3)/4.
|
||||
*
|
||||
* @see interpolate32_3_1 for similar method
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline uint32 interpolate32_2_1_1(uint32 p1, uint32 p2, uint32 p3) {
|
||||
uint32 x = ((p1 & ColorMask::qhighBits) >> 1)
|
||||
+ ((p2 & ColorMask::qhighBits) >> 2)
|
||||
+ ((p3 & ColorMask::qhighBits) >> 2);
|
||||
uint32 y = ((p1 & ColorMask::qlowBits) << 1)
|
||||
+ (p2 & ColorMask::qlowBits)
|
||||
+ (p2 & ColorMask::qlowBits);
|
||||
y >>= 2;
|
||||
y &= ColorMask::qlowBits;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 32 bit pixels with weights 5, 2, and 1, i.e., (5*p1+2*p2+p3)/8.
|
||||
*
|
||||
* @see interpolate32_3_1 for similar method
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline uint32 interpolate32_5_2_1(uint32 p1, uint32 p2, uint32 p3) {
|
||||
uint32 x = ((p1 & ~ColorMask::kLow3Bits) >> 3) * 5
|
||||
+ ((p2 & ~ColorMask::kLow3Bits) >> 3) * 2
|
||||
+ ((p3 & ~ColorMask::kLow3Bits) >> 3);
|
||||
uint32 y = (p1 & ColorMask::kLow3Bits) * 5
|
||||
+ (p2 & ColorMask::kLow3Bits) * 2
|
||||
+ (p2 & ColorMask::kLow3Bits);
|
||||
y >>= 3;
|
||||
y &= ColorMask::kLow3Bits;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 32 bit pixels with weights 6, 1, and 1, i.e., (6*p1+p2+p3)/8.
|
||||
*
|
||||
* @see interpolate32_3_1 for similar method
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline uint32 interpolate32_6_1_1(uint32 p1, uint32 p2, uint32 p3) {
|
||||
uint32 x = ((p1 & ~ColorMask::kLow3Bits) >> 3) * 6
|
||||
+ ((p2 & ~ColorMask::kLow3Bits) >> 3)
|
||||
+ ((p3 & ~ColorMask::kLow3Bits) >> 3);
|
||||
uint32 y = (p1 & ColorMask::kLow3Bits) * 6
|
||||
+ (p2 & ColorMask::kLow3Bits)
|
||||
+ (p2 & ColorMask::kLow3Bits);
|
||||
y >>= 3;
|
||||
y &= ColorMask::kLow3Bits;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 32 bit pixels with weights 2, 3, and 3, i.e., (2*p1+3*(p2+p3))/8.
|
||||
*
|
||||
* @see interpolate32_3_1 for similar method
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline uint32 interpolate32_2_3_3(uint32 p1, uint32 p2, uint32 p3) {
|
||||
uint32 x = ((p1 & ~ColorMask::kLow3Bits) >> 2)
|
||||
+ (((p2 & ~ColorMask::kLow3Bits) >> 3)
|
||||
+ ((p3 & ~ColorMask::kLow3Bits) >> 3)) * 3;
|
||||
uint32 y = (p1 & ColorMask::kLow3Bits) * 2
|
||||
+ ((p2 & ColorMask::kLow3Bits)
|
||||
+ (p2 & ColorMask::kLow3Bits)) * 3;
|
||||
y >>= 3;
|
||||
y &= ColorMask::kLow3Bits;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 32 bit pixels with weights 2, 7, and 7, i.e., (2*p1+7*(p2+p3))/16.
|
||||
*
|
||||
* @see interpolate32_3_1 for similar method
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
inline uint32 interpolate32_2_7_7(uint32 p1, uint32 p2, uint32 p3) {
|
||||
uint32 x = ((p1 & ~ColorMask::kLow4Bits) >> 3)
|
||||
+ (((p2 & ~ColorMask::kLow4Bits) >> 4)
|
||||
+ ((p3 & ~ColorMask::kLow4Bits) >> 4)) * 7;
|
||||
uint32 y = (p1 & ColorMask::kLow4Bits) * 2
|
||||
+ ((p2 & ColorMask::kLow4Bits)
|
||||
+ (p2 & ColorMask::kLow4Bits)) * 7;
|
||||
y >>= 4;
|
||||
y &= ColorMask::kLow4Bits;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
// Dummy specializations.
|
||||
template<>
|
||||
inline uint32 interpolate32_2_7_7<Graphics::ColorMasks<555> >(uint32 p1, uint32 p2, uint32 p3) {
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint32 interpolate32_2_7_7<Graphics::ColorMasks<565> >(uint32 p1, uint32 p2, uint32 p3) {
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 32 bit pixels with weights 14, 1, and 1, i.e., (14*p1+p2+p3)/16.
|
||||
*
|
||||
* @see interpolate32_3_1 for similar method
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
inline uint32 interpolate32_14_1_1(uint32 p1, uint32 p2, uint32 p3) {
|
||||
uint32 x = ((p1 & ~ColorMask::kLow4Bits) >> 4) * 14
|
||||
+ ((p2 & ~ColorMask::kLow4Bits) >> 4)
|
||||
+ ((p3 & ~ColorMask::kLow4Bits) >> 4);
|
||||
uint32 y = (p1 & ColorMask::kLow4Bits) * 14
|
||||
+ (p2 & ColorMask::kLow4Bits)
|
||||
+ (p2 & ColorMask::kLow4Bits);
|
||||
y >>= 4;
|
||||
y &= ColorMask::kLow4Bits;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
|
||||
// Dummy specializations.
|
||||
template<>
|
||||
inline uint32 interpolate32_14_1_1<Graphics::ColorMasks<555> >(uint32 p1, uint32 p2, uint32 p3) {
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint32 interpolate32_14_1_1<Graphics::ColorMasks<565> >(uint32 p1, uint32 p2, uint32 p3) {
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 32 bit pixels with weights 1, 1, and 1, i.e., (p1+p2+p3)/3.
|
||||
*/
|
||||
|
||||
template<typename ColorMask>
|
||||
uint32 interpolate32_1_1_1(uint32 pixel1, uint32 pixel2, uint32 pixel3) {
|
||||
uint32 rsum, gsum, bsum;
|
||||
|
||||
rsum = ((pixel1 & ColorMask::kRedMask) >> ColorMask::kRedShift);
|
||||
rsum += ((pixel2 & ColorMask::kRedMask) >> ColorMask::kRedShift);
|
||||
rsum += ((pixel3 & ColorMask::kRedMask) >> ColorMask::kRedShift);
|
||||
rsum /= 3;
|
||||
rsum <<= ColorMask::kRedShift;
|
||||
|
||||
gsum = ((pixel1 & ColorMask::kGreenMask) >> ColorMask::kGreenShift);
|
||||
gsum += ((pixel2 & ColorMask::kGreenMask) >> ColorMask::kGreenShift);
|
||||
gsum += ((pixel3 & ColorMask::kGreenMask) >> ColorMask::kGreenShift);
|
||||
gsum /= 3;
|
||||
gsum <<= ColorMask::kGreenShift;
|
||||
|
||||
bsum = ((pixel1 & ColorMask::kBlueMask) >> ColorMask::kBlueShift);
|
||||
bsum += ((pixel2 & ColorMask::kBlueMask) >> ColorMask::kBlueShift);
|
||||
bsum += ((pixel3 & ColorMask::kBlueMask) >> ColorMask::kBlueShift);
|
||||
bsum /= 3;
|
||||
bsum <<= ColorMask::kBlueShift;
|
||||
|
||||
return (rsum & ColorMask::kRedMask) | (gsum & ColorMask::kGreenMask) | (bsum & ColorMask::kBlueMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate four 32 bit pixels with weights 1, 1, 1, and 1, i.e., (p1+p2+p3+p4)/4.
|
||||
*
|
||||
* @see interpolate32_3_1 for similar method
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline uint32 interpolate32_1_1_1_1(uint32 p1, uint32 p2, uint32 p3, uint32 p4) {
|
||||
uint32 x = ((p1 & ~ColorMask::kLow2Bits) >> 2)
|
||||
+ ((p2 & ~ColorMask::kLow2Bits) >> 2)
|
||||
+ ((p3 & ~ColorMask::kLow2Bits) >> 2)
|
||||
+ ((p4 & ~ColorMask::kLow2Bits) >> 2);
|
||||
uint32 y = (p1 & ColorMask::kLow2Bits)
|
||||
+ (p2 & ColorMask::kLow2Bits)
|
||||
+ (p3 & ColorMask::kLow2Bits)
|
||||
+ (p4 & ColorMask::kLow2Bits);
|
||||
y >>= 2;
|
||||
y &= ColorMask::kLow2Bits;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interpolate two 16 bit pixels with weights 1 and 1, i.e., (p1+p2)/2.
|
||||
* See <https://www.slack.net/~ant/info/rgb_mixing.html> for details on how this works.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline unsigned interpolate16_1_1(unsigned p1, unsigned p2) {
|
||||
const unsigned lowbits = (p1 ^ p2) & ColorMask::kLowBits;
|
||||
return ((p1 + p2) - lowbits) >> 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate two 16 bit pixels with weights 3 and 1, i.e., (3*p1+p2)/4.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline unsigned interpolate16_3_1(unsigned p1, unsigned p2) {
|
||||
const unsigned lowbits = (((p1 & ColorMask::kLowBits) << 1) + (p1 & ColorMask::kLow2Bits)
|
||||
+ (p2 & ColorMask::kLow2Bits)) & ColorMask::kLow2Bits;
|
||||
return ((p1*3 + p2) - lowbits) >> 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate two 16 bit pixels with weights 2 and 1, i.e., (2*p1+p2)/3.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
uint16 interpolate16_2_1(uint16 pixel1, uint16 pixel2) {
|
||||
uint32 rsum;
|
||||
uint16 gsum, bsum;
|
||||
|
||||
rsum = (pixel1 & ColorMask::kRedMask) << 1;
|
||||
rsum += (pixel2 & ColorMask::kRedMask);
|
||||
rsum /= 3;
|
||||
|
||||
gsum = (pixel1 & ColorMask::kGreenMask) << 1;
|
||||
gsum += (pixel2 & ColorMask::kGreenMask);
|
||||
gsum /= 3;
|
||||
|
||||
bsum = (pixel1 & ColorMask::kBlueMask) << 1;
|
||||
bsum += (pixel2 & ColorMask::kBlueMask);
|
||||
bsum /= 3;
|
||||
|
||||
return (rsum & ColorMask::kRedMask) | (gsum & ColorMask::kGreenMask) | (bsum & ColorMask::kBlueMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate two 16 bit pixels with weights 5 and 3 and 1, i.e., (5*p1+3*p2)/8.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline unsigned interpolate16_5_3(unsigned p1, unsigned p2) {
|
||||
const unsigned lowbits = (((p1 & ColorMask::kLowBits) << 2) + (p1 & ColorMask::kLow3Bits)
|
||||
+ ((p2 & ColorMask::kLow2Bits) << 1) + (p2 & ColorMask::kLow3Bits)) & ColorMask::kLow3Bits;
|
||||
return ((p1*5 + p2*3) - lowbits) >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate two 16 bit pixels with weights 7 and 1, i.e., (7*p1+p2)/8.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline unsigned interpolate16_7_1(unsigned p1, unsigned p2) {
|
||||
const unsigned lowbits = (((p1 & ColorMask::kLowBits) << 2) + ((p1 & ColorMask::kLow2Bits) << 1) + (p1 & ColorMask::kLow3Bits)
|
||||
+ (p2 & ColorMask::kLow3Bits)) & ColorMask::kLow3Bits;
|
||||
return ((p1*7+p2) - lowbits) >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 16 bit pixels with weights 2, 1, and 1, i.e., (2*p1+p2+p3)/4.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline unsigned interpolate16_2_1_1(unsigned p1, unsigned p2, unsigned p3) {
|
||||
p1<<=1;
|
||||
const unsigned lowbits = ((p1 & (ColorMask::kLowBits << 1))
|
||||
+ (p2 & ColorMask::kLow2Bits)
|
||||
+ (p3 & ColorMask::kLow2Bits)) & ColorMask::kLow2Bits;
|
||||
return ((p1+p2+p3) - lowbits) >> 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 16 bit pixels with weights 5, 2, and 1, i.e., (5*p1+2*p2+p3)/8.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline unsigned interpolate16_5_2_1(unsigned p1, unsigned p2, unsigned p3) {
|
||||
p2<<=1;
|
||||
const unsigned lowbits = (((p1 & ColorMask::kLowBits) << 2) + (p1 & ColorMask::kLow3Bits)
|
||||
+ (p2 & (ColorMask::kLow2Bits << 1))
|
||||
+ (p3 & ColorMask::kLow3Bits)) & ColorMask::kLow3Bits;
|
||||
return ((p1*5 + p2 + p3) - lowbits) >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 16 bit pixels with weights 6, 1, and 1, i.e., (6*p1+p2+p3)/8.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline unsigned interpolate16_6_1_1(unsigned p1, unsigned p2, unsigned p3) {
|
||||
const unsigned lowbits = (((((p1 & ColorMask::kLowBits) << 1) + (p1 & ColorMask::kLow2Bits)) << 1)
|
||||
+ (p2 & ColorMask::kLow3Bits)
|
||||
+ (p3 & ColorMask::kLow3Bits)) & ColorMask::kLow3Bits;
|
||||
return ((p1*6 + p2 + p3) - lowbits) >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 16 bit pixels with weights 2, 3, and 3, i.e., (2*p1+3*(p2+p3))/8.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline unsigned interpolate16_2_3_3(unsigned p1, unsigned p2, unsigned p3) {
|
||||
p1 <<= 1;
|
||||
const unsigned rb = (p1 & (ColorMask::kRedBlueMask<<1))
|
||||
+ ((p2 & ColorMask::kRedBlueMask) + (p3 & ColorMask::kRedBlueMask))*3;
|
||||
const unsigned g = (p1 & (ColorMask::kGreenMask<<1))
|
||||
+ ((p2 & ColorMask::kGreenMask) + (p3 & ColorMask::kGreenMask))*3;
|
||||
return ((rb & (ColorMask::kRedBlueMask<<3)) | (g & (ColorMask::kGreenMask<<3))) >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 16 bit pixels with weights 2, 7, and 7, i.e., (2*p1+7*(p2+p3))/16.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline unsigned interpolate16_2_7_7(unsigned p1, unsigned p2, unsigned p3) {
|
||||
p1 <<= 1;
|
||||
const unsigned rb = (p1 & (ColorMask::kRedBlueMask<<1))
|
||||
+ ((p2 & ColorMask::kRedBlueMask) + (p3 & ColorMask::kRedBlueMask))*7;
|
||||
const unsigned g = (p1 & (ColorMask::kGreenMask<<1))
|
||||
+ ((p2 & ColorMask::kGreenMask) + (p3 & ColorMask::kGreenMask))*7;
|
||||
return ((rb & (ColorMask::kRedBlueMask<<4)) | (g & (ColorMask::kGreenMask<<4))) >> 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 16 bit pixels with weights 14, 1, and 1, i.e., (14*p1+p2+p3)/16.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline unsigned interpolate16_14_1_1(unsigned p1, unsigned p2, unsigned p3) {
|
||||
const unsigned rb = (p1&ColorMask::kRedBlueMask)*14
|
||||
+ (p2&ColorMask::kRedBlueMask)
|
||||
+ (p3&ColorMask::kRedBlueMask);
|
||||
const unsigned g = (p1&ColorMask::kGreenMask)*14
|
||||
+ (p2&ColorMask::kGreenMask) + (p3&ColorMask::kGreenMask);
|
||||
return ((rb&(ColorMask::kRedBlueMask<<4)) | (g&(ColorMask::kGreenMask<<4))) >> 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate three 16 bit pixels with weights 1, 1, and 1, i.e., (p1+p2+p3)/3.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
uint16 interpolate16_1_1_1(uint16 pixel1, uint16 pixel2, uint16 pixel3)
|
||||
{
|
||||
uint32 rsum;
|
||||
uint16 gsum, bsum;
|
||||
|
||||
rsum = (pixel1 & ColorMask::kRedMask);
|
||||
rsum += (pixel2 & ColorMask::kRedMask);
|
||||
rsum += (pixel3 & ColorMask::kRedMask);
|
||||
rsum /= 3;
|
||||
|
||||
gsum = (pixel1 & ColorMask::kGreenMask);
|
||||
gsum += (pixel2 & ColorMask::kGreenMask);
|
||||
gsum += (pixel3 & ColorMask::kGreenMask);
|
||||
gsum /= 3;
|
||||
|
||||
bsum = (pixel1 & ColorMask::kBlueMask);
|
||||
bsum += (pixel2 & ColorMask::kBlueMask);
|
||||
bsum += (pixel3 & ColorMask::kBlueMask);
|
||||
bsum /= 3;
|
||||
|
||||
return (rsum & ColorMask::kRedMask) | (gsum & ColorMask::kGreenMask) | (bsum & ColorMask::kBlueMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolate four 16 bit pixels with weights 1, 1, 1, and 1, i.e., (p1+p2+p3+p4)/4.
|
||||
*/
|
||||
template<typename ColorMask>
|
||||
static inline unsigned interpolate16_1_1_1_1(unsigned p1, unsigned p2, unsigned p3, unsigned p4) {
|
||||
const unsigned lowbits = ((p1 & ColorMask::kLow2Bits)
|
||||
+ (p2 & ColorMask::kLow2Bits)
|
||||
+ (p3 & ColorMask::kLow2Bits)
|
||||
+ (p4 & ColorMask::kLow2Bits)) & ColorMask::kLow2Bits;
|
||||
return ((p1+p2+p3+p4) - lowbits) >> 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two YUV values (encoded 8-8-8) and check if they differ by more than
|
||||
* a certain hard coded threshold. Used by the hq scaler family.
|
||||
*/
|
||||
static inline bool diffYUV(int yuv1, int yuv2) {
|
||||
static const int Ymask = 0x00FF0000;
|
||||
static const int Umask = 0x0000FF00;
|
||||
static const int Vmask = 0x000000FF;
|
||||
static const int trY = 0x00300000;
|
||||
static const int trU = 0x00000700;
|
||||
static const int trV = 0x00000006;
|
||||
|
||||
int diff;
|
||||
int mask;
|
||||
|
||||
diff = ((yuv1 & Umask) - (yuv2 & Umask));
|
||||
mask = diff >> 31; // -1 if value < 0, 0 otherwise
|
||||
diff = (diff ^ mask) - mask; // -1: ~value + 1; 0: value
|
||||
if (diff > trU) return true;
|
||||
|
||||
diff = ((yuv1 & Vmask) - (yuv2 & Vmask));
|
||||
mask = diff >> 31; // -1 if value < 0, 0 otherwise
|
||||
diff = (diff ^ mask) - mask; // -1: ~value + 1; 0: value
|
||||
if (diff > trV) return true;
|
||||
|
||||
diff = ((yuv1 & Ymask) - (yuv2 & Ymask));
|
||||
mask = diff >> 31; // -1 if value < 0, 0 otherwise
|
||||
diff = (diff ^ mask) - mask; // -1: ~value + 1; 0: value
|
||||
if (diff > trY) return true;
|
||||
|
||||
return false;
|
||||
/*
|
||||
return
|
||||
( ( ABS((yuv1 & Ymask) - (yuv2 & Ymask)) > trY ) ||
|
||||
( ABS((yuv1 & Umask) - (yuv2 & Umask)) > trU ) ||
|
||||
( ABS((yuv1 & Vmask) - (yuv2 & Vmask)) > trV ) );
|
||||
*/
|
||||
}
|
||||
|
||||
#endif
|
||||
316
graphics/scaler/normal.cpp
Normal file
316
graphics/scaler/normal.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "graphics/scaler/normal.h"
|
||||
|
||||
#ifdef USE_SCALERS
|
||||
|
||||
/**
|
||||
* Trivial nearest-neighbor 2x scaler.
|
||||
*/
|
||||
template<typename Pixel>
|
||||
void Normal2x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
||||
int width, int height) {
|
||||
uint8 *r;
|
||||
const int b = sizeof(Pixel);
|
||||
|
||||
assert(IS_ALIGNED(dstPtr, 2));
|
||||
while (height--) {
|
||||
r = dstPtr;
|
||||
for (int i = 0; i < width; ++i, r += b * 2) {
|
||||
Pixel color = *(((const Pixel*)srcPtr) + i);
|
||||
|
||||
*(Pixel *)(r) = color;
|
||||
*(Pixel *)(r + b) = color;
|
||||
*(Pixel *)(r + dstPitch) = color;
|
||||
*(Pixel *)(r + b + dstPitch) = color;
|
||||
}
|
||||
srcPtr += srcPitch;
|
||||
dstPtr += dstPitch << 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_ARM_SCALER_ASM
|
||||
extern "C" void Normal2xARM(const uint8 *srcPtr,
|
||||
uint32 srcPitch,
|
||||
uint8 *dstPtr,
|
||||
uint32 dstPitch,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
#else
|
||||
/**
|
||||
* Template Specialization that writes 2 pixels at a time.
|
||||
*/
|
||||
template<>
|
||||
void Normal2x<uint16>(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
||||
int width, int height) {
|
||||
uint8 *r;
|
||||
|
||||
assert(IS_ALIGNED(dstPtr, 4));
|
||||
while (height--) {
|
||||
r = dstPtr;
|
||||
for (int i = 0; i < width; ++i, r += 4) {
|
||||
uint32 color = *(((const uint16*)srcPtr) + i);
|
||||
|
||||
color |= color << 16;
|
||||
|
||||
*(uint32 *)(r) = color;
|
||||
*(uint32 *)(r + dstPitch) = color;
|
||||
}
|
||||
srcPtr += srcPitch;
|
||||
dstPtr += dstPitch << 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Trivial nearest-neighbor 3x scaler.
|
||||
*/
|
||||
template<typename Pixel>
|
||||
void Normal3x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
||||
int width, int height) {
|
||||
uint8 *r;
|
||||
const uint32 dstPitch2 = dstPitch * 2;
|
||||
const uint32 dstPitch3 = dstPitch * 3;
|
||||
const int b = sizeof(Pixel);
|
||||
|
||||
assert(IS_ALIGNED(dstPtr, 2));
|
||||
while (height--) {
|
||||
r = dstPtr;
|
||||
for (int i = 0; i < width; ++i, r += b * 3) {
|
||||
Pixel color = *(((const Pixel *)srcPtr) + i);
|
||||
|
||||
*(Pixel *)(r + b * 0) = color;
|
||||
*(Pixel *)(r + b * 1) = color;
|
||||
*(Pixel *)(r + b * 2) = color;
|
||||
*(Pixel *)(r + b * 0 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 1 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 2 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 0 + dstPitch2) = color;
|
||||
*(Pixel *)(r + b * 1 + dstPitch2) = color;
|
||||
*(Pixel *)(r + b * 2 + dstPitch2) = color;
|
||||
}
|
||||
srcPtr += srcPitch;
|
||||
dstPtr += dstPitch3;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trivial nearest-neighbor 4x scaler.
|
||||
*/
|
||||
template<typename Pixel>
|
||||
void Normal4x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
||||
int width, int height) {
|
||||
uint8 *r;
|
||||
const uint32 dstPitch2 = dstPitch * 2;
|
||||
const uint32 dstPitch3 = dstPitch * 3;
|
||||
const uint32 dstPitch4 = dstPitch * 4;
|
||||
const int b = sizeof(Pixel);
|
||||
|
||||
assert(IS_ALIGNED(dstPtr, 2));
|
||||
while (height--) {
|
||||
r = dstPtr;
|
||||
for (int i = 0; i < width; ++i, r += b * 4) {
|
||||
Pixel color = *(((const Pixel *)srcPtr) + i);
|
||||
|
||||
*(Pixel *)(r + b * 0) = color;
|
||||
*(Pixel *)(r + b * 1) = color;
|
||||
*(Pixel *)(r + b * 2) = color;
|
||||
*(Pixel *)(r + b * 3) = color;
|
||||
*(Pixel *)(r + b * 0 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 1 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 2 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 3 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 0 + dstPitch2) = color;
|
||||
*(Pixel *)(r + b * 1 + dstPitch2) = color;
|
||||
*(Pixel *)(r + b * 2 + dstPitch2) = color;
|
||||
*(Pixel *)(r + b * 3 + dstPitch2) = color;
|
||||
*(Pixel *)(r + b * 0 + dstPitch3) = color;
|
||||
*(Pixel *)(r + b * 1 + dstPitch3) = color;
|
||||
*(Pixel *)(r + b * 2 + dstPitch3) = color;
|
||||
*(Pixel *)(r + b * 3 + dstPitch3) = color;
|
||||
}
|
||||
srcPtr += srcPitch;
|
||||
dstPtr += dstPitch4;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trivial nearest-neighbor 5x scaler.
|
||||
*/
|
||||
template<typename Pixel>
|
||||
void Normal5x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
||||
int width, int height) {
|
||||
uint8 *r;
|
||||
const uint32 dstPitch2 = dstPitch * 2;
|
||||
const uint32 dstPitch3 = dstPitch * 3;
|
||||
const uint32 dstPitch4 = dstPitch * 4;
|
||||
const uint32 dstPitch5 = dstPitch * 5;
|
||||
const int b = sizeof(Pixel);
|
||||
|
||||
assert(IS_ALIGNED(dstPtr, 2));
|
||||
while (height--) {
|
||||
r = dstPtr;
|
||||
for (int i = 0; i < width; ++i, r += b * 5) {
|
||||
Pixel color = *(((const Pixel *)srcPtr) + i);
|
||||
|
||||
*(Pixel *)(r + b * 0) = color;
|
||||
*(Pixel *)(r + b * 1) = color;
|
||||
*(Pixel *)(r + b * 2) = color;
|
||||
*(Pixel *)(r + b * 3) = color;
|
||||
*(Pixel *)(r + b * 4) = color;
|
||||
*(Pixel *)(r + b * 0 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 1 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 2 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 3 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 4 + dstPitch) = color;
|
||||
*(Pixel *)(r + b * 0 + dstPitch2) = color;
|
||||
*(Pixel *)(r + b * 1 + dstPitch2) = color;
|
||||
*(Pixel *)(r + b * 2 + dstPitch2) = color;
|
||||
*(Pixel *)(r + b * 3 + dstPitch2) = color;
|
||||
*(Pixel *)(r + b * 4 + dstPitch2) = color;
|
||||
*(Pixel *)(r + b * 0 + dstPitch3) = color;
|
||||
*(Pixel *)(r + b * 1 + dstPitch3) = color;
|
||||
*(Pixel *)(r + b * 2 + dstPitch3) = color;
|
||||
*(Pixel *)(r + b * 3 + dstPitch3) = color;
|
||||
*(Pixel *)(r + b * 4 + dstPitch3) = color;
|
||||
*(Pixel *)(r + b * 0 + dstPitch4) = color;
|
||||
*(Pixel *)(r + b * 1 + dstPitch4) = color;
|
||||
*(Pixel *)(r + b * 2 + dstPitch4) = color;
|
||||
*(Pixel *)(r + b * 3 + dstPitch4) = color;
|
||||
*(Pixel *)(r + b * 4 + dstPitch4) = color;
|
||||
}
|
||||
srcPtr += srcPitch;
|
||||
dstPtr += dstPitch5;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void NormalScaler::scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
|
||||
#ifdef USE_SCALERS
|
||||
if (_format.bytesPerPixel == 1) {
|
||||
switch (_factor) {
|
||||
case 2:
|
||||
Normal2x<uint8>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
break;
|
||||
case 3:
|
||||
Normal3x<uint8>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
break;
|
||||
case 4:
|
||||
Normal4x<uint8>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
break;
|
||||
case 5:
|
||||
Normal5x<uint8>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
break;
|
||||
}
|
||||
} else if (_format.bytesPerPixel == 2) {
|
||||
switch (_factor) {
|
||||
case 2:
|
||||
#ifdef USE_ARM_SCALER_ASM
|
||||
Normal2xARM(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
#else
|
||||
Normal2x<uint16>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
#endif
|
||||
break;
|
||||
case 3:
|
||||
Normal3x<uint16>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
break;
|
||||
case 4:
|
||||
Normal4x<uint16>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
break;
|
||||
case 5:
|
||||
Normal5x<uint16>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
assert(_format.bytesPerPixel == 4);
|
||||
switch (_factor) {
|
||||
case 2:
|
||||
Normal2x<uint32>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
break;
|
||||
case 3:
|
||||
Normal3x<uint32>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
break;
|
||||
case 4:
|
||||
Normal4x<uint32>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
break;
|
||||
case 5:
|
||||
Normal5x<uint32>(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint NormalScaler::increaseFactor() {
|
||||
#ifdef USE_SCALERS
|
||||
if (_factor < 5)
|
||||
setFactor(_factor + 1);
|
||||
#endif
|
||||
return _factor;
|
||||
}
|
||||
|
||||
uint NormalScaler::decreaseFactor() {
|
||||
#ifdef USE_SCALERS
|
||||
if (_factor > 1)
|
||||
setFactor(_factor - 1);
|
||||
#endif
|
||||
return _factor;
|
||||
}
|
||||
|
||||
|
||||
class NormalPlugin final : public ScalerPluginObject {
|
||||
public:
|
||||
NormalPlugin();
|
||||
|
||||
Scaler *createInstance(const Graphics::PixelFormat &format) const override;
|
||||
|
||||
bool canDrawCursor() const override { return true; }
|
||||
uint extraPixels() const override { return 0; }
|
||||
const char *getName() const override;
|
||||
const char *getPrettyName() const override;
|
||||
};
|
||||
|
||||
NormalPlugin::NormalPlugin() {
|
||||
_factors.push_back(1);
|
||||
#ifdef USE_SCALERS
|
||||
_factors.push_back(2);
|
||||
_factors.push_back(3);
|
||||
_factors.push_back(4);
|
||||
_factors.push_back(5);
|
||||
#endif
|
||||
}
|
||||
|
||||
Scaler *NormalPlugin::createInstance(const Graphics::PixelFormat &format) const {
|
||||
return new NormalScaler(format);
|
||||
}
|
||||
|
||||
const char *NormalPlugin::getName() const {
|
||||
return "normal";
|
||||
}
|
||||
|
||||
const char *NormalPlugin::getPrettyName() const {
|
||||
return "Normal";
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(NORMAL, PLUGIN_TYPE_SCALER, NormalPlugin);
|
||||
37
graphics/scaler/normal.h
Normal file
37
graphics/scaler/normal.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_SCALER_NORMAL_H
|
||||
#define GRAPHICS_SCALER_NORMAL_H
|
||||
|
||||
#include "graphics/scalerplugin.h"
|
||||
|
||||
class NormalScaler : public Scaler {
|
||||
public:
|
||||
NormalScaler(const Graphics::PixelFormat &format) : Scaler(format) { _factor = 1; }
|
||||
uint increaseFactor() override;
|
||||
uint decreaseFactor() override;
|
||||
protected:
|
||||
virtual void scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) override;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
241
graphics/scaler/pm.cpp
Normal file
241
graphics/scaler/pm.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "graphics/scaler/pm.h"
|
||||
#include "graphics/scaler/intern.h"
|
||||
|
||||
//
|
||||
// Code taken from Pablo Medina (aka "pm") (pjmedina3@yahoo.com)
|
||||
// You can find it here: https://web.archive.org/web/20051018114450/http://2xpm.freeservers.com/
|
||||
// Thanks for his great work
|
||||
// Implemented and fixed for ScummVM by Johannes Schickel (aka "LordHoto") (lordhoto [at] gmail [dot] com)
|
||||
//
|
||||
|
||||
#define interpolate_1_1(a,b) (ColorMask::kBytesPerPixel == 2 ? interpolate16_1_1<ColorMask>(a,b) : interpolate32_1_1<ColorMask>(a,b))
|
||||
#define interpolate_3_1(a,b) (ColorMask::kBytesPerPixel == 2 ? interpolate16_3_1<ColorMask>(a,b) : interpolate32_3_1<ColorMask>(a,b))
|
||||
|
||||
template<typename ColorMask>
|
||||
void scaleIntern(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
|
||||
typedef typename ColorMask::PixelType Pixel;
|
||||
|
||||
uint32 nextLineSrc = srcPitch / sizeof(Pixel);
|
||||
uint32 nextLine = dstPitch / sizeof(Pixel);
|
||||
uint32 completeLineSrc = nextLineSrc - width;
|
||||
uint32 completeLine = nextLine - (2*width);
|
||||
|
||||
const Pixel *startAddr2 = (const Pixel*)srcPtr;
|
||||
const Pixel *startAddr1 = startAddr2 - nextLineSrc;
|
||||
const Pixel *startAddr3 = startAddr2 + nextLineSrc;
|
||||
|
||||
Pixel *dstPixel = (Pixel*)dstPtr;
|
||||
int y = height;
|
||||
|
||||
Pixel E[4] = { 0, 0, 0, 0 };
|
||||
|
||||
while (y--) {
|
||||
int x = width;
|
||||
|
||||
while (x--) {
|
||||
//
|
||||
// pA pB pC
|
||||
// pD pE pF
|
||||
// pG pH pI
|
||||
//
|
||||
Pixel pB = startAddr1[0];
|
||||
Pixel pE = startAddr2[0];
|
||||
Pixel pH = startAddr3[0];
|
||||
|
||||
Pixel pA = startAddr1[-1];
|
||||
Pixel pD = startAddr2[-1];
|
||||
Pixel pG = startAddr3[-1];
|
||||
|
||||
Pixel pC = startAddr1[1];
|
||||
Pixel pF = startAddr2[1];
|
||||
Pixel pI = startAddr3[1];
|
||||
|
||||
bool doNotReblit = false;
|
||||
E[0] = E[1] = E[2] = E[3] = pE;
|
||||
|
||||
if (!doNotReblit) {
|
||||
if (pD != pF) {
|
||||
if ((pE != pD) && (pD == pH) && (pD == pI) && (pE != pG)
|
||||
&& ((pD != pG) || (pE != pF) || (pA != pD))
|
||||
&& (!((pD == pA) && (pD == pG) && (pE == pB) && (pE == pF)))) {
|
||||
E[2] = pH;
|
||||
E[3] = interpolate_1_1(E[3], pH);
|
||||
doNotReblit = true;
|
||||
} else if ((pE != pF) && (pF == pH) && (pF == pG) && (pE != pI)
|
||||
&& ((pF != pI) || (pE != pD) || (pC != pF))
|
||||
&& (!((pF == pC) && (pF == pI) && (pE == pB) && (pE == pD)))) {
|
||||
E[2] = interpolate_1_1(E[2], pH);
|
||||
E[3] = pH;
|
||||
doNotReblit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pB != pH) {
|
||||
if (pE != pB) {
|
||||
if ((pA != pB) || (pB != pC) || (pE != pH)) {
|
||||
if ((pB == pD) && (pB == pG) && (pE != pA)
|
||||
&& (!((pD == pA) && (pD == pC) && (pE == pH) && (pE == pF)))) {
|
||||
E[0] = interpolate_3_1( pB,E[0]);
|
||||
E[2] = interpolate_3_1(E[2], pB);
|
||||
doNotReblit = true;
|
||||
} else if ((pB == pF) && (pB == pI) && (pE != pC)
|
||||
&& (!((pF == pC) && (pF == pA) && (pE == pH) && (pE == pD)))) {
|
||||
E[1] = interpolate_3_1(pB, E[1]);
|
||||
E[3] = interpolate_3_1(E[3], pB);
|
||||
doNotReblit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pE != pH) {
|
||||
if ((pG != pH) || (pE != pB) || (pH != pI)) {
|
||||
if ((pH == pD) && (pH == pA) && (pE != pG)
|
||||
&& (!((pD == pG) && (pD == pI) && (pE == pB) && (pE == pF)))) {
|
||||
E[2] = interpolate_3_1( pH,E[2]);
|
||||
E[0] = interpolate_3_1(E[0], pH);
|
||||
doNotReblit = true;
|
||||
} else if ((pH == pF) && (pH == pC) && (pE != pI)
|
||||
&& (!((pF == pI) && (pF == pG) && (pE == pB) && (pE == pD)))) {
|
||||
E[3] = interpolate_3_1( pH,E[3]);
|
||||
E[1] = interpolate_3_1(E[1], pH);
|
||||
doNotReblit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!doNotReblit) {
|
||||
if ((pB != pH) && (pD != pF)) {
|
||||
|
||||
if ((pB == pD) && (pE != pD)
|
||||
&& (!((pE == pA) && (pB == pC) && (pE == pF))) // Block
|
||||
&& (!((pB == pA) && (pB == pG)))
|
||||
&& (!((pD == pA) && (pD == pC) && (pE == pF) && (pG != pD) && (pG != pE))))
|
||||
E[0] = interpolate_1_1(E[0], pB);
|
||||
|
||||
if ((pB == pF) && (pE != pF)
|
||||
&& (!((pE == pC) && (pB == pA) && (pE == pD))) // Block
|
||||
&& (!((pB == pC) && (pB == pI)))
|
||||
&& (!((pF == pA) && (pF == pC) && (pE == pD) && (pI != pF) && (pI != pE))))
|
||||
E[1] = interpolate_1_1(E[1], pB);
|
||||
|
||||
if ((pH == pD) && ((pE != pG) || (pE != pD))
|
||||
&& (!((pE == pG) && (pH == pI) && (pE == pF))) // Block
|
||||
&& (!((pH == pG) && (pH == pA)))
|
||||
&& (!((pD == pG) && (pD == pI) && (pE == pF) && (pA != pD) && (pA != pE))))
|
||||
E[2] = interpolate_1_1(E[2], pH);
|
||||
|
||||
if ((pH == pF) && ((pE != pI) || (pE != pF))
|
||||
&& (!((pE == pI) && (pH == pG) && (pE == pD))) // Block
|
||||
&& (!((pH == pI) && (pH == pC)))
|
||||
&& (!((pF == pG) && (pF == pI) && (pE == pD) && (pC != pF) && (pI != pE))))
|
||||
E[3] = interpolate_1_1(E[3], pH);
|
||||
|
||||
} else if ((pD == pB) && (pD == pF) && (pD == pH) && (pD != pE)) {
|
||||
if ((pD == pG) || (pD == pC)) {
|
||||
E[1] = interpolate_1_1(E[1], pD);
|
||||
E[2] = E[1];
|
||||
}
|
||||
|
||||
if ((pD == pA) || (pD == pI)) {
|
||||
E[0] = interpolate_1_1(E[0], pD);
|
||||
E[3] = E[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dstPixel[0] = E[0];
|
||||
dstPixel[1] = E[1];
|
||||
dstPixel[nextLine] = E[2];
|
||||
dstPixel[nextLine + 1] = E[3];
|
||||
|
||||
startAddr1++;
|
||||
startAddr2++;
|
||||
startAddr3++;
|
||||
|
||||
dstPixel += 2;
|
||||
}
|
||||
|
||||
startAddr2 += completeLineSrc;
|
||||
startAddr1 = startAddr2 - nextLineSrc;
|
||||
startAddr3 = startAddr2 + nextLineSrc;
|
||||
dstPixel += completeLine + nextLine;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PMScaler::scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
|
||||
if (_format.bytesPerPixel == 2) {
|
||||
if (_format.gLoss == 2)
|
||||
::scaleIntern<Graphics::ColorMasks<565> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
else
|
||||
::scaleIntern<Graphics::ColorMasks<555> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
} else {
|
||||
if (_format.aLoss == 0)
|
||||
::scaleIntern<Graphics::ColorMasks<8888> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
else
|
||||
::scaleIntern<Graphics::ColorMasks<888> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
uint PMScaler::increaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
uint PMScaler::decreaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
|
||||
class PMPlugin final : public ScalerPluginObject {
|
||||
public:
|
||||
PMPlugin();
|
||||
|
||||
Scaler *createInstance(const Graphics::PixelFormat &format) const override;
|
||||
|
||||
bool canDrawCursor() const override { return false; }
|
||||
uint extraPixels() const override { return 1; }
|
||||
const char *getName() const override;
|
||||
const char *getPrettyName() const override;
|
||||
};
|
||||
|
||||
|
||||
PMPlugin::PMPlugin() {
|
||||
_factors.push_back(2);
|
||||
}
|
||||
|
||||
Scaler *PMPlugin::createInstance(const Graphics::PixelFormat &format) const {
|
||||
return new PMScaler(format);
|
||||
}
|
||||
|
||||
const char *PMPlugin::getName() const {
|
||||
return "pm";
|
||||
}
|
||||
|
||||
const char *PMPlugin::getPrettyName() const {
|
||||
return "PM";
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(PM, PLUGIN_TYPE_SCALER, PMPlugin);
|
||||
36
graphics/scaler/pm.h
Normal file
36
graphics/scaler/pm.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_SCALER_PM_H
|
||||
#define GRAPHICS_SCALER_PM_H
|
||||
|
||||
#include "graphics/scalerplugin.h"
|
||||
|
||||
class PMScaler : public Scaler {
|
||||
public:
|
||||
PMScaler(const Graphics::PixelFormat &format) : Scaler(format) { _factor = 2; }
|
||||
uint increaseFactor() override;
|
||||
uint decreaseFactor() override;
|
||||
protected:
|
||||
virtual void scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
558
graphics/scaler/sai.cpp
Normal file
558
graphics/scaler/sai.cpp
Normal file
@@ -0,0 +1,558 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "graphics/scaler/sai.h"
|
||||
#include "graphics/scaler/intern.h"
|
||||
|
||||
static inline int GetResult(uint32 A, uint32 B, uint32 C, uint32 D) {
|
||||
const bool ac = (A==C);
|
||||
const bool bc = (B==C);
|
||||
const int x1 = ac;
|
||||
const int y1 = (bc & !ac);
|
||||
const bool ad = (A==D);
|
||||
const bool bd = (B==D);
|
||||
const int x2 = ad;
|
||||
const int y2 = (bd & !ad);
|
||||
const int x = x1+x2;
|
||||
const int y = y1+y2;
|
||||
return (y>>1) - (x>>1);
|
||||
}
|
||||
|
||||
#define interpolate_1_1(a,b) (ColorMask::kBytesPerPixel == 2 ? interpolate16_1_1<ColorMask>(a,b) : interpolate32_1_1<ColorMask>(a,b))
|
||||
#define interpolate_3_1(a,b) (ColorMask::kBytesPerPixel == 2 ? interpolate16_3_1<ColorMask>(a,b) : interpolate32_3_1<ColorMask>(a,b))
|
||||
#define interpolate_6_1_1(a,b,c) (ColorMask::kBytesPerPixel == 2 ? interpolate16_6_1_1<ColorMask>(a,b,c) : interpolate32_6_1_1<ColorMask>(a,b,c))
|
||||
#define interpolate_1_1_1_1(a,b,c,d) (ColorMask::kBytesPerPixel == 2 ? interpolate16_1_1_1_1<ColorMask>(a,b,c,d) : interpolate32_1_1_1_1<ColorMask>(a,b,c,d))
|
||||
|
||||
template<typename ColorMask>
|
||||
void Super2xSaITemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
|
||||
typedef typename ColorMask::PixelType Pixel;
|
||||
|
||||
const Pixel *bP;
|
||||
Pixel *dP;
|
||||
const uint32 nextlineSrc = srcPitch / sizeof(Pixel);
|
||||
|
||||
while (height--) {
|
||||
bP = (const Pixel *)srcPtr;
|
||||
dP = (Pixel *)dstPtr;
|
||||
|
||||
for (int i = 0; i < width; ++i) {
|
||||
unsigned color4, color5, color6;
|
||||
unsigned color1, color2, color3;
|
||||
unsigned colorA0, colorA1, colorA2, colorA3;
|
||||
unsigned colorB0, colorB1, colorB2, colorB3;
|
||||
unsigned colorS1, colorS2;
|
||||
unsigned product1a, product1b, product2a, product2b;
|
||||
|
||||
//--------------------------------------- B1 B2
|
||||
// 4 5 6 S2
|
||||
// 1 2 3 S1
|
||||
// A1 A2
|
||||
|
||||
colorB0 = *(bP - nextlineSrc - 1);
|
||||
colorB1 = *(bP - nextlineSrc);
|
||||
colorB2 = *(bP - nextlineSrc + 1);
|
||||
colorB3 = *(bP - nextlineSrc + 2);
|
||||
|
||||
color4 = *(bP - 1);
|
||||
color5 = *(bP);
|
||||
color6 = *(bP + 1);
|
||||
colorS2 = *(bP + 2);
|
||||
|
||||
color1 = *(bP + nextlineSrc - 1);
|
||||
color2 = *(bP + nextlineSrc);
|
||||
color3 = *(bP + nextlineSrc + 1);
|
||||
colorS1 = *(bP + nextlineSrc + 2);
|
||||
|
||||
colorA0 = *(bP + 2 * nextlineSrc - 1);
|
||||
colorA1 = *(bP + 2 * nextlineSrc);
|
||||
colorA2 = *(bP + 2 * nextlineSrc + 1);
|
||||
colorA3 = *(bP + 2 * nextlineSrc + 2);
|
||||
|
||||
//--------------------------------------
|
||||
if (color2 == color6 && color5 != color3) {
|
||||
product2b = product1b = color2;
|
||||
} else if (color5 == color3 && color2 != color6) {
|
||||
product2b = product1b = color5;
|
||||
} else if (color5 == color3 && color2 == color6) {
|
||||
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_1_1(color5, color6);
|
||||
}
|
||||
} else {
|
||||
if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0)
|
||||
product2b = interpolate_3_1(color3, color2);
|
||||
else if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3)
|
||||
product2b = interpolate_3_1(color2, color3);
|
||||
else
|
||||
product2b = interpolate_1_1(color2, color3);
|
||||
|
||||
if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0)
|
||||
product1b = interpolate_3_1(color6, color5);
|
||||
else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3)
|
||||
product1b = interpolate_3_1(color5, color6);
|
||||
else
|
||||
product1b = interpolate_1_1(color5, color6);
|
||||
}
|
||||
|
||||
if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2)
|
||||
product2a = interpolate_1_1(color2, color5);
|
||||
else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0)
|
||||
product2a = interpolate_1_1(color2, color5);
|
||||
else
|
||||
product2a = color2;
|
||||
|
||||
if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2)
|
||||
product1a = interpolate_1_1(color2, color5);
|
||||
else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0)
|
||||
product1a = interpolate_1_1(color2, color5);
|
||||
else
|
||||
product1a = color5;
|
||||
|
||||
*(dP + 0) = (Pixel) product1a;
|
||||
*(dP + 1) = (Pixel) product1b;
|
||||
*(dP + dstPitch / sizeof(Pixel) + 0) = (Pixel) product2a;
|
||||
*(dP + dstPitch / sizeof(Pixel) + 1) = (Pixel) product2b;
|
||||
|
||||
bP += 1;
|
||||
dP += 2;
|
||||
}
|
||||
|
||||
srcPtr += srcPitch;
|
||||
dstPtr += dstPitch * 2;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ColorMask>
|
||||
void SuperEagleTemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
|
||||
typedef typename ColorMask::PixelType Pixel;
|
||||
|
||||
const Pixel *bP;
|
||||
Pixel *dP;
|
||||
const uint32 nextlineSrc = srcPitch / sizeof(Pixel);
|
||||
|
||||
while (height--) {
|
||||
bP = (const Pixel *)srcPtr;
|
||||
dP = (Pixel *)dstPtr;
|
||||
for (int i = 0; i < width; ++i) {
|
||||
unsigned color4, color5, color6;
|
||||
unsigned color1, color2, color3;
|
||||
unsigned colorA1, colorA2, colorB1, colorB2, colorS1, colorS2;
|
||||
unsigned product1a, product1b, product2a, product2b;
|
||||
|
||||
colorB1 = *(bP - nextlineSrc);
|
||||
colorB2 = *(bP - nextlineSrc + 1);
|
||||
|
||||
color4 = *(bP - 1);
|
||||
color5 = *(bP);
|
||||
color6 = *(bP + 1);
|
||||
colorS2 = *(bP + 2);
|
||||
|
||||
color1 = *(bP + nextlineSrc - 1);
|
||||
color2 = *(bP + nextlineSrc);
|
||||
color3 = *(bP + nextlineSrc + 1);
|
||||
colorS1 = *(bP + nextlineSrc + 2);
|
||||
|
||||
colorA1 = *(bP + 2 * nextlineSrc);
|
||||
colorA2 = *(bP + 2 * nextlineSrc + 1);
|
||||
|
||||
// --------------------------------------
|
||||
if (color5 != color3) {
|
||||
if (color2 == color6) {
|
||||
product1b = product2a = color2;
|
||||
if ((color1 == color2) || (color6 == colorB2)) {
|
||||
product1a = interpolate_3_1(color2, color5);
|
||||
} else {
|
||||
product1a = interpolate_1_1(color5, color6);
|
||||
}
|
||||
|
||||
if ((color6 == colorS2) || (color2 == colorA1)) {
|
||||
product2b = interpolate_3_1(color2, color3);
|
||||
} else {
|
||||
product2b = interpolate_1_1(color2, color3);
|
||||
}
|
||||
} else {
|
||||
product2b = interpolate_6_1_1(color3, color2, color6);
|
||||
product1a = interpolate_6_1_1(color5, color2, color6);
|
||||
|
||||
product2a = interpolate_6_1_1(color2, color5, color3);
|
||||
product1b = interpolate_6_1_1(color6, color5, color3);
|
||||
}
|
||||
} else {
|
||||
if (color2 != color6) {
|
||||
product2b = product1a = color5;
|
||||
|
||||
if ((colorB1 == color5) || (color3 == colorS1)) {
|
||||
product1b = interpolate_3_1(color5, color6);
|
||||
} else {
|
||||
product1b = interpolate_1_1(color5, color6);
|
||||
}
|
||||
|
||||
if ((color3 == colorA2) || (color4 == color5)) {
|
||||
product2a = interpolate_3_1(color5, color2);
|
||||
} else {
|
||||
product2a = interpolate_1_1(color2, color3);
|
||||
}
|
||||
} else {
|
||||
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_1_1(color5, color6);
|
||||
} else if (r < 0) {
|
||||
product2b = product1a = color5;
|
||||
product1b = product2a = interpolate_1_1(color5, color6);
|
||||
} else {
|
||||
product2b = product1a = color5;
|
||||
product1b = product2a = color2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*(dP + 0) = (Pixel) product1a;
|
||||
*(dP + 1) = (Pixel) product1b;
|
||||
*(dP + dstPitch / sizeof(Pixel) + 0) = (Pixel) product2a;
|
||||
*(dP + dstPitch / sizeof(Pixel) + 1) = (Pixel) product2b;
|
||||
|
||||
bP += 1;
|
||||
dP += 2;
|
||||
}
|
||||
|
||||
srcPtr += srcPitch;
|
||||
dstPtr += dstPitch * 2;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ColorMask>
|
||||
void _2xSaITemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
|
||||
typedef typename ColorMask::PixelType Pixel;
|
||||
|
||||
const Pixel *bP;
|
||||
Pixel *dP;
|
||||
const uint32 nextlineSrc = srcPitch / sizeof(Pixel);
|
||||
|
||||
while (height--) {
|
||||
bP = (const Pixel *)srcPtr;
|
||||
dP = (Pixel *)dstPtr;
|
||||
|
||||
for (int i = 0; i < width; ++i) {
|
||||
|
||||
unsigned colorA, colorB;
|
||||
unsigned colorC, colorD,
|
||||
colorE, colorF, colorG, colorH, colorI, colorJ, colorK, colorL, colorM, colorN, colorO;
|
||||
unsigned 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 - nextlineSrc - 1);
|
||||
colorE = *(bP - nextlineSrc);
|
||||
colorF = *(bP - nextlineSrc + 1);
|
||||
colorJ = *(bP - nextlineSrc + 2);
|
||||
|
||||
colorG = *(bP - 1);
|
||||
colorA = *(bP);
|
||||
colorB = *(bP + 1);
|
||||
colorK = *(bP + 2);
|
||||
|
||||
colorH = *(bP + nextlineSrc - 1);
|
||||
colorC = *(bP + nextlineSrc);
|
||||
colorD = *(bP + nextlineSrc + 1);
|
||||
colorL = *(bP + nextlineSrc + 2);
|
||||
|
||||
colorM = *(bP + 2 * nextlineSrc - 1);
|
||||
colorN = *(bP + 2 * nextlineSrc);
|
||||
colorO = *(bP + 2 * nextlineSrc + 1);
|
||||
|
||||
if ((colorA == colorD) && (colorB != colorC)) {
|
||||
if (((colorA == colorE) && (colorB == colorL)) ||
|
||||
((colorA == colorC) && (colorA == colorF) && (colorB != colorE) && (colorB == colorJ))) {
|
||||
product = colorA;
|
||||
} else {
|
||||
product = interpolate_1_1(colorA, colorB);
|
||||
}
|
||||
|
||||
if (((colorA == colorG) && (colorC == colorO)) ||
|
||||
((colorA == colorB) && (colorA == colorH) && (colorG != colorC) && (colorC == colorM))) {
|
||||
product1 = colorA;
|
||||
} else {
|
||||
product1 = interpolate_1_1(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_1_1(colorA, colorB);
|
||||
}
|
||||
|
||||
if (((colorC == colorH) && (colorA == colorF)) ||
|
||||
((colorC == colorG) && (colorC == colorD) && (colorA != colorH) && (colorA == colorI))) {
|
||||
product1 = colorC;
|
||||
} else {
|
||||
product1 = interpolate_1_1(colorA, colorC);
|
||||
}
|
||||
product2 = colorB;
|
||||
} else if ((colorA == colorD) && (colorB == colorC)) {
|
||||
if (colorA == colorB) {
|
||||
product = colorA;
|
||||
product1 = colorA;
|
||||
product2 = colorA;
|
||||
} else {
|
||||
int r = 0;
|
||||
|
||||
product1 = interpolate_1_1(colorA, colorC);
|
||||
product = interpolate_1_1(colorA, colorB);
|
||||
|
||||
r += GetResult(colorA, colorB, colorG, colorE);
|
||||
r -= GetResult(colorB, colorA, colorK, colorF);
|
||||
r -= GetResult(colorB, colorA, colorH, colorN);
|
||||
r += GetResult(colorA, colorB, colorL, colorO);
|
||||
|
||||
if (r > 0)
|
||||
product2 = colorA;
|
||||
else if (r < 0)
|
||||
product2 = colorB;
|
||||
else {
|
||||
product2 = interpolate_1_1_1_1(colorA, colorB, colorC, colorD);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
product2 = interpolate_1_1_1_1(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_1_1(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_1_1(colorA, colorC);
|
||||
}
|
||||
}
|
||||
|
||||
*(dP + 0) = (Pixel) colorA;
|
||||
*(dP + 1) = (Pixel) product;
|
||||
*(dP + dstPitch / sizeof(Pixel) + 0) = (Pixel) product1;
|
||||
*(dP + dstPitch / sizeof(Pixel) + 1) = (Pixel) product2;
|
||||
|
||||
bP += 1;
|
||||
dP += 2;
|
||||
}
|
||||
|
||||
srcPtr += srcPitch;
|
||||
dstPtr += dstPitch * 2;
|
||||
}
|
||||
}
|
||||
|
||||
// SAI
|
||||
|
||||
void SAIScaler::scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
|
||||
if (_format.bytesPerPixel == 2) {
|
||||
if (_format.gLoss == 2)
|
||||
_2xSaITemplate<Graphics::ColorMasks<565> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
else
|
||||
_2xSaITemplate<Graphics::ColorMasks<555> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
} else {
|
||||
if (_format.aLoss == 0)
|
||||
_2xSaITemplate<Graphics::ColorMasks<8888> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
else
|
||||
_2xSaITemplate<Graphics::ColorMasks<888> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
uint SAIScaler::increaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
uint SAIScaler::decreaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
|
||||
class SAIPlugin final : public ScalerPluginObject {
|
||||
public:
|
||||
SAIPlugin();
|
||||
|
||||
Scaler *createInstance(const Graphics::PixelFormat &format) const override;
|
||||
|
||||
bool canDrawCursor() const override { return false; }
|
||||
uint extraPixels() const override { return 2; }
|
||||
const char *getName() const override;
|
||||
const char *getPrettyName() const override;
|
||||
};
|
||||
|
||||
SAIPlugin::SAIPlugin() {
|
||||
_factors.push_back(2);
|
||||
}
|
||||
|
||||
Scaler *SAIPlugin::createInstance(const Graphics::PixelFormat &format) const {
|
||||
return new SAIScaler(format);
|
||||
}
|
||||
|
||||
const char *SAIPlugin::getName() const {
|
||||
return "sai";
|
||||
}
|
||||
|
||||
const char *SAIPlugin::getPrettyName() const {
|
||||
return "SAI";
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(SAI, PLUGIN_TYPE_SCALER, SAIPlugin);
|
||||
|
||||
// SuperSAI
|
||||
|
||||
void SuperSAIScaler::scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
|
||||
if (_format.bytesPerPixel == 2) {
|
||||
if (_format.gLoss == 2)
|
||||
Super2xSaITemplate<Graphics::ColorMasks<565> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
else
|
||||
Super2xSaITemplate<Graphics::ColorMasks<555> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
} else {
|
||||
if (_format.aLoss == 0)
|
||||
Super2xSaITemplate<Graphics::ColorMasks<8888> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
else
|
||||
Super2xSaITemplate<Graphics::ColorMasks<888> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
uint SuperSAIScaler::increaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
uint SuperSAIScaler::decreaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
|
||||
class SuperSAIPlugin final : public ScalerPluginObject {
|
||||
public:
|
||||
SuperSAIPlugin();
|
||||
|
||||
Scaler *createInstance(const Graphics::PixelFormat &format) const override;
|
||||
|
||||
bool canDrawCursor() const override { return false; }
|
||||
uint extraPixels() const override { return 2; }
|
||||
const char *getName() const override;
|
||||
const char *getPrettyName() const override;
|
||||
};
|
||||
|
||||
SuperSAIPlugin::SuperSAIPlugin() {
|
||||
_factors.push_back(2);
|
||||
}
|
||||
|
||||
Scaler *SuperSAIPlugin::createInstance(const Graphics::PixelFormat &format) const {
|
||||
return new SuperSAIScaler(format);
|
||||
}
|
||||
|
||||
const char *SuperSAIPlugin::getName() const {
|
||||
return "supersai";
|
||||
}
|
||||
|
||||
const char *SuperSAIPlugin::getPrettyName() const {
|
||||
return "SuperSAI";
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(SUPERSAI, PLUGIN_TYPE_SCALER, SuperSAIPlugin);
|
||||
|
||||
// SuperEagle
|
||||
|
||||
void SuperEagleScaler::scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
|
||||
if (_format.bytesPerPixel == 2) {
|
||||
if (_format.gLoss == 2)
|
||||
SuperEagleTemplate<Graphics::ColorMasks<565> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
else
|
||||
SuperEagleTemplate<Graphics::ColorMasks<555> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
} else {
|
||||
if (_format.aLoss == 0)
|
||||
SuperEagleTemplate<Graphics::ColorMasks<8888> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
else
|
||||
SuperEagleTemplate<Graphics::ColorMasks<888> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
uint SuperEagleScaler::increaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
uint SuperEagleScaler::decreaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
|
||||
class SuperEaglePlugin final : public ScalerPluginObject {
|
||||
public:
|
||||
SuperEaglePlugin();
|
||||
|
||||
Scaler *createInstance(const Graphics::PixelFormat &format) const override;
|
||||
|
||||
bool canDrawCursor() const override { return false; }
|
||||
uint extraPixels() const override { return 2; }
|
||||
const char *getName() const override;
|
||||
const char *getPrettyName() const override;
|
||||
};
|
||||
|
||||
SuperEaglePlugin::SuperEaglePlugin() {
|
||||
_factors.push_back(2);
|
||||
}
|
||||
|
||||
Scaler *SuperEaglePlugin::createInstance(const Graphics::PixelFormat &format) const {
|
||||
return new SuperEagleScaler(format);
|
||||
}
|
||||
|
||||
const char *SuperEaglePlugin::getName() const {
|
||||
return "supereagle";
|
||||
}
|
||||
|
||||
const char *SuperEaglePlugin::getPrettyName() const {
|
||||
return "SuperEagle";
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(SUPEREAGLE, PLUGIN_TYPE_SCALER, SuperEaglePlugin);
|
||||
56
graphics/scaler/sai.h
Normal file
56
graphics/scaler/sai.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_SCALER_SAI_H
|
||||
#define GRAPHICS_SCALER_SAI_H
|
||||
|
||||
#include "graphics/scalerplugin.h"
|
||||
|
||||
class SAIScaler : public Scaler {
|
||||
public:
|
||||
SAIScaler(const Graphics::PixelFormat &format) : Scaler(format) { _factor = 2; }
|
||||
uint increaseFactor() override;
|
||||
uint decreaseFactor() override;
|
||||
protected:
|
||||
virtual void scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) override;
|
||||
};
|
||||
|
||||
class SuperSAIScaler : public Scaler {
|
||||
public:
|
||||
SuperSAIScaler(const Graphics::PixelFormat &format) : Scaler(format) { _factor = 2; }
|
||||
uint increaseFactor() override;
|
||||
uint decreaseFactor() override;
|
||||
protected:
|
||||
virtual void scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) override;
|
||||
};
|
||||
|
||||
class SuperEagleScaler : public Scaler {
|
||||
public:
|
||||
SuperEagleScaler(const Graphics::PixelFormat &format) : Scaler(format) { _factor = 2; }
|
||||
uint increaseFactor() override;
|
||||
uint decreaseFactor() override;
|
||||
protected:
|
||||
virtual void scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
503
graphics/scaler/scale2x.cpp
Normal file
503
graphics/scaler/scale2x.cpp
Normal file
@@ -0,0 +1,503 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains a C and MMX implementation of the Scale2x effect.
|
||||
*
|
||||
* You can find a high-level description of the effect at:
|
||||
*
|
||||
* https://www.scale2x.it
|
||||
*
|
||||
* Alternatively at the previous license terms, you are allowed to use this
|
||||
* code in your program with these conditions:
|
||||
* - the program is not used in commercial activities.
|
||||
* - the whole source code of the program is released with the binary.
|
||||
* - derivative works of the program are allowed.
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#include "graphics/scaler/scale2x.h"
|
||||
|
||||
/***************************************************************************/
|
||||
/* Scale2x C implementation */
|
||||
|
||||
static inline void scale2x_8_def_single(scale2x_uint8* __restrict__ dst, const scale2x_uint8* __restrict__ src0, const scale2x_uint8* __restrict__ src1, const scale2x_uint8* __restrict__ src2, unsigned count) {
|
||||
/* central pixels */
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
||||
++src0;
|
||||
++src1;
|
||||
++src2;
|
||||
dst += 2;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale2x_16_def_single(scale2x_uint16* __restrict__ dst, const scale2x_uint16* __restrict__ src0, const scale2x_uint16* __restrict__ src1, const scale2x_uint16* __restrict__ src2, unsigned count) {
|
||||
/* central pixels */
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
||||
++src0;
|
||||
++src1;
|
||||
++src2;
|
||||
dst += 2;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale2x_32_def_single(scale2x_uint32* __restrict__ dst, const scale2x_uint32* __restrict__ src0, const scale2x_uint32* __restrict__ src1, const scale2x_uint32* __restrict__ src2, unsigned count) {
|
||||
/* central pixels */
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
||||
++src0;
|
||||
++src1;
|
||||
++src2;
|
||||
dst += 2;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale by a factor of 2 a row of pixels of 8 bits.
|
||||
* The function is implemented in C.
|
||||
* The pixels over the left and right borders are assumed of the same color of
|
||||
* the pixels on the border.
|
||||
* @param src0 Pointer at the first pixel of the previous row.
|
||||
* @param src1 Pointer at the first pixel of the current row.
|
||||
* @param src2 Pointer at the first pixel of the next row.
|
||||
* @param count Length in pixels of the src0, src1 and src2 rows.
|
||||
* It must be at least 2.
|
||||
* @param dst0 First destination row, double length in pixels.
|
||||
* @param dst1 Second destination row, double length in pixels.
|
||||
*/
|
||||
void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) {
|
||||
scale2x_8_def_single(dst0, src0, src1, src2, count);
|
||||
scale2x_8_def_single(dst1, src2, src1, src0, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale by a factor of 2 a row of pixels of 16 bits.
|
||||
* This function operates like scale2x_8_def() but for 16 bits pixels.
|
||||
* @param src0 Pointer at the first pixel of the previous row.
|
||||
* @param src1 Pointer at the first pixel of the current row.
|
||||
* @param src2 Pointer at the first pixel of the next row.
|
||||
* @param count Length in pixels of the src0, src1 and src2 rows.
|
||||
* It must be at least 2.
|
||||
* @param dst0 First destination row, double length in pixels.
|
||||
* @param dst1 Second destination row, double length in pixels.
|
||||
*/
|
||||
void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) {
|
||||
scale2x_16_def_single(dst0, src0, src1, src2, count);
|
||||
scale2x_16_def_single(dst1, src2, src1, src0, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale by a factor of 2 a row of pixels of 32 bits.
|
||||
* This function operates like scale2x_8_def() but for 32 bits pixels.
|
||||
* @param src0 Pointer at the first pixel of the previous row.
|
||||
* @param src1 Pointer at the first pixel of the current row.
|
||||
* @param src2 Pointer at the first pixel of the next row.
|
||||
* @param count Length in pixels of the src0, src1 and src2 rows.
|
||||
* It must be at least 2.
|
||||
* @param dst0 First destination row, double length in pixels.
|
||||
* @param dst1 Second destination row, double length in pixels.
|
||||
*/
|
||||
void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) {
|
||||
scale2x_32_def_single(dst0, src0, src1, src2, count);
|
||||
scale2x_32_def_single(dst1, src2, src1, src0, count);
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* Scale2x MMX implementation */
|
||||
|
||||
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
|
||||
/*
|
||||
* Apply the Scale2x effect at a single row.
|
||||
* This function must be called only by the other scale2x functions.
|
||||
*
|
||||
* Considering the pixel map :
|
||||
*
|
||||
* ABC (src0)
|
||||
* DEF (src1)
|
||||
* GHI (src2)
|
||||
*
|
||||
* this functions compute 2 new pixels in substitution of the source pixel E
|
||||
* like this map :
|
||||
*
|
||||
* ab (dst)
|
||||
*
|
||||
* with these variables :
|
||||
*
|
||||
* ¤t -> E
|
||||
* ¤t_left -> D
|
||||
* ¤t_right -> F
|
||||
* ¤t_upper -> B
|
||||
* ¤t_lower -> H
|
||||
*
|
||||
* %0 -> current_upper
|
||||
* %1 -> current
|
||||
* %2 -> current_lower
|
||||
* %3 -> dst
|
||||
* %4 -> counter
|
||||
*
|
||||
* %mm0 -> *current_left
|
||||
* %mm1 -> *current_next
|
||||
* %mm2 -> tmp0
|
||||
* %mm3 -> tmp1
|
||||
* %mm4 -> tmp2
|
||||
* %mm5 -> tmp3
|
||||
* %mm6 -> *current_upper
|
||||
* %mm7 -> *current
|
||||
*/
|
||||
static inline void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) {
|
||||
assert(count >= 16);
|
||||
assert(count % 8 == 0);
|
||||
|
||||
__asm__ __volatile__(
|
||||
/* central runs */
|
||||
"shr $3, %4\n"
|
||||
"jz 1f\n"
|
||||
|
||||
"0:\n"
|
||||
|
||||
/* set the current, current_pre, current_next registers */
|
||||
"movq -8(%1), %%mm0\n"
|
||||
"movq (%1), %%mm7\n"
|
||||
"movq 8(%1), %%mm1\n"
|
||||
"psrlq $56, %%mm0\n"
|
||||
"psllq $56, %%mm1\n"
|
||||
"movq %%mm7, %%mm2\n"
|
||||
"movq %%mm7, %%mm3\n"
|
||||
"psllq $8, %%mm2\n"
|
||||
"psrlq $8, %%mm3\n"
|
||||
"por %%mm2, %%mm0\n"
|
||||
"por %%mm3, %%mm1\n"
|
||||
|
||||
/* current_upper */
|
||||
"movq (%0), %%mm6\n"
|
||||
|
||||
/* compute the upper-left pixel for dst on %%mm2 */
|
||||
/* compute the upper-right pixel for dst on %%mm4 */
|
||||
"movq %%mm0, %%mm2\n"
|
||||
"movq %%mm1, %%mm4\n"
|
||||
"movq %%mm0, %%mm3\n"
|
||||
"movq %%mm1, %%mm5\n"
|
||||
"pcmpeqb %%mm6, %%mm2\n"
|
||||
"pcmpeqb %%mm6, %%mm4\n"
|
||||
"pcmpeqb (%2), %%mm3\n"
|
||||
"pcmpeqb (%2), %%mm5\n"
|
||||
"pandn %%mm2, %%mm3\n"
|
||||
"pandn %%mm4, %%mm5\n"
|
||||
"movq %%mm0, %%mm2\n"
|
||||
"movq %%mm1, %%mm4\n"
|
||||
"pcmpeqb %%mm1, %%mm2\n"
|
||||
"pcmpeqb %%mm0, %%mm4\n"
|
||||
"pandn %%mm3, %%mm2\n"
|
||||
"pandn %%mm5, %%mm4\n"
|
||||
"movq %%mm2, %%mm3\n"
|
||||
"movq %%mm4, %%mm5\n"
|
||||
"pand %%mm6, %%mm2\n"
|
||||
"pand %%mm6, %%mm4\n"
|
||||
"pandn %%mm7, %%mm3\n"
|
||||
"pandn %%mm7, %%mm5\n"
|
||||
"por %%mm3, %%mm2\n"
|
||||
"por %%mm5, %%mm4\n"
|
||||
|
||||
/* set *dst */
|
||||
"movq %%mm2, %%mm3\n"
|
||||
"punpcklbw %%mm4, %%mm2\n"
|
||||
"punpckhbw %%mm4, %%mm3\n"
|
||||
"movq %%mm2, (%3)\n"
|
||||
"movq %%mm3, 8(%3)\n"
|
||||
|
||||
/* next */
|
||||
"add $8, %0\n"
|
||||
"add $8, %1\n"
|
||||
"add $8, %2\n"
|
||||
"add $16, %3\n"
|
||||
|
||||
"dec %4\n"
|
||||
"jnz 0b\n"
|
||||
"1:\n"
|
||||
|
||||
: "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
|
||||
:
|
||||
: "cc"
|
||||
);
|
||||
}
|
||||
|
||||
static inline void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) {
|
||||
assert(count >= 8);
|
||||
assert(count % 4 == 0);
|
||||
|
||||
__asm__ __volatile__(
|
||||
/* central runs */
|
||||
"shr $2, %4\n"
|
||||
"jz 1f\n"
|
||||
|
||||
"0:\n"
|
||||
|
||||
/* set the current, current_pre, current_next registers */
|
||||
"movq -8(%1), %%mm0\n"
|
||||
"movq (%1), %%mm7\n"
|
||||
"movq 8(%1), %%mm1\n"
|
||||
"psrlq $48, %%mm0\n"
|
||||
"psllq $48, %%mm1\n"
|
||||
"movq %%mm7, %%mm2\n"
|
||||
"movq %%mm7, %%mm3\n"
|
||||
"psllq $16, %%mm2\n"
|
||||
"psrlq $16, %%mm3\n"
|
||||
"por %%mm2, %%mm0\n"
|
||||
"por %%mm3, %%mm1\n"
|
||||
|
||||
/* current_upper */
|
||||
"movq (%0), %%mm6\n"
|
||||
|
||||
/* compute the upper-left pixel for dst on %%mm2 */
|
||||
/* compute the upper-right pixel for dst on %%mm4 */
|
||||
"movq %%mm0, %%mm2\n"
|
||||
"movq %%mm1, %%mm4\n"
|
||||
"movq %%mm0, %%mm3\n"
|
||||
"movq %%mm1, %%mm5\n"
|
||||
"pcmpeqw %%mm6, %%mm2\n"
|
||||
"pcmpeqw %%mm6, %%mm4\n"
|
||||
"pcmpeqw (%2), %%mm3\n"
|
||||
"pcmpeqw (%2), %%mm5\n"
|
||||
"pandn %%mm2, %%mm3\n"
|
||||
"pandn %%mm4, %%mm5\n"
|
||||
"movq %%mm0, %%mm2\n"
|
||||
"movq %%mm1, %%mm4\n"
|
||||
"pcmpeqw %%mm1, %%mm2\n"
|
||||
"pcmpeqw %%mm0, %%mm4\n"
|
||||
"pandn %%mm3, %%mm2\n"
|
||||
"pandn %%mm5, %%mm4\n"
|
||||
"movq %%mm2, %%mm3\n"
|
||||
"movq %%mm4, %%mm5\n"
|
||||
"pand %%mm6, %%mm2\n"
|
||||
"pand %%mm6, %%mm4\n"
|
||||
"pandn %%mm7, %%mm3\n"
|
||||
"pandn %%mm7, %%mm5\n"
|
||||
"por %%mm3, %%mm2\n"
|
||||
"por %%mm5, %%mm4\n"
|
||||
|
||||
/* set *dst */
|
||||
"movq %%mm2, %%mm3\n"
|
||||
"punpcklwd %%mm4, %%mm2\n"
|
||||
"punpckhwd %%mm4, %%mm3\n"
|
||||
"movq %%mm2, (%3)\n"
|
||||
"movq %%mm3, 8(%3)\n"
|
||||
|
||||
/* next */
|
||||
"add $8, %0\n"
|
||||
"add $8, %1\n"
|
||||
"add $8, %2\n"
|
||||
"add $16, %3\n"
|
||||
|
||||
"dec %4\n"
|
||||
"jnz 0b\n"
|
||||
"1:\n"
|
||||
|
||||
: "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
|
||||
:
|
||||
: "cc"
|
||||
);
|
||||
}
|
||||
|
||||
static inline void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) {
|
||||
assert(count >= 4);
|
||||
assert(count % 2 == 0);
|
||||
|
||||
__asm__ __volatile__(
|
||||
/* central runs */
|
||||
"shr $1, %4\n"
|
||||
"jz 1f\n"
|
||||
|
||||
"0:\n"
|
||||
|
||||
/* set the current, current_pre, current_next registers */
|
||||
"movq -8(%1), %%mm0\n"
|
||||
"movq (%1), %%mm7\n"
|
||||
"movq 8(%1), %%mm1\n"
|
||||
"psrlq $32, %%mm0\n"
|
||||
"psllq $32, %%mm1\n"
|
||||
"movq %%mm7, %%mm2\n"
|
||||
"movq %%mm7, %%mm3\n"
|
||||
"psllq $32, %%mm2\n"
|
||||
"psrlq $32, %%mm3\n"
|
||||
"por %%mm2, %%mm0\n"
|
||||
"por %%mm3, %%mm1\n"
|
||||
|
||||
/* current_upper */
|
||||
"movq (%0), %%mm6\n"
|
||||
|
||||
/* compute the upper-left pixel for dst on %%mm2 */
|
||||
/* compute the upper-right pixel for dst on %%mm4 */
|
||||
"movq %%mm0, %%mm2\n"
|
||||
"movq %%mm1, %%mm4\n"
|
||||
"movq %%mm0, %%mm3\n"
|
||||
"movq %%mm1, %%mm5\n"
|
||||
"pcmpeqd %%mm6, %%mm2\n"
|
||||
"pcmpeqd %%mm6, %%mm4\n"
|
||||
"pcmpeqd (%2), %%mm3\n"
|
||||
"pcmpeqd (%2), %%mm5\n"
|
||||
"pandn %%mm2, %%mm3\n"
|
||||
"pandn %%mm4, %%mm5\n"
|
||||
"movq %%mm0, %%mm2\n"
|
||||
"movq %%mm1, %%mm4\n"
|
||||
"pcmpeqd %%mm1, %%mm2\n"
|
||||
"pcmpeqd %%mm0, %%mm4\n"
|
||||
"pandn %%mm3, %%mm2\n"
|
||||
"pandn %%mm5, %%mm4\n"
|
||||
"movq %%mm2, %%mm3\n"
|
||||
"movq %%mm4, %%mm5\n"
|
||||
"pand %%mm6, %%mm2\n"
|
||||
"pand %%mm6, %%mm4\n"
|
||||
"pandn %%mm7, %%mm3\n"
|
||||
"pandn %%mm7, %%mm5\n"
|
||||
"por %%mm3, %%mm2\n"
|
||||
"por %%mm5, %%mm4\n"
|
||||
|
||||
/* set *dst */
|
||||
"movq %%mm2, %%mm3\n"
|
||||
"punpckldq %%mm4, %%mm2\n"
|
||||
"punpckhdq %%mm4, %%mm3\n"
|
||||
"movq %%mm2, (%3)\n"
|
||||
"movq %%mm3, 8(%3)\n"
|
||||
|
||||
/* next */
|
||||
"add $8, %0\n"
|
||||
"add $8, %1\n"
|
||||
"add $8, %2\n"
|
||||
"add $16, %3\n"
|
||||
|
||||
"dec %4\n"
|
||||
"jnz 0b\n"
|
||||
"1:\n"
|
||||
|
||||
: "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
|
||||
:
|
||||
: "cc"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale by a factor of 2 a row of pixels of 8 bits.
|
||||
* This is a very fast MMX implementation.
|
||||
* The implementation uses a combination of cmp/and/not operations to
|
||||
* completly remove the need of conditional jumps. This trick give the
|
||||
* major speed improvement.
|
||||
* Also, using the 8 bytes MMX registers more than one pixel are computed
|
||||
* at the same time.
|
||||
* Before calling this function you must ensure that the currenct CPU supports
|
||||
* the MMX instruction set. After calling it you must be sure to call the EMMS
|
||||
* instruction before any floating-point operation.
|
||||
* The pixels over the left and right borders are assumed of the same color of
|
||||
* the pixels on the border.
|
||||
* @param src0 Pointer at the first pixel of the previous row.
|
||||
* @param src1 Pointer at the first pixel of the current row.
|
||||
* @param src2 Pointer at the first pixel of the next row.
|
||||
* @param count Length in pixels of the src0, src1 and src2 rows. It must
|
||||
* be at least 16 and a multiple of 8.
|
||||
* @param dst0 First destination row, double length in pixels.
|
||||
* @param dst1 Second destination row, double length in pixels.
|
||||
*/
|
||||
void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) {
|
||||
if (count % 8 != 0 || count < 16) {
|
||||
scale2x_8_def(dst0, dst1, src0, src1, src2, count);
|
||||
} else {
|
||||
assert(count >= 16);
|
||||
assert(count % 8 == 0);
|
||||
|
||||
scale2x_8_mmx_single(dst0, src0, src1, src2, count);
|
||||
scale2x_8_mmx_single(dst1, src2, src1, src0, count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale by a factor of 2 a row of pixels of 16 bits.
|
||||
* This function operates like scale2x_8_mmx() but for 16 bits pixels.
|
||||
* @param src0 Pointer at the first pixel of the previous row.
|
||||
* @param src1 Pointer at the first pixel of the current row.
|
||||
* @param src2 Pointer at the first pixel of the next row.
|
||||
* @param count Length in pixels of the src0, src1 and src2 rows. It must
|
||||
* be at least 8 and a multiple of 4.
|
||||
* @param dst0 First destination row, double length in pixels.
|
||||
* @param dst1 Second destination row, double length in pixels.
|
||||
*/
|
||||
void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) {
|
||||
if (count % 4 != 0 || count < 8) {
|
||||
scale2x_16_def(dst0, dst1, src0, src1, src2, count);
|
||||
} else {
|
||||
assert(count >= 8);
|
||||
assert(count % 4 == 0);
|
||||
|
||||
scale2x_16_mmx_single(dst0, src0, src1, src2, count);
|
||||
scale2x_16_mmx_single(dst1, src2, src1, src0, count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale by a factor of 2 a row of pixels of 32 bits.
|
||||
* This function operates like scale2x_8_mmx() but for 32 bits pixels.
|
||||
* @param src0 Pointer at the first pixel of the previous row.
|
||||
* @param src1 Pointer at the first pixel of the current row.
|
||||
* @param src2 Pointer at the first pixel of the next row.
|
||||
* @param count Length in pixels of the src0, src1 and src2 rows. It must
|
||||
* be at least 4 and a multiple of 2.
|
||||
* @param dst0 First destination row, double length in pixels.
|
||||
* @param dst1 Second destination row, double length in pixels.
|
||||
*/
|
||||
void scale2x_32_mmx(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) {
|
||||
if (count % 2 != 0 || count < 4) {
|
||||
scale2x_32_def(dst0, dst1, src0, src1, src2, count);
|
||||
} else {
|
||||
assert(count >= 4);
|
||||
assert(count % 2 == 0);
|
||||
|
||||
scale2x_32_mmx_single(dst0, src0, src1, src2, count);
|
||||
scale2x_32_mmx_single(dst1, src2, src1, src0, count);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
64
graphics/scaler/scale2x.h
Normal file
64
graphics/scaler/scale2x.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCALER_SCALE2X_H
|
||||
#define SCALER_SCALE2X_H
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define __restrict__
|
||||
#endif
|
||||
|
||||
typedef unsigned char scale2x_uint8;
|
||||
typedef unsigned short scale2x_uint16;
|
||||
typedef unsigned scale2x_uint32;
|
||||
|
||||
void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
|
||||
void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
|
||||
void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
|
||||
|
||||
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
|
||||
void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
|
||||
void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
|
||||
void scale2x_32_mmx(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
|
||||
|
||||
/**
|
||||
* End the use of the MMX instructions.
|
||||
* This function must be called before using any floating-point operations.
|
||||
*/
|
||||
static inline void scale2x_mmx_emms(void)
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
"emms"
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(USE_ARM_SCALER_ASM)
|
||||
|
||||
extern "C" void scale2x_8_arm(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
|
||||
extern "C" void scale2x_16_arm(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
|
||||
extern "C" void scale2x_32_arm(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
184
graphics/scaler/scale2xARM.s
Normal file
184
graphics/scaler/scale2xARM.s
Normal file
@@ -0,0 +1,184 @@
|
||||
@ ScummVM - Graphic Adventure Engine
|
||||
@
|
||||
@ ScummVM is the legal property of its developers, whose names
|
||||
@ are too numerous to list here. Please refer to the COPYRIGHT
|
||||
@ file distributed with this source distribution.
|
||||
@
|
||||
@ This program is free software: you can redistribute it and/or modify
|
||||
@ it under the terms of the GNU General Public License as published by
|
||||
@ the Free Software Foundation, either version 3 of the License, or
|
||||
@ (at your option) any later version.
|
||||
@
|
||||
@ This program is distributed in the hope that it will be useful,
|
||||
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
@ GNU General Public License for more details.
|
||||
@
|
||||
@ You should have received a copy of the GNU General Public License
|
||||
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@
|
||||
@ @author Robin Watts (robin@wss.co.uk)
|
||||
|
||||
.text
|
||||
|
||||
.global scale2x_8_arm
|
||||
.global scale2x_16_arm
|
||||
.global scale2x_32_arm
|
||||
|
||||
@ r0 = dst0
|
||||
@ r1 = dst1
|
||||
@ r2 = src
|
||||
@ r3 = src_prev
|
||||
@ r4 = src_next
|
||||
@ r5 = len
|
||||
|
||||
|
||||
@ We hold: r10 B
|
||||
@ r8 r14 r7 D E F
|
||||
@ r12 H
|
||||
.align 2
|
||||
scale2x_8_arm:
|
||||
STMFD r13!,{r4-r5,r7-r8,r10-r11,r14}
|
||||
LDR r4, [r13,#4*7]
|
||||
LDR r5, [r13,#4*8]
|
||||
|
||||
LDRB r14,[r2], #1
|
||||
CMP r3, #0 @ Set NE
|
||||
@ Stall on Xscale
|
||||
MOV r8, r14
|
||||
B loop8
|
||||
same8:
|
||||
STRB r14,[r0], #1
|
||||
STRB r14,[r0], #1
|
||||
STRB r14,[r1], #1
|
||||
STRB r14,[r1], #1
|
||||
SUBS r5, r5, #1
|
||||
MOV r8, r14
|
||||
MOV r14,r7
|
||||
BLT end8
|
||||
loop8:
|
||||
LDRNEB r7, [r3], #1 @ As long as we aren't on the last pixel
|
||||
LDRB r10,[r2], #1
|
||||
LDRB r12,[r4], #1
|
||||
@ Stall on Xscale
|
||||
CMP r7, r8
|
||||
CMPNE r10,r12
|
||||
BEQ same8
|
||||
CMP r8, r10
|
||||
STREQB r8, [r0], #1
|
||||
STRNEB r14,[r0], #1
|
||||
CMP r10,r7
|
||||
STREQB r7, [r0], #1
|
||||
STRNEB r14,[r0], #1
|
||||
CMP r8, r12
|
||||
STREQB r8, [r1], #1
|
||||
STRNEB r14,[r1], #1
|
||||
CMP r12,r7
|
||||
STREQB r7, [r1], #1
|
||||
STRNEB r14,[r1], #1
|
||||
|
||||
SUBS r5, r5, #1
|
||||
MOV r8, r14
|
||||
MOV r14,r7
|
||||
BGE loop8
|
||||
end8:
|
||||
|
||||
LDMFD r13!,{r4-r5,r7-r8,r10-r11,PC}
|
||||
|
||||
.align 2
|
||||
scale2x_16_arm:
|
||||
STMFD r13!,{r4-r5,r7-r8,r10-r11,r14}
|
||||
LDR r4, [r13,#4*7]
|
||||
LDR r5, [r13,#4*8]
|
||||
|
||||
LDRH r14,[r3], #2
|
||||
CMP r3, #0 @ Set NE
|
||||
@ Stall on Xscale
|
||||
MOV r8, r14
|
||||
B loop16
|
||||
same16:
|
||||
STRH r14,[r0], #2
|
||||
STRH r14,[r0], #2
|
||||
STRH r14,[r1], #2
|
||||
STRH r14,[r1], #2
|
||||
SUBS r5, r5, #1
|
||||
MOV r8, r14
|
||||
MOV r14,r7
|
||||
BLT end16
|
||||
loop16:
|
||||
LDRNEH r7, [r3], #2 @ As long as we aren't on the last pixel
|
||||
LDRH r10,[r2], #2
|
||||
LDRH r12,[r4], #2
|
||||
@ Stall on Xscale
|
||||
CMP r7, r8
|
||||
CMPNE r10,r12
|
||||
BEQ same16
|
||||
CMP r8, r10
|
||||
STREQH r8, [r0], #2
|
||||
STRNEH r14,[r0], #2
|
||||
CMP r10,r7
|
||||
STREQH r7, [r0], #2
|
||||
STRNEH r14,[r0], #2
|
||||
CMP r8, r12
|
||||
STREQH r8, [r1], #2
|
||||
STRNEH r14,[r1], #2
|
||||
CMP r12,r7
|
||||
STREQH r7, [r1], #2
|
||||
STRNEH r14,[r1], #2
|
||||
|
||||
SUBS r5, r5, #1
|
||||
MOV r8, r14
|
||||
MOV r14,r7
|
||||
BGE loop16
|
||||
end16:
|
||||
|
||||
LDMFD r13!,{r4-r5,r7-r8,r10-r11,PC}
|
||||
|
||||
.align 2
|
||||
scale2x_32_arm:
|
||||
STMFD r13!,{r4-r5,r7-r8,r10-r11,r14}
|
||||
LDR r4, [r13,#4*7]
|
||||
LDR r5, [r13,#4*8]
|
||||
|
||||
LDR r14,[r3], #4
|
||||
CMP r3, #0 @ Set NE
|
||||
@ Stall on Xscale
|
||||
MOV r8, r14
|
||||
B loop32
|
||||
same32:
|
||||
STR r14,[r0], #4
|
||||
STR r14,[r0], #4
|
||||
STR r14,[r1], #4
|
||||
STR r14,[r1], #4
|
||||
SUBS r5, r5, #1
|
||||
MOV r8, r14
|
||||
MOV r14,r7
|
||||
BLT end32
|
||||
loop32:
|
||||
LDRNE r7, [r3], #4 @ As long as we aren't on the last pixel
|
||||
LDR r10,[r2], #4
|
||||
LDR r12,[r4], #4
|
||||
@ Stall on Xscale
|
||||
CMP r7, r8
|
||||
CMPNE r10,r12
|
||||
BEQ same32
|
||||
CMP r8, r10
|
||||
STREQ r8, [r0], #4
|
||||
STRNE r14,[r0], #4
|
||||
CMP r10,r7
|
||||
STREQ r7, [r0], #4
|
||||
STRNE r14,[r0], #4
|
||||
CMP r8, r12
|
||||
STREQ r8, [r1], #4
|
||||
STRNE r14,[r1], #4
|
||||
CMP r12,r7
|
||||
STREQ r7, [r1], #4
|
||||
STRNE r14,[r1], #4
|
||||
|
||||
SUBS r5, r5, #1
|
||||
MOV r8, r14
|
||||
MOV r14,r7
|
||||
BGE loop32
|
||||
end32:
|
||||
|
||||
LDMFD r13!,{r4-r5,r7-r8,r10-r11,PC}
|
||||
223
graphics/scaler/scale3x.cpp
Normal file
223
graphics/scaler/scale3x.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains a C and MMX implementation of the Scale2x effect.
|
||||
*
|
||||
* You can find a high-level description of the effect at:
|
||||
*
|
||||
* https://www.scale2x.it
|
||||
*
|
||||
* Alternatively at the previous license terms, you are allowed to use this
|
||||
* code in your program with these conditions:
|
||||
* - the program is not used in commercial activities.
|
||||
* - the whole source code of the program is released with the binary.
|
||||
* - derivative works of the program are allowed.
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#include "graphics/scaler/scale3x.h"
|
||||
|
||||
/***************************************************************************/
|
||||
/* Scale3x C implementation */
|
||||
|
||||
static inline void scale3x_8_def_border(scale3x_uint8* __restrict__ dst, const scale3x_uint8* __restrict__ src0, const scale3x_uint8* __restrict__ src1, const scale3x_uint8* __restrict__ src2, unsigned count) {
|
||||
/* central pixels */
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
|
||||
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
}
|
||||
|
||||
++src0;
|
||||
++src1;
|
||||
++src2;
|
||||
dst += 3;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale3x_8_def_center(scale3x_uint8* __restrict__ dst, const scale3x_uint8* __restrict__ src0, const scale3x_uint8* __restrict__ src1, const scale3x_uint8* __restrict__ src2, unsigned count) {
|
||||
/* central pixels */
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
}
|
||||
|
||||
++src0;
|
||||
++src1;
|
||||
++src2;
|
||||
dst += 3;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale3x_16_def_border(scale3x_uint16* __restrict__ dst, const scale3x_uint16* __restrict__ src0, const scale3x_uint16* __restrict__ src1, const scale3x_uint16* __restrict__ src2, unsigned count) {
|
||||
/* central pixels */
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
|
||||
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
}
|
||||
|
||||
++src0;
|
||||
++src1;
|
||||
++src2;
|
||||
dst += 3;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale3x_16_def_center(scale3x_uint16* __restrict__ dst, const scale3x_uint16* __restrict__ src0, const scale3x_uint16* __restrict__ src1, const scale3x_uint16* __restrict__ src2, unsigned count) {
|
||||
/* central pixels */
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
}
|
||||
|
||||
++src0;
|
||||
++src1;
|
||||
++src2;
|
||||
dst += 3;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale3x_32_def_border(scale3x_uint32* __restrict__ dst, const scale3x_uint32* __restrict__ src0, const scale3x_uint32* __restrict__ src1, const scale3x_uint32* __restrict__ src2, unsigned count) {
|
||||
/* central pixels */
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
|
||||
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
}
|
||||
|
||||
++src0;
|
||||
++src1;
|
||||
++src2;
|
||||
dst += 3;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale3x_32_def_center(scale3x_uint32* __restrict__ dst, const scale3x_uint32* __restrict__ src0, const scale3x_uint32* __restrict__ src1, const scale3x_uint32* __restrict__ src2, unsigned count) {
|
||||
/* central pixels */
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
}
|
||||
|
||||
++src0;
|
||||
++src1;
|
||||
++src2;
|
||||
dst += 3;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale by a factor of 3 a row of pixels of 8 bits.
|
||||
* The function is implemented in C.
|
||||
* The pixels over the left and right borders are assumed of the same color of
|
||||
* the pixels on the border.
|
||||
* @param src0 Pointer at the first pixel of the previous row.
|
||||
* @param src1 Pointer at the first pixel of the current row.
|
||||
* @param src2 Pointer at the first pixel of the next row.
|
||||
* @param count Length in pixels of the src0, src1 and src2 rows.
|
||||
* It must be at least 2.
|
||||
* @param dst0 First destination row, triple length in pixels.
|
||||
* @param dst1 Second destination row, triple length in pixels.
|
||||
* @param dst2 Third destination row, triple length in pixels.
|
||||
*/
|
||||
void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count) {
|
||||
scale3x_8_def_border(dst0, src0, src1, src2, count);
|
||||
scale3x_8_def_center(dst1, src0, src1, src2, count);
|
||||
scale3x_8_def_border(dst2, src2, src1, src0, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale by a factor of 3 a row of pixels of 16 bits.
|
||||
* This function operates like scale3x_8_def() but for 16 bits pixels.
|
||||
* @param src0 Pointer at the first pixel of the previous row.
|
||||
* @param src1 Pointer at the first pixel of the current row.
|
||||
* @param src2 Pointer at the first pixel of the next row.
|
||||
* @param count Length in pixels of the src0, src1 and src2 rows.
|
||||
* It must be at least 2.
|
||||
* @param dst0 First destination row, triple length in pixels.
|
||||
* @param dst1 Second destination row, triple length in pixels.
|
||||
* @param dst2 Third destination row, triple length in pixels.
|
||||
*/
|
||||
void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count) {
|
||||
scale3x_16_def_border(dst0, src0, src1, src2, count);
|
||||
scale3x_16_def_center(dst1, src0, src1, src2, count);
|
||||
scale3x_16_def_border(dst2, src2, src1, src0, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale by a factor of 3 a row of pixels of 32 bits.
|
||||
* This function operates like scale3x_8_def() but for 32 bits pixels.
|
||||
* @param src0 Pointer at the first pixel of the previous row.
|
||||
* @param src1 Pointer at the first pixel of the current row.
|
||||
* @param src2 Pointer at the first pixel of the next row.
|
||||
* @param count Length in pixels of the src0, src1 and src2 rows.
|
||||
* It must be at least 2.
|
||||
* @param dst0 First destination row, triple length in pixels.
|
||||
* @param dst1 Second destination row, triple length in pixels.
|
||||
* @param dst2 Third destination row, triple length in pixels.
|
||||
*/
|
||||
void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count) {
|
||||
scale3x_32_def_border(dst0, src0, src1, src2, count);
|
||||
scale3x_32_def_center(dst1, src0, src1, src2, count);
|
||||
scale3x_32_def_border(dst2, src2, src1, src0, count);
|
||||
}
|
||||
37
graphics/scaler/scale3x.h
Normal file
37
graphics/scaler/scale3x.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCALER_SCALE3X_H
|
||||
#define SCALER_SCALE3X_H
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define __restrict__
|
||||
#endif
|
||||
|
||||
typedef unsigned char scale3x_uint8;
|
||||
typedef unsigned short scale3x_uint16;
|
||||
typedef unsigned scale3x_uint32;
|
||||
|
||||
void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count);
|
||||
void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count);
|
||||
void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count);
|
||||
|
||||
#endif
|
||||
407
graphics/scaler/scalebit.cpp
Normal file
407
graphics/scaler/scalebit.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains an example implementation of the Scale effect
|
||||
* applied to a generic bitmap.
|
||||
*
|
||||
* You can find a high-level description of the effect at:
|
||||
*
|
||||
* https://www.scale2x.it
|
||||
*
|
||||
* Alternatively at the previous license terms, you are allowed to use this
|
||||
* code in your program with these conditions:
|
||||
* - the program is not used in commercial activities.
|
||||
* - the whole source code of the program is released with the binary.
|
||||
* - derivative works of the program are allowed.
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#include "graphics/scaler/scale2x.h"
|
||||
#include "graphics/scaler/scale3x.h"
|
||||
#include "graphics/scaler/scalebit.h"
|
||||
|
||||
#define DST(bits, num) (scale2x_uint ## bits *)dst ## num
|
||||
#define SRC(bits, num) (const scale2x_uint ## bits *)src ## num
|
||||
|
||||
/**
|
||||
* Apply the Scale2x effect on a group of rows. Used internally.
|
||||
*/
|
||||
static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) {
|
||||
switch (pixel) {
|
||||
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
case 1: scale2x_8_mmx( DST( 8,0), DST( 8,1), SRC( 8,0), SRC( 8,1), SRC( 8,2), pixel_per_row); break;
|
||||
case 2: scale2x_16_mmx(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
|
||||
case 4: scale2x_32_mmx(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
|
||||
#elif defined(USE_ARM_SCALER_ASM)
|
||||
case 1: scale2x_8_arm( DST( 8,0), DST( 8,1), SRC( 8,0), SRC( 8,1), SRC( 8,2), pixel_per_row); break;
|
||||
case 2: scale2x_16_arm(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
|
||||
case 4: scale2x_32_arm(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
|
||||
#else
|
||||
case 1: scale2x_8_def( DST( 8,0), DST( 8,1), SRC( 8,0), SRC( 8,1), SRC( 8,2), pixel_per_row); break;
|
||||
case 2: scale2x_16_def(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
|
||||
case 4: scale2x_32_def(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the Scale3x effect on a group of rows. Used internally.
|
||||
*/
|
||||
static inline void stage_scale3x(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) {
|
||||
switch (pixel) {
|
||||
case 1: scale3x_8_def( DST( 8,0), DST( 8,1), DST( 8,2), SRC( 8,0), SRC( 8,1), SRC( 8,2), pixel_per_row); break;
|
||||
case 2: scale3x_16_def(DST(16,0), DST(16,1), DST(16,2), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
|
||||
case 4: scale3x_32_def(DST(32,0), DST(32,1), DST(32,2), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the Scale4x effect on a group of rows. Used internally.
|
||||
*/
|
||||
static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, const void* src3, unsigned pixel, unsigned pixel_per_row) {
|
||||
stage_scale2x(dst0, dst1, src0, src1, src2, pixel, 2 * pixel_per_row);
|
||||
stage_scale2x(dst2, dst3, src1, src2, src3, pixel, 2 * pixel_per_row);
|
||||
}
|
||||
|
||||
#define SCDST(i) (dst+(i)*dst_slice)
|
||||
#define SCSRC(i) (src+(i)*src_slice)
|
||||
#define SCMID(i) (mid[(i)])
|
||||
|
||||
/**
|
||||
* Apply the Scale2x effect on a bitmap.
|
||||
* The destination bitmap is filled with the scaled version of the source bitmap.
|
||||
* The source bitmap isn't modified.
|
||||
* The destination bitmap must be manually allocated before calling the function,
|
||||
* note that the resulting size is exactly 2x2 times the size of the source bitmap.
|
||||
* @param void_dst Pointer at the first pixel of the destination bitmap.
|
||||
* @param dst_slice Size in bytes of a destination bitmap row.
|
||||
* @param void_src Pointer at the first pixel of the source bitmap.
|
||||
* @param src_slice Size in bytes of a source bitmap row.
|
||||
* @param pixel Bytes per pixel of the source and destination bitmap.
|
||||
* @param width Horizontal size in pixels of the source bitmap.
|
||||
* @param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
|
||||
unsigned char* dst = (unsigned char*)void_dst;
|
||||
const unsigned char* src = (const unsigned char*)void_src;
|
||||
unsigned count;
|
||||
|
||||
assert(height >= 2);
|
||||
|
||||
count = height;
|
||||
|
||||
while (count) {
|
||||
stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
|
||||
|
||||
dst = SCDST(2);
|
||||
src = SCSRC(1);
|
||||
|
||||
--count;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
scale2x_mmx_emms();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the Scale3x effect on a bitmap.
|
||||
* The destination bitmap is filled with the scaled version of the source bitmap.
|
||||
* The source bitmap isn't modified.
|
||||
* The destination bitmap must be manually allocated before calling the function,
|
||||
* note that the resulting size is exactly 3x3 times the size of the source bitmap.
|
||||
* @param void_dst Pointer at the first pixel of the destination bitmap.
|
||||
* @param dst_slice Size in bytes of a destination bitmap row.
|
||||
* @param void_src Pointer at the first pixel of the source bitmap.
|
||||
* @param src_slice Size in bytes of a source bitmap row.
|
||||
* @param pixel Bytes per pixel of the source and destination bitmap.
|
||||
* @param width Horizontal size in pixels of the source bitmap.
|
||||
* @param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
|
||||
unsigned char* dst = (unsigned char*)void_dst;
|
||||
const unsigned char* src = (const unsigned char*)void_src;
|
||||
unsigned count;
|
||||
|
||||
assert(height >= 2);
|
||||
|
||||
count = height;
|
||||
|
||||
while (count) {
|
||||
stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
|
||||
|
||||
dst = SCDST(3);
|
||||
src = SCSRC(1);
|
||||
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the Scale4x effect on a bitmap.
|
||||
* The destination bitmap is filled with the scaled version of the source bitmap.
|
||||
* The source bitmap isn't modified.
|
||||
* The destination bitmap must be manually allocated before calling the function,
|
||||
* note that the resulting size is exactly 4x4 times the size of the source bitmap.
|
||||
* \note This function requires also a small buffer bitmap used internally to store
|
||||
* intermediate results. This bitmap must have at least a horizontal size in bytes of 2*width*pixel,
|
||||
* and a vertical size of 6 rows. The memory of this buffer must not be allocated
|
||||
* in video memory because it's also read and not only written. Generally
|
||||
* a heap (malloc) or a stack (alloca) buffer is the best choices.
|
||||
* @param void_dst Pointer at the first pixel of the destination bitmap.
|
||||
* @param dst_slice Size in bytes of a destination bitmap row.
|
||||
* @param void_mid Pointer at the first pixel of the buffer bitmap.
|
||||
* @param mid_slice Size in bytes of a buffer bitmap row.
|
||||
* @param void_src Pointer at the first pixel of the source bitmap.
|
||||
* @param src_slice Size in bytes of a source bitmap row.
|
||||
* @param pixel Bytes per pixel of the source and destination bitmap.
|
||||
* @param width Horizontal size in pixels of the source bitmap.
|
||||
* @param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsigned mid_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
|
||||
unsigned char* dst = (unsigned char*)void_dst;
|
||||
const unsigned char* src = (const unsigned char*)void_src;
|
||||
unsigned count;
|
||||
unsigned char* mid[6];
|
||||
|
||||
assert(height >= 4);
|
||||
|
||||
count = height;
|
||||
|
||||
/* set the 6 buffer pointers */
|
||||
mid[0] = (unsigned char*)void_mid;
|
||||
mid[1] = mid[0] + mid_slice;
|
||||
mid[2] = mid[1] + mid_slice;
|
||||
mid[3] = mid[2] + mid_slice;
|
||||
mid[4] = mid[3] + mid_slice;
|
||||
mid[5] = mid[4] + mid_slice;
|
||||
|
||||
stage_scale2x(SCMID(0), SCMID(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
|
||||
stage_scale2x(SCMID(2), SCMID(3), SCSRC(1), SCSRC(2), SCSRC(3), pixel, width);
|
||||
while (count) {
|
||||
unsigned char* tmp;
|
||||
|
||||
stage_scale2x(SCMID(4), SCMID(5), SCSRC(2), SCSRC(3), SCSRC(4), pixel, width);
|
||||
stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(1), SCMID(2), SCMID(3), SCMID(4), pixel, width);
|
||||
|
||||
dst = SCDST(4);
|
||||
src = SCSRC(1);
|
||||
|
||||
tmp = SCMID(0); /* shift by 2 position */
|
||||
SCMID(0) = SCMID(2);
|
||||
SCMID(2) = SCMID(4);
|
||||
SCMID(4) = tmp;
|
||||
tmp = SCMID(1);
|
||||
SCMID(1) = SCMID(3);
|
||||
SCMID(3) = SCMID(5);
|
||||
SCMID(5) = tmp;
|
||||
|
||||
--count;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
scale2x_mmx_emms();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the Scale4x effect on a bitmap.
|
||||
* The destination bitmap is filled with the scaled version of the source bitmap.
|
||||
* The source bitmap isn't modified.
|
||||
* The destination bitmap must be manually allocated before calling the function,
|
||||
* note that the resulting size is exactly 4x4 times the size of the source bitmap.
|
||||
* \note This function operates like ::scale4x_buf() but the intermediate buffer is
|
||||
* automatically allocated in the stack.
|
||||
* @param void_dst Pointer at the first pixel of the destination bitmap.
|
||||
* @param dst_slice Size in bytes of a destination bitmap row.
|
||||
* @param void_src Pointer at the first pixel of the source bitmap.
|
||||
* @param src_slice Size in bytes of a source bitmap row.
|
||||
* @param pixel Bytes per pixel of the source and destination bitmap.
|
||||
* @param width Horizontal size in pixels of the source bitmap.
|
||||
* @param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
|
||||
unsigned mid_slice;
|
||||
void* mid;
|
||||
|
||||
mid_slice = 2 * pixel * width; /* required space for 1 row buffer */
|
||||
|
||||
mid_slice = (mid_slice + 0x7) & ~0x7; /* align to 8 bytes */
|
||||
|
||||
#if defined(HAVE_ALLOCA)
|
||||
mid = alloca(6 * mid_slice); /* allocate space for 6 row buffers */
|
||||
|
||||
assert(mid != 0); /* alloca should never fails */
|
||||
#else
|
||||
mid = malloc(6 * mid_slice); /* allocate space for 6 row buffers */
|
||||
|
||||
if (!mid)
|
||||
return;
|
||||
#endif
|
||||
|
||||
scale4x_buf(void_dst, dst_slice, mid, mid_slice, void_src, src_slice, pixel, width, height);
|
||||
|
||||
#if !defined(HAVE_ALLOCA)
|
||||
free(mid);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the scale implementation is applicable at the given arguments.
|
||||
* @param scale Scale factor. 2, 3 or 4.
|
||||
* @param pixel Bytes per pixel of the source and destination bitmap.
|
||||
* @param width Horizontal size in pixels of the source bitmap.
|
||||
* @param height Vertical size in pixels of the source bitmap.
|
||||
* \return
|
||||
* - -1 on precondition violated.
|
||||
* - 0 on success.
|
||||
*/
|
||||
int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned height)
|
||||
{
|
||||
if (scale != 2 && scale != 3 && scale != 4)
|
||||
return -1;
|
||||
|
||||
if (pixel != 1 && pixel != 2 && pixel != 4)
|
||||
return -1;
|
||||
|
||||
switch (scale) {
|
||||
case 2:
|
||||
case 3:
|
||||
if (height < 2)
|
||||
return -1;
|
||||
break;
|
||||
case 4:
|
||||
if (height < 4)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
switch (scale) {
|
||||
case 2:
|
||||
case 4:
|
||||
if (width < (16 / pixel))
|
||||
return -1;
|
||||
if (width % (8 / pixel) != 0)
|
||||
return -1;
|
||||
break;
|
||||
case 3:
|
||||
if (width < 2)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if (width < 2)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the Scale effect on a bitmap.
|
||||
* This function is simply a common interface for ::scale2x(), ::scale3x() and ::scale4x().
|
||||
* @param scale Scale factor. 2, 3 or 4.
|
||||
* @param void_dst Pointer at the first pixel of the destination bitmap.
|
||||
* @param dst_slice Size in bytes of a destination bitmap row.
|
||||
* @param void_src Pointer at the first pixel of the source bitmap.
|
||||
* @param src_slice Size in bytes of a source bitmap row.
|
||||
* @param pixel Bytes per pixel of the source and destination bitmap.
|
||||
* @param width Horizontal size in pixels of the source bitmap.
|
||||
* @param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
|
||||
{
|
||||
switch (scale) {
|
||||
case 2:
|
||||
scale2x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
|
||||
break;
|
||||
case 3:
|
||||
scale3x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
|
||||
break;
|
||||
case 4:
|
||||
scale4x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AdvMameScaler::scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
|
||||
if (_factor != 4)
|
||||
::scale(_factor, dstPtr, dstPitch, srcPtr - srcPitch, srcPitch, _format.bytesPerPixel, width, height);
|
||||
else
|
||||
::scale(_factor, dstPtr, dstPitch, srcPtr - srcPitch * 2, srcPitch, _format.bytesPerPixel, width, height);
|
||||
}
|
||||
|
||||
uint AdvMameScaler::increaseFactor() {
|
||||
if (_factor < 4)
|
||||
setFactor(_factor + 1);
|
||||
return _factor;
|
||||
}
|
||||
|
||||
uint AdvMameScaler::decreaseFactor() {
|
||||
if (_factor > 2)
|
||||
setFactor(_factor - 1);
|
||||
return _factor;
|
||||
}
|
||||
|
||||
|
||||
class AdvMamePlugin final : public ScalerPluginObject {
|
||||
public:
|
||||
AdvMamePlugin();
|
||||
|
||||
Scaler *createInstance(const Graphics::PixelFormat &format) const override;
|
||||
|
||||
bool canDrawCursor() const override { return true; }
|
||||
uint extraPixels() const override { return 4; }
|
||||
const char *getName() const override;
|
||||
const char *getPrettyName() const override;
|
||||
};
|
||||
|
||||
AdvMamePlugin::AdvMamePlugin() {
|
||||
_factors.push_back(2);
|
||||
_factors.push_back(3);
|
||||
_factors.push_back(4);
|
||||
}
|
||||
|
||||
Scaler *AdvMamePlugin::createInstance(const Graphics::PixelFormat &format) const {
|
||||
return new AdvMameScaler(format);
|
||||
}
|
||||
|
||||
const char *AdvMamePlugin::getName() const {
|
||||
return "advmame";
|
||||
}
|
||||
|
||||
const char *AdvMamePlugin::getPrettyName() const {
|
||||
return "AdvMame";
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(ADVMAME, PLUGIN_TYPE_SCALER, AdvMamePlugin);
|
||||
55
graphics/scaler/scalebit.h
Normal file
55
graphics/scaler/scalebit.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains an example implementation of the Scale effect
|
||||
* applied to a generic bitmap.
|
||||
*
|
||||
* You can find a high-level description of the effect at:
|
||||
*
|
||||
* https://www.scale2x.it
|
||||
*
|
||||
* Alternatively at the previous license terms, you are allowed to use this
|
||||
* code in your program with these conditions:
|
||||
* - the program is not used in commercial activities.
|
||||
* - the whole source code of the program is released with the binary.
|
||||
* - derivative works of the program are allowed.
|
||||
*/
|
||||
|
||||
#ifndef SCALER_SCALEBIT_H
|
||||
#define SCALER_SCALEBIT_H
|
||||
|
||||
#include "graphics/scalerplugin.h"
|
||||
|
||||
int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned height);
|
||||
void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height);
|
||||
|
||||
class AdvMameScaler : public Scaler {
|
||||
public:
|
||||
AdvMameScaler(const Graphics::PixelFormat &format) : Scaler(format) { _factor = 2; }
|
||||
uint increaseFactor() override;
|
||||
uint decreaseFactor() override;
|
||||
protected:
|
||||
virtual void scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
304
graphics/scaler/thumbnail_intern.cpp
Normal file
304
graphics/scaler/thumbnail_intern.cpp
Normal file
@@ -0,0 +1,304 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "graphics/colormasks.h"
|
||||
#include "graphics/scaler.h"
|
||||
#include "graphics/scaler/intern.h"
|
||||
#include "graphics/paletteman.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
template<typename ColorMask>
|
||||
uint16 quadBlockInterpolate(const uint8 *src, uint32 srcPitch) {
|
||||
uint16 colorx1y1 = *(((const uint16 *)src));
|
||||
uint16 colorx2y1 = *(((const uint16 *)src) + 1);
|
||||
|
||||
uint16 colorx1y2 = *(((const uint16 *)(src + srcPitch)));
|
||||
uint16 colorx2y2 = *(((const uint16 *)(src + srcPitch)) + 1);
|
||||
|
||||
return interpolate16_1_1_1_1<ColorMask>(colorx1y1, colorx2y1, colorx1y2, colorx2y2);
|
||||
}
|
||||
|
||||
template<typename ColorMask>
|
||||
void createThumbnail_2(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
|
||||
// Make sure the width and height is a multiple of 2.
|
||||
width &= ~1;
|
||||
height &= ~1;
|
||||
|
||||
for (int y = 0; y < height; y += 2) {
|
||||
for (int x = 0; x < width; x += 2, dstPtr += 2) {
|
||||
*((uint16 *)dstPtr) = quadBlockInterpolate<ColorMask>(src + 2 * x, srcPitch);
|
||||
}
|
||||
dstPtr += (dstPitch - 2 * width / 2);
|
||||
src += 2 * srcPitch;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ColorMask>
|
||||
void createThumbnail_4(const uint8 *src, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
|
||||
// Make sure the width and height is a multiple of 4
|
||||
width &= ~3;
|
||||
height &= ~3;
|
||||
|
||||
for (int y = 0; y < height; y += 4) {
|
||||
for (int x = 0; x < width; x += 4, dstPtr += 2) {
|
||||
uint16 upleft = quadBlockInterpolate<ColorMask>(src + 2 * x, srcPitch);
|
||||
uint16 upright = quadBlockInterpolate<ColorMask>(src + 2 * (x + 2), srcPitch);
|
||||
uint16 downleft = quadBlockInterpolate<ColorMask>(src + srcPitch * 2 + 2 * x, srcPitch);
|
||||
uint16 downright = quadBlockInterpolate<ColorMask>(src + srcPitch * 2 + 2 * (x + 2), srcPitch);
|
||||
|
||||
*((uint16 *)dstPtr) = interpolate16_1_1_1_1<ColorMask>(upleft, upright, downleft, downright);
|
||||
}
|
||||
dstPtr += (dstPitch - 2 * width / 4);
|
||||
src += 4 * srcPitch;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ColorMask>
|
||||
static void scaleThumbnail(Graphics::Surface &in, Graphics::Surface &out) {
|
||||
while (in.w / out.w >= 4 || in.h / out.h >= 4) {
|
||||
createThumbnail_4<ColorMask>((const uint8 *)in.getPixels(), in.pitch, (uint8 *)in.getPixels(), in.pitch, in.w, in.h);
|
||||
in.w /= 4;
|
||||
in.h /= 4;
|
||||
}
|
||||
|
||||
while (in.w / out.w >= 2 || in.h / out.h >= 2) {
|
||||
createThumbnail_2<ColorMask>((const uint8 *)in.getPixels(), in.pitch, (uint8 *)in.getPixels(), in.pitch, in.w, in.h);
|
||||
in.w /= 2;
|
||||
in.h /= 2;
|
||||
}
|
||||
|
||||
if ((in.w == out.w && in.h < out.h) || (in.w < out.w && in.h == out.h)) {
|
||||
// In this case we simply center the input surface in the output
|
||||
uint8 *dst = (uint8 *)out.getBasePtr((out.w - in.w) / 2, (out.h - in.h) / 2);
|
||||
const uint8 *src = (const uint8 *)in.getPixels();
|
||||
|
||||
for (int y = 0; y < in.h; ++y) {
|
||||
memcpy(dst, src, in.w * in.format.bytesPerPixel);
|
||||
src += in.pitch;
|
||||
dst += out.pitch;
|
||||
}
|
||||
} else {
|
||||
// Assure the aspect of the scaled image still matches the original.
|
||||
int targetWidth = out.w, targetHeight = out.h;
|
||||
|
||||
const float inputAspect = (float)in.w / in.h;
|
||||
const float outputAspect = (float)out.w / out.h;
|
||||
|
||||
if (inputAspect > outputAspect) {
|
||||
targetHeight = int(targetWidth / inputAspect);
|
||||
} else if (inputAspect < outputAspect) {
|
||||
targetWidth = int(targetHeight * inputAspect);
|
||||
}
|
||||
|
||||
// Make sure we are still in the bounds of the output
|
||||
assert(targetWidth <= out.w);
|
||||
assert(targetHeight <= out.h);
|
||||
|
||||
// Center the image on the output surface
|
||||
byte *dst = (byte *)out.getBasePtr((out.w - targetWidth) / 2, (out.h - targetHeight) / 2);
|
||||
const uint dstLineIncrease = out.pitch - targetWidth * out.format.bytesPerPixel;
|
||||
|
||||
const float scaleFactorX = (float)targetWidth / in.w;
|
||||
const float scaleFactorY = (float)targetHeight / in.h;
|
||||
|
||||
for (int y = 0; y < targetHeight; ++y) {
|
||||
const float yFrac = (y / scaleFactorY);
|
||||
const int y1 = (int)yFrac;
|
||||
const int y2 = (y1 + 1 < in.h) ? (y1 + 1) : (in.h - 1);
|
||||
|
||||
for (int x = 0; x < targetWidth; ++x) {
|
||||
const float xFrac = (x / scaleFactorX);
|
||||
const int x1 = (int)xFrac;
|
||||
const int x2 = (x1 + 1 < in.w) ? (x1 + 1) : (in.w - 1);
|
||||
|
||||
// Look up colors at the points
|
||||
uint8 p1R, p1G, p1B;
|
||||
in.format.colorToRGBT<ColorMask>(READ_UINT16(in.getBasePtr(x1, y1)), p1R, p1G, p1B);
|
||||
uint8 p2R, p2G, p2B;
|
||||
in.format.colorToRGBT<ColorMask>(READ_UINT16(in.getBasePtr(x2, y1)), p2R, p2G, p2B);
|
||||
uint8 p3R, p3G, p3B;
|
||||
in.format.colorToRGBT<ColorMask>(READ_UINT16(in.getBasePtr(x1, y2)), p3R, p3G, p3B);
|
||||
uint8 p4R, p4G, p4B;
|
||||
in.format.colorToRGBT<ColorMask>(READ_UINT16(in.getBasePtr(x2, y2)), p4R, p4G, p4B);
|
||||
|
||||
const float xDiff = xFrac - x1;
|
||||
const float yDiff = yFrac - y1;
|
||||
|
||||
uint8 pR = (uint8)((1 - yDiff) * ((1 - xDiff) * p1R + xDiff * p2R) + yDiff * ((1 - xDiff) * p3R + xDiff * p4R));
|
||||
uint8 pG = (uint8)((1 - yDiff) * ((1 - xDiff) * p1G + xDiff * p2G) + yDiff * ((1 - xDiff) * p3G + xDiff * p4G));
|
||||
uint8 pB = (uint8)((1 - yDiff) * ((1 - xDiff) * p1B + xDiff * p2B) + yDiff * ((1 - xDiff) * p3B + xDiff * p4B));
|
||||
|
||||
WRITE_UINT16(dst, out.format.RGBToColorT<ColorMask>(pR, pG, pB));
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
// Move to the next line
|
||||
dst = (byte *)dst + dstLineIncrease;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies the current screen contents to a new surface, using RGB565 format.
|
||||
* WARNING: surf->free() must be called by the user to avoid leaking.
|
||||
*
|
||||
* @param surf the surface to store the data in it
|
||||
*/
|
||||
static bool grabScreen565(Graphics::Surface *surf) {
|
||||
Graphics::Surface *screen = g_system->lockScreen();
|
||||
if (!screen)
|
||||
return false;
|
||||
|
||||
assert(screen->format.bytesPerPixel == 1 || screen->format.bytesPerPixel == 2
|
||||
|| screen->format.bytesPerPixel == 4);
|
||||
assert(screen->getPixels() != 0);
|
||||
|
||||
Graphics::PixelFormat screenFormat = g_system->getScreenFormat();
|
||||
|
||||
surf->create(screen->w, screen->h, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
|
||||
|
||||
byte *palette = 0;
|
||||
if (screenFormat.bytesPerPixel == 1) {
|
||||
palette = new byte[256 * 3];
|
||||
assert(palette);
|
||||
g_system->getPaletteManager()->grabPalette(palette, 0, 256);
|
||||
}
|
||||
|
||||
for (int y = 0; y < screen->h; ++y) {
|
||||
for (int x = 0; x < screen->w; ++x) {
|
||||
byte r = 0, g = 0, b = 0;
|
||||
|
||||
if (screenFormat.bytesPerPixel == 1) {
|
||||
uint8 pixel = *(uint8 *)screen->getBasePtr(x, y);
|
||||
r = palette[pixel * 3 + 0];
|
||||
g = palette[pixel * 3 + 1];
|
||||
b = palette[pixel * 3 + 2];
|
||||
} else if (screenFormat.bytesPerPixel == 2) {
|
||||
uint16 col = READ_UINT16(screen->getBasePtr(x, y));
|
||||
screenFormat.colorToRGB(col, r, g, b);
|
||||
} else if (screenFormat.bytesPerPixel == 4) {
|
||||
uint32 col = READ_UINT32(screen->getBasePtr(x, y));
|
||||
screenFormat.colorToRGB(col, r, g, b);
|
||||
}
|
||||
|
||||
*((uint16 *)surf->getBasePtr(x, y)) = surf->format.RGBToColor(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] palette;
|
||||
|
||||
g_system->unlockScreen();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) {
|
||||
int height;
|
||||
if ((in.w == 320 && in.h == 200) || (in.w == 640 && in.h == 400)) {
|
||||
height = kThumbnailHeight1;
|
||||
} else {
|
||||
height = kThumbnailHeight2;
|
||||
}
|
||||
|
||||
out.create(kThumbnailWidth, height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
|
||||
assert(out.format == Graphics::createPixelFormat<565>());
|
||||
scaleThumbnail<Graphics::ColorMasks<565> >(in, out);
|
||||
in.free();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool createThumbnailFromScreen(Graphics::Surface *surf) {
|
||||
assert(surf);
|
||||
|
||||
Graphics::Surface screen;
|
||||
|
||||
if (!grabScreen565(&screen))
|
||||
return false;
|
||||
|
||||
return createThumbnail(*surf, screen);
|
||||
}
|
||||
|
||||
bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette) {
|
||||
assert(surf);
|
||||
|
||||
Graphics::Surface screen;
|
||||
screen.create(w, h, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
|
||||
|
||||
for (int y = 0; y < screen.h; ++y) {
|
||||
for (int x = 0; x < screen.w; ++x) {
|
||||
byte r, g, b;
|
||||
r = palette[pixels[y * w + x] * 3];
|
||||
g = palette[pixels[y * w + x] * 3 + 1];
|
||||
b = palette[pixels[y * w + x] * 3 + 2];
|
||||
|
||||
*((uint16 *)screen.getBasePtr(x, y)) = screen.format.RGBToColor(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
return createThumbnail(*surf, screen);
|
||||
}
|
||||
|
||||
bool createThumbnail(Graphics::Surface *surf, Graphics::ManagedSurface *in) {
|
||||
assert(surf);
|
||||
|
||||
Graphics::Surface screen;
|
||||
|
||||
if (in->hasPalette()) {
|
||||
uint8 palette[3 * 256];
|
||||
in->grabPalette(palette, 0, 256);
|
||||
return createThumbnail(surf, (const uint8 *)in->getPixels(), in->w, in->h, palette);
|
||||
} else {
|
||||
screen.convertFrom(in->rawSurface(), Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
|
||||
return createThumbnail(*surf, screen);
|
||||
}
|
||||
}
|
||||
|
||||
// this is somewhat awkward, but createScreenShot should logically be in graphics,
|
||||
// but moving other functions in this file into that namespace breaks several engines
|
||||
namespace Graphics {
|
||||
bool createScreenShot(Graphics::Surface &surf) {
|
||||
Graphics::PixelFormat screenFormat = g_system->getScreenFormat();
|
||||
//convert surface to 2 bytes pixel format to avoid problems with palette saving and loading
|
||||
if ((screenFormat.bytesPerPixel == 1) || (screenFormat.bytesPerPixel == 2)) {
|
||||
return grabScreen565(&surf);
|
||||
} else {
|
||||
Graphics::Surface *screen = g_system->lockScreen();
|
||||
if (!screen) {
|
||||
return false;
|
||||
}
|
||||
surf.create(screen->w, screen->h, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
|
||||
for (int y = 0; y < screen->h; ++y) {
|
||||
for (int x = 0; x < screen->w; ++x) {
|
||||
byte r = 0, g = 0, b = 0, a = 0;
|
||||
uint32 col = READ_UINT32(screen->getBasePtr(x, y));
|
||||
screenFormat.colorToARGB(col, a, r, g, b);
|
||||
*((uint32 *)surf.getBasePtr(x, y)) = surf.format.ARGBToColor(a, r, g, b);
|
||||
}
|
||||
}
|
||||
g_system->unlockScreen();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} // End of namespace Graphics
|
||||
112
graphics/scaler/tv.cpp
Normal file
112
graphics/scaler/tv.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "graphics/scaler/tv.h"
|
||||
#include "graphics/scaler.h"
|
||||
#include "graphics/colormasks.h"
|
||||
|
||||
void TVScaler::scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) {
|
||||
if (_format.bytesPerPixel == 2) {
|
||||
if (_format.gLoss == 2)
|
||||
scaleIntern<Graphics::ColorMasks<565> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
else
|
||||
scaleIntern<Graphics::ColorMasks<555> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
} else {
|
||||
if (_format.aLoss == 0)
|
||||
scaleIntern<Graphics::ColorMasks<8888> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
else
|
||||
scaleIntern<Graphics::ColorMasks<888> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint TVScaler::increaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
uint TVScaler::decreaseFactor() {
|
||||
return _factor;
|
||||
}
|
||||
|
||||
template<typename ColorMask>
|
||||
void TVScaler::scaleIntern(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
|
||||
int width, int height) {
|
||||
typedef typename ColorMask::PixelType Pixel;
|
||||
|
||||
const uint32 nextlineSrc = srcPitch / sizeof(Pixel);
|
||||
const Pixel *p = (const Pixel *)srcPtr;
|
||||
|
||||
const uint32 nextlineDst = dstPitch / sizeof(Pixel);
|
||||
Pixel *q = (Pixel *)dstPtr;
|
||||
|
||||
while (height--) {
|
||||
for (int i = 0, j = 0; i < width; ++i, j += 2) {
|
||||
Pixel p1 = *(p + i);
|
||||
Pixel pi;
|
||||
|
||||
pi = (((p1 & ColorMask::kRedBlueMask) * 7) >> 3) & ColorMask::kRedBlueMask;
|
||||
pi |= (((p1 & ColorMask::kGreenMask) * 7) >> 3) & ColorMask::kGreenMask;
|
||||
pi |= p1 & ColorMask::kAlphaMask;
|
||||
|
||||
uint8 r, g, b;
|
||||
_format.colorToRGB(p1,r,g,b);
|
||||
pi = _format.RGBToColor((r*7)/8, (g*7) / 8, (b*7) / 8);
|
||||
|
||||
*(q + j) = p1;
|
||||
*(q + j + 1) = p1;
|
||||
*(q + j + nextlineDst) = pi;
|
||||
*(q + j + nextlineDst + 1) = pi;
|
||||
}
|
||||
p += nextlineSrc;
|
||||
q += nextlineDst << 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TVPlugin final : public ScalerPluginObject {
|
||||
public:
|
||||
TVPlugin();
|
||||
|
||||
Scaler *createInstance(const Graphics::PixelFormat &format) const override;
|
||||
|
||||
bool canDrawCursor() const override { return false; }
|
||||
uint extraPixels() const override { return 0; }
|
||||
const char *getName() const override;
|
||||
const char *getPrettyName() const override;
|
||||
};
|
||||
|
||||
TVPlugin::TVPlugin() {
|
||||
_factors.push_back(2);
|
||||
}
|
||||
|
||||
Scaler *TVPlugin::createInstance(const Graphics::PixelFormat &format) const {
|
||||
return new TVScaler(format);
|
||||
}
|
||||
|
||||
const char *TVPlugin::getName() const {
|
||||
return "tv";
|
||||
}
|
||||
|
||||
const char *TVPlugin::getPrettyName() const {
|
||||
return "TV";
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(TV, PLUGIN_TYPE_SCALER, TVPlugin);
|
||||
40
graphics/scaler/tv.h
Normal file
40
graphics/scaler/tv.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_SCALER_TV_H
|
||||
#define GRAPHICS_SCALER_TV_H
|
||||
|
||||
#include "graphics/scalerplugin.h"
|
||||
|
||||
class TVScaler : public Scaler {
|
||||
public:
|
||||
TVScaler(const Graphics::PixelFormat &format) : Scaler(format) { _factor = 2; }
|
||||
uint increaseFactor() override;
|
||||
uint decreaseFactor() override;
|
||||
private:
|
||||
virtual void scaleIntern(const uint8 *srcPtr, uint32 srcPitch,
|
||||
uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y) override;
|
||||
template<typename ColorMask>
|
||||
void scaleIntern(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr,
|
||||
uint32 dstPitch, int width, int height);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user