mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 05:38:56 +00:00
181 lines
6.7 KiB
C++
181 lines
6.7 KiB
C++
/* 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_EDGE_H
|
|
#define GRAPHICS_SCALER_EDGE_H
|
|
|
|
#include "graphics/scalerplugin.h"
|
|
|
|
class EdgePlugin : public SourceScaler {
|
|
public:
|
|
|
|
EdgePlugin();
|
|
void initialize(const Graphics::PixelFormat &format) override;
|
|
uint increaseFactor() override;
|
|
uint decreaseFactor() override;
|
|
bool canDrawCursor() const override { return false; }
|
|
bool useOldSource() const override { return true; }
|
|
uint extraPixels() const override { return 1; }
|
|
const char *getName() const override;
|
|
const char *getPrettyName() const 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
|