STARK: Optionally use linear filtering when rendering backgrounds

This commit is contained in:
Bastien Bouclet 2019-01-15 20:54:01 +01:00
parent 45c5cf0c80
commit b9a1b8eefd
17 changed files with 87 additions and 9 deletions

View File

@ -297,7 +297,8 @@ static const ADFileBasedFallback fileBasedFallback[] = {
{NULL, {NULL}}
};*/
#define GAMEOPTION_ASSETS_MOD GUIO_GAMEOPTIONS1
#define GAMEOPTION_ASSETS_MOD GUIO_GAMEOPTIONS1
#define GAMEOPTION_LINEAR_FILTERING GUIO_GAMEOPTIONS2
static const ADExtraGuiOptionsMap optionsList[] = {
{
@ -309,6 +310,15 @@ static const ADExtraGuiOptionsMap optionsList[] = {
true
}
},
{
GAMEOPTION_LINEAR_FILTERING,
{
_s("Enable linear filtering of the backgrounds images"),
_s("When linear filtering is enabled the background graphics are smoother in full screen mode, at the cost of some details."),
"use_linear_filtering",
true
}
},
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
@ -317,7 +327,7 @@ class StarkMetaEngine : public AdvancedMetaEngine {
public:
StarkMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), starkGames, optionsList) {
_singleId = "stark";
_guiOptions = GUIO2(GUIO_NOMIDI, GAMEOPTION_ASSETS_MOD);
_guiOptions = GUIO3(GUIO_NOMIDI, GAMEOPTION_ASSETS_MOD, GAMEOPTION_LINEAR_FILTERING);
}
const char *getName() const override {

View File

@ -198,10 +198,10 @@ XMGDecoder::Block XMGDecoder::processYCrCb() {
XMGDecoder::Block XMGDecoder::processTrans() {
Block block;
block.a1 = _transColor;
block.a2 = _transColor;
block.b1 = _transColor;
block.b2 = _transColor;
block.a1 = 0;
block.a2 = 0;
block.b1 = 0;
block.b2 = 0;
return block;
}
@ -214,24 +214,32 @@ XMGDecoder::Block XMGDecoder::processRGB() {
color += _stream->readByte() << 16;
if (color != _transColor)
color += 255 << 24;
else
color = 0;
block.a1 = color;
color = _stream->readUint16LE();
color += _stream->readByte() << 16;
if (color != _transColor)
color += 255 << 24;
else
color = 0;
block.a2 = color;
color = _stream->readUint16LE();
color += _stream->readByte() << 16;
if (color != _transColor)
color += 255 << 24;
else
color = 0;
block.b1 = color;
color = _stream->readUint16LE();
color += _stream->readByte() << 16;
if (color != _transColor)
color += 255 << 24;
else
color = 0;
block.b2 = color;
return block;

View File

@ -65,6 +65,11 @@ private:
Common::ReadStream *_stream;
/**
* The transparency color in the RGB and transparency blocks.
* In the output surface, the transparent color is black with zero
* alpha. So the images are effectively pre-multiplied alpha.
*/
uint32 _transColor;
};

View File

@ -162,7 +162,11 @@ void OpenGLSDriver::start2DMode() {
// Enable alpha blending
glEnable(GL_BLEND);
//glBlendEquation(GL_FUNC_ADD); // It's the default
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// This blend mode prevents color fringes due to filtering.
// It requires the textures to have their color values pre-multiplied
// with their alpha value. This is the "Premultiplied Alpha" technique.
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);

View File

@ -78,6 +78,23 @@ void OpenGlTexture::update(const Graphics::Surface *surface, const byte *palette
updateLevel(0, surface, palette);
}
void OpenGlTexture::setSamplingFilter(Texture::SamplingFilter filter) {
assert(_levelCount == 0);
switch (filter) {
case kNearest:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case kLinear:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
default:
warning("Unhandled sampling filter %d", filter);
}
}
void OpenGlTexture::setLevelCount(uint32 count) {
_levelCount = count;

View File

@ -41,6 +41,7 @@ public:
// Texture API
void bind() const override;
void update(const Graphics::Surface *surface, const byte *palette = nullptr) override;
void setSamplingFilter(SamplingFilter filter) override;
void setLevelCount(uint32 count) override;
void addLevel(uint32 level, const Graphics::Surface *surface, const byte *palette = nullptr) override;

View File

@ -40,12 +40,20 @@ public:
Texture();
virtual ~Texture();
enum SamplingFilter {
kNearest,
kLinear
};
/** Make the texture active */
virtual void bind() const = 0;
/** Define or update the texture pixel data */
virtual void update(const Graphics::Surface *surface, const byte *palette = nullptr) = 0;
/** Set the filter used when sampling the texture */
virtual void setSamplingFilter(SamplingFilter filter) = 0;
/**
* Define the total number of levels of details
*

View File

@ -88,4 +88,8 @@ bool Settings::isAssetsModEnabled() const {
return ConfMan.getBool("enable_assets_mod");
}
Gfx::Texture::SamplingFilter Settings::getImageSamplingFilter() const {
return ConfMan.getBool("use_linear_filtering") ? Gfx::Texture::kLinear : Gfx::Texture::kNearest;
}
} // End of namespace Stark

View File

@ -25,6 +25,7 @@
#include "common/config-manager.h"
#include "engines/stark/gfx/texture.h"
#include "engines/stark/services/services.h"
struct ADGameDescription;
@ -97,6 +98,9 @@ public:
/** Should the game try to load external replacement assets? */
bool isAssetsModEnabled() const;
/** Should linear filtering be used when sampling the background image textures? */
Gfx::Texture::SamplingFilter getImageSamplingFilter() const;
private:
Audio::Mixer *_mixer;
bool _hasLowRes;

View File

@ -255,7 +255,7 @@ Screen *UserInterface::getScreenByName(Screen::Name screenName) const {
}
bool UserInterface::isInGameScreen() const {
return _currentScreen->getName() == Screen::kScreenGame;
return _currentScreen && (_currentScreen->getName() == Screen::kScreenGame);
}
bool UserInterface::isInSaveLoadMenuScreen() const {

View File

@ -45,6 +45,8 @@ FMVScreen::FMVScreen(Gfx::Driver *gfx, Cursor *cursor) :
_decoder->setSoundType(Audio::Mixer::kSFXSoundType);
_texture = _gfx->createTexture();
_texture->setSamplingFilter(StarkSettings->getImageSamplingFilter());
_surfaceRenderer = _gfx->createSurfaceRenderer();
}

View File

@ -27,6 +27,8 @@
#include "engines/stark/gfx/driver.h"
#include "engines/stark/gfx/surfacerenderer.h"
#include "engines/stark/gfx/texture.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/settings.h"
namespace Stark {
@ -40,6 +42,7 @@ VisualEffect::VisualEffect(VisualType type, const Common::Point &size, Gfx::Driv
_surface->create(size.x, size.y, Gfx::Driver::getRGBAPixelFormat());
_texture = _gfx->createTexture(_surface);
_texture->setSamplingFilter(StarkSettings->getImageSamplingFilter());
_surfaceRenderer = _gfx->createSurfaceRenderer();
}

View File

@ -31,6 +31,7 @@
#include "engines/stark/services/global.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/settings.h"
namespace Stark {
@ -57,7 +58,9 @@ void VisualExplodingImage::initFromSurface(const Graphics::Surface *surface) {
// Decode the XMG
_surface = new Graphics::Surface();
_surface->copyFrom(*surface);
_texture = _gfx->createTexture(_surface);
_texture->setSamplingFilter(StarkSettings->getImageSamplingFilter());
// Create an explosion unit for each pixel in the surface
_units.resize(_surface->w * _surface->h);

View File

@ -31,6 +31,7 @@
#include "engines/stark/services/global.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/settings.h"
namespace Stark {
@ -55,6 +56,7 @@ void VisualFlashingImage::initFromSurface(const Graphics::Surface *surface) {
assert(!_texture);
_texture = _gfx->createTexture(surface);
_texture->setSamplingFilter(StarkSettings->getImageSamplingFilter());
}
void VisualFlashingImage::updateFadeLevel() {

View File

@ -29,6 +29,8 @@
#include "engines/stark/gfx/driver.h"
#include "engines/stark/gfx/surfacerenderer.h"
#include "engines/stark/gfx/texture.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/settings.h"
namespace Stark {
@ -61,6 +63,7 @@ void VisualImageXMG::load(Common::ReadStream *stream) {
// Decode the XMG
_surface = Formats::XMGDecoder::decode(stream);
_texture = _gfx->createTexture(_surface);
_texture->setSamplingFilter(StarkSettings->getImageSamplingFilter());
_originalWidth = _surface->w;
_originalHeight = _surface->h;
@ -81,7 +84,7 @@ bool VisualImageXMG::loadPNG(Common::SeekableReadStream *stream) {
_surface = pngDecoder.getSurface()->convertTo(Gfx::Driver::getRGBAPixelFormat());
_texture = _gfx->createTexture(_surface);
_texture->setSamplingFilter(Gfx::Texture::kLinear);
_texture->setSamplingFilter(StarkSettings->getImageSamplingFilter());
return true;
}

View File

@ -27,6 +27,7 @@
#include "engines/stark/gfx/texture.h"
#include "engines/stark/scene.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/settings.h"
#include "common/str.h"
#include "common/archive.h"
@ -63,6 +64,7 @@ void VisualSmacker::load(Common::SeekableReadStream *stream) {
rewind();
_texture = _gfx->createTexture();
_texture->setSamplingFilter(StarkSettings->getImageSamplingFilter());
update();
}

View File

@ -140,6 +140,8 @@ void VisualText::createTexture() {
// Create a texture from the surface
_texture = _gfx->createTexture(&surface);
_texture->setSamplingFilter(Gfx::Texture::kNearest);
surface.free();
}