BACKENDS: Drop launcherInitSize() and use 2d backend gfx manager for launcher.

This commit is contained in:
Pawel Kolodziejski 2020-09-30 08:28:15 +02:00
parent d0713f1072
commit 6f69981904
26 changed files with 7046 additions and 58 deletions

View File

@ -128,7 +128,7 @@ bool LegacySdlEventSource::handleKbdMouse(Common::Event &event) {
if (_km.x != oldKmX || _km.y != oldKmY) {
if (_graphicsManager) {
_graphicsManager->getWindow()->warpMouseInWindow((Uint16)(_km.x / MULTIPLIER), (Uint16)(_km.y / MULTIPLIER));
dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->getWindow()->warpMouseInWindow((Uint16)(_km.x / MULTIPLIER), (Uint16)(_km.y / MULTIPLIER)); // ResidualVM
}
event.type = Common::EVENT_MOUSEMOVE;
@ -240,8 +240,8 @@ void LegacySdlEventSource::checkScreenChange() {
return;
}
int newMaxX = _graphicsManager->getWindowWidth() - 1;
int newMaxY = _graphicsManager->getWindowHeight() - 1;
int newMaxX = dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->getWindowWidth() - 1; // ResidualVM
int newMaxY = dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->getWindowHeight() - 1; // ResidualVM
if (_km.x_max != newMaxX || _km.y_max != newMaxY) {
resetKeyboardEmulation(newMaxX, newMaxY);

View File

@ -270,6 +270,9 @@ bool ResVmSdlEventSource::handleKbdMouse(Common::Event &event) {
updateKbdMouse();
if (!dynamic_cast<SdlGraphics3dManager *>(_graphicsManager))
return false;
if (_km.x != oldKmX || _km.y != oldKmY) {
SdlGraphics3dManager *graphicsManager = dynamic_cast<SdlGraphics3dManager *>(_graphicsManager);

View File

@ -187,7 +187,13 @@ bool SdlEventSource::processMouseEvent(Common::Event &event, int x, int y, int r
event.mouse.y = y;
if (_graphicsManager) {
return _graphicsManager->notifyMousePosition(event.mouse);
// ResidualVM start:
if (dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->notifyMousePosition(event.mouse);
} else if (dynamic_cast<SdlGraphicsManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->notifyMousePosition(event.mouse);
}
// ResidualVM end
}
return true;
@ -508,8 +514,15 @@ bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
case SDL_WINDOWEVENT:
switch (ev.window.event) {
case SDL_WINDOWEVENT_EXPOSED:
if (_graphicsManager)
_graphicsManager->notifyVideoExpose();
if (_graphicsManager) {
// ResidualVM start:
if (dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->notifyVideoExpose();
} else if (dynamic_cast<SdlGraphicsManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->notifyVideoExpose();
}
// ResidualVM end
}
return false;
// SDL2 documentation indicate that SDL_WINDOWEVENT_SIZE_CHANGED is sent either as a result
@ -566,8 +579,15 @@ bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
return true;
#else
case SDL_VIDEOEXPOSE:
if (_graphicsManager)
_graphicsManager->notifyVideoExpose();
if (_graphicsManager) {
// ResidualVM start:
if (dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->notifyVideoExpose();
} else if (dynamic_cast<SdlGraphicsManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->notifyVideoExpose();
}
// ResidualVM end
}
return false;
case SDL_VIDEORESIZE:
@ -960,8 +980,13 @@ void SdlEventSource::setEngineRunning(const bool value) {
bool SdlEventSource::handleResizeEvent(Common::Event &event, int w, int h) {
if (_graphicsManager) {
_graphicsManager->notifyResize(w, h);
// ResidualVM start:
if (dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->notifyResize(w, h);
} else if (dynamic_cast<SdlGraphicsManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->notifyResize(w, h);
}
// ResidualVM end
// If the screen changed, send an Common::EVENT_SCREEN_CHANGED
int screenID = g_system->getScreenChangeID();
if (screenID != _lastScreenID) {

View File

@ -44,7 +44,7 @@ public:
SdlEventSource();
virtual ~SdlEventSource();
void setGraphicsManager(SdlGraphics3dManager *gMan) { _graphicsManager = gMan; }
void setGraphicsManager(GraphicsManager *gMan) { _graphicsManager = gMan; } // ResidualVM specific
/**
* Gets and processes SDL events.
@ -86,7 +86,7 @@ protected:
/**
* The associated graphics manager.
*/
SdlGraphics3dManager *_graphicsManager;
GraphicsManager *_graphicsManager; // ResidualVM specific
/**
* Search for a game controller db file and load it.

View File

@ -45,7 +45,7 @@ SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *source, SdlWindow *window
}
void SdlGraphicsManager::activateManager() {
_eventSource->setGraphicsManager(dynamic_cast<SdlGraphics3dManager *>(this));
_eventSource->setGraphicsManager(this);
// Register the graphics manager as a event observer
g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);

View File

@ -2626,7 +2626,7 @@ void SurfaceSdlGraphicsManager::recreateScreenTexture() {
SDL_Surface *SurfaceSdlGraphicsManager::SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags) {
deinitializeRenderer();
uint32 createWindowFlags = SDL_WINDOW_RESIZABLE;
uint32 createWindowFlags = 0;//SDL_WINDOW_RESIZABLE; // ResidualVM specific
if ((flags & SDL_FULLSCREEN) != 0) {
createWindowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
}

View File

@ -463,11 +463,6 @@ Common::KeymapperDefaultBindings *OSystem_Android::getKeymapperDefaultBindings()
return keymapperDefaultBindings;
}
// ResidualVM specific method
void OSystem_Android::launcherInitSize(uint w, uint h) {
dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->setupScreen(w, h, true, true, false);
}
uint32 OSystem_Android::getMillis(bool skipRecord) {
timeval curTime;

View File

@ -193,7 +193,6 @@ public:
virtual char *convertEncoding(const char *to, const char *from, const char *string, size_t length);
// ResidualVM specific method
virtual void launcherInitSize(uint w, uint h);
void updateEventScale(const GLESBaseTexture *tex);
TouchControls* getTouchControls() { return &_touchControls; }
};

View File

@ -93,6 +93,7 @@ OSystem_SDL::OSystem_SDL()
_eventSource(0),
_eventSourceWrapper(nullptr),
_window(0) {
_gfxManagerState = {};
}
OSystem_SDL::~OSystem_SDL() {
@ -105,7 +106,13 @@ OSystem_SDL::~OSystem_SDL() {
delete _savefileManager;
_savefileManager = 0;
if (_graphicsManager) {
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->deactivateManager();
// ResidualVM start:
if (dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->deactivateManager();
} else {
dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->deactivateManager();
}
// ResidualVM end
}
delete _graphicsManager;
_graphicsManager = 0;
@ -257,7 +264,14 @@ void OSystem_SDL::initBackend() {
#endif
if (_graphicsManager == 0) {
_graphicsManager = dynamic_cast<GraphicsManager *>(new SurfaceSdlGraphics3dManager(_eventSource, _window)); // ResidualVM specific
// ResidualVM start:
#ifdef USE_OPENGL
_graphicsManager = new OpenGLSdlGraphicsManager(_eventSource, _window);
_graphicsMode = _firstGLMode;
#else
_graphicsManager = new SurfaceSdlGraphicsManager(_eventSource, _window);
#endif
// ResidualVM end
}
}
@ -296,7 +310,13 @@ void OSystem_SDL::initBackend() {
// so the virtual keyboard can be initialized, but we have to add the
// graphics manager as an event observer after initializing the event
// manager.
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->activateManager();
// ResidualVM start:
if (dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->activateManager();
} else {
dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->activateManager();
}
// ResidualVM end
}
// ResidualVM specific code - Start
@ -381,7 +401,13 @@ void OSystem_SDL::detectAntiAliasingSupport() {
void OSystem_SDL::engineInit() {
#if SDL_VERSION_ATLEAST(2, 0, 0)
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->unlockWindowSize();
// ResidualVM start:
if (dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->unlockWindowSize();
} else {
dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->unlockWindowSize();
}
// ResidualVM end
// Disable screen saver when engine starts
SDL_DisableScreenSaver();
#endif
@ -403,7 +429,13 @@ void OSystem_SDL::engineInit() {
void OSystem_SDL::engineDone() {
#if SDL_VERSION_ATLEAST(2, 0, 0)
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->unlockWindowSize();
// ResidualVM start:
if (dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->unlockWindowSize();
} else {
dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->unlockWindowSize();
}
// ResidualVM end
SDL_EnableScreenSaver();
#endif
#ifdef USE_TASKBAR
@ -489,9 +521,17 @@ void OSystem_SDL::setupScreen(uint screenW, uint screenH, bool fullscreen, bool
switchedManager = true;
}
if (dynamic_cast<SdlGraphicsManager *>(_graphicsManager)) {
_gfxManagerState = dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->getState();
}
if (switchedManager) {
SdlGraphics3dManager *sdlGraphicsManager = dynamic_cast<SdlGraphics3dManager *>(_graphicsManager);
sdlGraphicsManager->deactivateManager();
SdlGraphics3dManager *sdlGraphicsManager;
if (dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)) {
dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->deactivateManager();
} else {
dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->deactivateManager();
}
delete _graphicsManager;
if (accel3d) {
@ -510,16 +550,6 @@ Common::Array<uint> OSystem_SDL::getSupportedAntiAliasingLevels() const {
}
#endif
void OSystem_SDL::launcherInitSize(uint w, uint h) {
Common::String rendererConfig = ConfMan.get("renderer");
Graphics::RendererType desiredRendererType = Graphics::parseRendererTypeCode(rendererConfig);
Graphics::RendererType matchingRendererType = Graphics::getBestMatchingAvailableRendererType(desiredRendererType);
bool fullscreen = ConfMan.getBool("fullscreen");
setupScreen(w, h, fullscreen, matchingRendererType != Graphics::kRendererTypeTinyGL);
}
// End of ResidualVM specific code
void OSystem_SDL::quit() {
@ -535,8 +565,15 @@ void OSystem_SDL::fatalError() {
Common::KeymapArray OSystem_SDL::getGlobalKeymaps() {
Common::KeymapArray globalMaps = BaseBackend::getGlobalKeymaps();
SdlGraphics3dManager *graphicsManager = dynamic_cast<SdlGraphics3dManager *>(_graphicsManager);
globalMaps.push_back(graphicsManager->getKeymap());
// ResidualVM start:
Common::Keymap *keymap;
if (dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)) {
keymap = dynamic_cast<SdlGraphics3dManager *>(_graphicsManager)->getKeymap();
} else {
keymap = dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->getKeymap();
}
globalMaps.push_back(keymap);
// ResidualVM end
return globalMaps;
}
@ -745,6 +782,52 @@ int OSystem_SDL::getDefaultGraphicsMode() const {
}
bool OSystem_SDL::setGraphicsMode(int mode) {
// ResidualVM start:
if (dynamic_cast<OpenGLSdlGraphics3dManager *>(_graphicsManager) ||
dynamic_cast<SurfaceSdlGraphics3dManager *>(_graphicsManager)) {
if (dynamic_cast<OpenGLSdlGraphics3dManager *>(_graphicsManager)) {
dynamic_cast<OpenGLSdlGraphics3dManager *>(_graphicsManager)->deactivateManager();
}
if (dynamic_cast<SurfaceSdlGraphics3dManager *>(_graphicsManager)) {
dynamic_cast<SurfaceSdlGraphics3dManager *>(_graphicsManager)->deactivateManager();
}
delete _graphicsManager;
SdlGraphicsManager *sdlGraphicsManager = nullptr;
if (mode < _firstGLMode) {
debug(1, "switching to plain SDL graphics");
_graphicsManager = sdlGraphicsManager = new SurfaceSdlGraphicsManager(_eventSource, _window);
} else if (mode >= _firstGLMode) {
debug(1, "switching to OpenGL graphics");
_graphicsManager = sdlGraphicsManager = new OpenGLSdlGraphicsManager(_eventSource, _window);
}
_graphicsMode = mode;
assert(sdlGraphicsManager);
sdlGraphicsManager->activateManager();
// This failing will probably have bad consequences...
if (!sdlGraphicsManager->setState(_gfxManagerState)) {
return false;
}
// Next setup the cursor again
CursorMan.pushCursor(0, 0, 0, 0, 0, 0);
CursorMan.popCursor();
// Next setup cursor palette if needed
if (_graphicsManager->getFeatureState(kFeatureCursorPalette)) {
CursorMan.pushCursorPalette(0, 0, 0);
CursorMan.popCursorPalette();
}
_graphicsManager->beginGFXTransaction();
// Oh my god if this failed the client code might just explode.
return _graphicsManager->setGraphicsMode(_graphicsModeIds[mode]);
}
// ResidualVM end
if (_graphicsModes.empty()) {
return _graphicsManager->setGraphicsMode(mode);
}

View File

@ -97,7 +97,6 @@ public:
virtual void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) override;
Common::Array<uint> getSupportedAntiAliasingLevels() const override;
#endif
virtual void launcherInitSize(uint w, uint h) override;
// ResidualVM - End
protected:
@ -132,6 +131,8 @@ protected:
*/
SdlWindow *_window;
SdlGraphicsManager::State _gfxManagerState; // ResidualVM
// ResidualVM specific code - start
#ifdef USE_OPENGL
// Graphics capabilities

View File

@ -159,8 +159,7 @@ static Common::Error runGame(const Plugin *plugin, OSystem &system, const Common
Common::Error err = Common::kNoError;
Engine *engine = 0;
// Disabled in ResidualVM:
#if 0//defined(SDL_BACKEND) && defined(USE_OPENGL) && defined(USE_RGB_COLOR)
#if defined(SDL_BACKEND) && defined(USE_OPENGL) && defined(USE_RGB_COLOR)
// HACK: We set up the requested graphics mode setting here to allow the
// backend to switch from Surface SDL to OpenGL if necessary. This is
// needed because otherwise the g_system->getSupportedFormats might return
@ -328,7 +327,6 @@ static void setupGraphics(OSystem &system) {
system.setGraphicsMode(ConfMan.get("gfx_mode").c_str());
system.initSize(320, 200);
system.launcherInitSize(640, 480); //ResidualVM specific
if (ConfMan.hasKey("aspect_ratio"))
system.setFeatureState(OSystem::kFeatureAspectRatioCorrection, ConfMan.getBool("aspect_ratio"));

View File

@ -128,7 +128,6 @@ void OSystem::destroy() {
}
bool OSystem::setGraphicsMode(const char *name) {
return true; //ResidualVM not use it
if (!name)
return false;

View File

@ -859,15 +859,6 @@ public:
*/
virtual void initSizeHint(const Graphics::ModeList &modes) {}
/**
* !!! ResidualVM specific method !!!
* Set the size of the launcher virtual screen.
*
* @param width the new virtual screen width
* @param height the new virtual screen height
*/
virtual void launcherInitSize(uint width, uint height) {};
/**
* !!! Not used in ResidualVM !!!
*

7
configure vendored
View File

@ -134,8 +134,7 @@ done
# Default settings
#
#ResidualVM defaults: sdlnet=no libcurl=no flac=no seq_midi=no sndio=no timidity=no
# a52=no faad=no fluidsynth=no mt32emu=no lua=no build_scalers=no
# build_hq_scalers=no nuked_opl=no tts=no osxdockplugin=no discord=no
# a52=no faad=no fluidsynth=no mt32emu=no lua=no nuked_opl=no tts=no osxdockplugin=no discord=no
#
# Default lib behavior yes/no/auto
_sdl=no
@ -189,8 +188,8 @@ _verbose_build=no
_text_console=no
_mt32emu=no
_lua=no
_build_scalers=no
_build_hq_scalers=no
_build_scalers=yes
_build_hq_scalers=yes
_enable_prof=no
_enable_asan=no
_enable_tsan=no

View File

@ -412,7 +412,6 @@ void GUIErrorMessage(const Common::U32String &msg, const char *url) {
g_system->beginGFXTransaction();
initCommonGFX();
g_system->initSize(320, 200);
g_system->launcherInitSize(640, 480);//ResidualVM specific
if (g_system->endGFXTransaction() == OSystem::kTransactionSuccess) {
if (url) {
GUI::MessageDialogWithURL dialog(msg, url);

412
graphics/scaler/2xsai.cpp Normal file
View File

@ -0,0 +1,412 @@
/* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#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 interpolate16_1_1<ColorMask>
#define interpolate_3_1 interpolate16_3_1<ColorMask>
#define interpolate_6_1_1 interpolate16_6_1_1<ColorMask>
#define interpolate_1_1_1_1 interpolate16_1_1_1_1<ColorMask>
template<typename ColorMask>
void Super2xSaITemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
const uint16 *bP;
uint16 *dP;
const uint32 nextlineSrc = srcPitch >> 1;
while (height--) {
bP = (const uint16 *)srcPtr;
dP = (uint16 *)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) = (uint16) product1a;
*(dP + 1) = (uint16) product1b;
*(dP + dstPitch/2 + 0) = (uint16) product2a;
*(dP + dstPitch/2 + 1) = (uint16) product2b;
bP += 1;
dP += 2;
}
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
}
}
void Super2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
extern int gBitFormat;
if (gBitFormat == 565)
Super2xSaITemplate<Graphics::ColorMasks<565> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
else
Super2xSaITemplate<Graphics::ColorMasks<555> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
}
template<typename ColorMask>
void SuperEagleTemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
const uint16 *bP;
uint16 *dP;
const uint32 nextlineSrc = srcPitch >> 1;
while (height--) {
bP = (const uint16 *)srcPtr;
dP = (uint16 *)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) = (uint16) product1a;
*(dP + 1) = (uint16) product1b;
*(dP + dstPitch/2 + 0) = (uint16) product2a;
*(dP + dstPitch/2 + 1) = (uint16) product2b;
bP += 1;
dP += 2;
}
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
}
}
void SuperEagle(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
extern int gBitFormat;
if (gBitFormat == 565)
SuperEagleTemplate<Graphics::ColorMasks<565> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
else
SuperEagleTemplate<Graphics::ColorMasks<555> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
}
template<typename ColorMask>
void _2xSaITemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
const uint16 *bP;
uint16 *dP;
const uint32 nextlineSrc = srcPitch >> 1;
while (height--) {
bP = (const uint16 *)srcPtr;
dP = (uint16 *)dstPtr;
for (int i = 0; i < width; ++i) {
unsigned colorA, colorB, 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) = (uint16) colorA;
*(dP + 1) = (uint16) product;
*(dP + dstPitch/2 + 0) = (uint16) product1;
*(dP + dstPitch/2 + 1) = (uint16) product2;
bP += 1;
dP += 2;
}
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
}
}
void _2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
extern int gBitFormat;
if (gBitFormat == 565)
_2xSaITemplate<Graphics::ColorMasks<565> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
else
_2xSaITemplate<Graphics::ColorMasks<555> >(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
}

276
graphics/scaler/aspect.cpp Normal file
View File

@ -0,0 +1,276 @@
/* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#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) {
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;
if (srcPtr == dstPtr)
break;
memcpy(dstPtr, srcPtr, sizeof(uint16) * 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) {
#if ASPECT_MODE != kSuperFastAndUglyAspectMode
extern int gBitFormat;
if (interpolate) {
if (gBitFormat == 565)
return stretch200To240Interpolated<Graphics::ColorMasks<565> >(buf, pitch, width, height, srcX, srcY, origSrcY);
else // gBitFormat == 555
return stretch200To240Interpolated<Graphics::ColorMasks<555> >(buf, pitch, width, height, srcX, srcY, origSrcY);
} else {
#endif
return stretch200To240Nearest(buf, pitch, width, height, srcX, srcY, origSrcY);
#if ASPECT_MODE != kSuperFastAndUglyAspectMode
}
#endif
}

View File

@ -0,0 +1,74 @@
/* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "graphics/scaler/downscaler.h"
#include "graphics/scaler/intern.h"
#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) {
// Rounding constants and masks used for different pixel formats
static const int roundingconstants[] = { 0x00200802, 0x00201002 };
static const int redbluegreenMasks[] = { 0x03E07C1F, 0x07E0F81F };
extern int gBitFormat;
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) {
extern 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

View File

@ -0,0 +1,35 @@
/* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef GRAPHICS_SCALER_DOWNSCALER_H
#define GRAPHICS_SCALER_DOWNSCALER_H
#include "common/scummsys.h"
#include "graphics/scaler.h"
/**
* This filter (down)scales the source image by a factor of 1/2.
* For example, a 320x200 image is scaled to 160x100.
*/
DECLARE_SCALER(DownscaleAllByHalf);
#endif

1970
graphics/scaler/hq2x.cpp Normal file

File diff suppressed because it is too large Load Diff

2947
graphics/scaler/hq3x.cpp Normal file

File diff suppressed because it is too large Load Diff

502
graphics/scaler/scale2x.cpp Normal file
View File

@ -0,0 +1,502 @@
/*
* This file is part of the Scale2x project.
*
* Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This file contains a C and MMX implementation of the Scale2x effect.
*
* You can find an high level description of the effect at :
*
* http://scale2x.sourceforge.net/
*
* 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 :
*
* &current -> E
* &current_left -> D
* &current_right -> F
* &current_upper -> B
* &current_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

68
graphics/scaler/scale2x.h Normal file
View File

@ -0,0 +1,68 @@
/*
* This file is part of the Scale2x project.
*
* Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef SCALER_SCALE2X_H
#define SCALER_SCALE2X_H
#if defined(_MSC_VER)
#define __restrict__
#endif
#ifdef __sgi
#define __restrict__ __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

222
graphics/scaler/scale3x.cpp Normal file
View File

@ -0,0 +1,222 @@
/*
* This file is part of the Scale2x project.
*
* Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This file contains a C and MMX implementation of the Scale2x effect.
*
* You can find an high level description of the effect at :
*
* http://scale2x.sourceforge.net/
*
* 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);
}

40
graphics/scaler/scale3x.h Normal file
View File

@ -0,0 +1,40 @@
/*
* This file is part of the Scale2x project.
*
* Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef SCALER_SCALE3X_H
#define SCALER_SCALE3X_H
#if defined(_MSC_VER)
#define __restrict__
#endif
#ifdef __sgi
#define __restrict__ __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

View File

@ -0,0 +1,350 @@
/*
* This file is part of the Scale2x project.
*
* Copyright (C) 2003 Andrea Mazzoleni
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This file contains an example implementation of the Scale effect
* applyed to a generic bitmap.
*
* You can find an high level description of the effect at :
*
* http://scale2x.sourceforge.net/
*
* 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"
#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 an 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;
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;
}
}