Update to v083r09 release.

byuu says:

Added frequency, latency, resampler selection to the audio settings
panel (I really only wanted it there for resampler selection ... having
three options matches the driver selection style though, so whatever.)
The linear/hermite sampler will double the framerate when running Game
Boy games, and sounds the same. Same framerate and sound quality on
SNES. But it will cause buzzing in many NES titles.
Also re-added the composition { never, fullscreen, always } modes.
I think that option is clutter, but it's just impossible to get good
audio+video on Windows 7 without it ...
Lastly, HQ2x was ported over, but not very well. I just convert source
pixels from RGB888 to RGB555, and output pixels in the opposite
direction.
Need someone good to port the diff() and blend functions over to RGB888
in a way that's not terribly slow.
This commit is contained in:
Tim Allen 2011-10-31 20:55:48 +11:00
parent 483f9f8f20
commit bf78e66027
26 changed files with 293 additions and 177 deletions

View File

@ -20,6 +20,7 @@ struct Intrinsics {
#define COMPILER_VISUALC #define COMPILER_VISUALC
Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::VisualC; } Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::VisualC; }
#else #else
#warning "unable to detect compiler"
#define COMPILER_UNKNOWN #define COMPILER_UNKNOWN
Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::Unknown; } Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::Unknown; }
#endif #endif
@ -37,8 +38,9 @@ struct Intrinsics {
#define PLATFORM_WIN #define PLATFORM_WIN
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Windows; } Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Windows; }
#else #else
#warning "unable to detect platform"
#define PLATFORM_UNKNOWN #define PLATFORM_UNKNOWN
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Unknown; }
#endif #endif
/* Endian detection */ /* Endian detection */
@ -52,9 +54,10 @@ struct Intrinsics {
#define ARCH_MSB #define ARCH_MSB
Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::MSB; } Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::MSB; }
#else #else
#warning "unable to detect endian"
#define ENDIAN_UNKNOWN #define ENDIAN_UNKNOWN
#define ARCH_UNKNOWN #define ARCH_UNKNOWN
Intrinsics::Endian Intrinsics::endia() { return Intrinsics::Endian::Unknown; } Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::Unknown; }
#endif #endif
#endif #endif

View File

@ -36,6 +36,13 @@ namespace nall {
buffersize = newsize; buffersize = newsize;
} }
template<typename... Args>
bool append(const T& data, Args&&... args) {
bool result = append(data);
append(std::forward<Args>(args)...);
return result;
}
bool append(const T data) { bool append(const T data) {
for(unsigned index = 0; index < buffersize; index++) { for(unsigned index = 0; index < buffersize; index++) {
if(pool[index] == &data) return false; if(pool[index] == &data) return false;

View File

@ -2,6 +2,7 @@
#include <snes/snes.hpp> #include <snes/snes.hpp>
#include <gameboy/gameboy.hpp> #include <gameboy/gameboy.hpp>
#include <nall/compositor.hpp>
#include <nall/config.hpp> #include <nall/config.hpp>
#include <nall/directory.hpp> #include <nall/directory.hpp>
#include <nall/dsp.hpp> #include <nall/dsp.hpp>
@ -32,6 +33,7 @@ struct Application {
bool quit; bool quit;
bool pause; bool pause;
bool autopause; bool autopause;
bool compositionEnable;
string basepath; string basepath;
string userpath; string userpath;

View File

@ -19,12 +19,14 @@ Config::Config() {
attach(video.fullScreenMode = 0, "Video::FullScreenMode"); attach(video.fullScreenMode = 0, "Video::FullScreenMode");
attach(video.startFullScreen = false, "Video::StartFullScreen"); attach(video.startFullScreen = false, "Video::StartFullScreen");
attach(video.compositionMode = 0, "Video::CompositionMode");
attach(audio.driver = "", "Audio::Driver"); attach(audio.driver = "", "Audio::Driver");
attach(audio.synchronize = true, "Audio::Synchronize"); attach(audio.synchronize = true, "Audio::Synchronize");
attach(audio.mute = false, "Audio::Mute"); attach(audio.mute = false, "Audio::Mute");
attach(audio.volume = 100, "Audio::Volume"); attach(audio.volume = 100, "Audio::Volume");
attach(audio.latency = 60, "Audio::Latency"); attach(audio.latency = 60, "Audio::Latency");
attach(audio.resampler = "sinc", "Audio::Resampler");
attach(audio.frequency = 48000, "Audio::Frequency::Native"); attach(audio.frequency = 48000, "Audio::Frequency::Native");
attach(audio.frequencyNES = 1789772, "Audio::Frequency::NES"); attach(audio.frequencyNES = 1789772, "Audio::Frequency::NES");

View File

@ -15,6 +15,7 @@ struct Config : public configuration {
unsigned gamma; unsigned gamma;
unsigned fullScreenMode; unsigned fullScreenMode;
unsigned compositionMode;
bool startFullScreen; bool startFullScreen;
} video; } video;
@ -25,6 +26,7 @@ struct Config : public configuration {
bool mute; bool mute;
unsigned volume; unsigned volume;
unsigned latency; unsigned latency;
string resampler;
unsigned frequency; unsigned frequency;
unsigned frequencyNES; unsigned frequencyNES;

View File

@ -35,9 +35,7 @@ GameBoyController::GameBoyController() {
select.mapping = "KB0::Apostrophe"; select.mapping = "KB0::Apostrophe";
start.mapping = "KB0::Return"; start.mapping = "KB0::Return";
append(up); append(down); append(left); append(right); append(up, down, left, right, b, a, select, start, bTurbo, aTurbo);
append(b); append(a); append(select); append(start);
append(bTurbo); append(aTurbo);
} }
// //

View File

@ -35,9 +35,7 @@ NesGamepad::NesGamepad() {
select.mapping = "KB0::Apostrophe"; select.mapping = "KB0::Apostrophe";
start.mapping = "KB0::Return"; start.mapping = "KB0::Return";
append(up); append(down); append(left); append(right); append(up, down, left, right, b,a, select, start, bTurbo, aTurbo);
append(b); append(a); append(select); append(start);
append(bTurbo); append(aTurbo);
} }
// //
@ -58,6 +56,5 @@ NesPort2Input::NesPort2Input() {
NesInput::NesInput() { NesInput::NesInput() {
name = "NES"; name = "NES";
append(port1); append(port1, port1);
append(port2);
} }

View File

@ -8,8 +8,8 @@ int16_t SnesGamepad::poll(unsigned n) {
case SNES::Input::JoypadID::A: return a.poll() | aTurbo.poll(); case SNES::Input::JoypadID::A: return a.poll() | aTurbo.poll();
case SNES::Input::JoypadID::Y: return y.poll() | yTurbo.poll(); case SNES::Input::JoypadID::Y: return y.poll() | yTurbo.poll();
case SNES::Input::JoypadID::X: return x.poll() | xTurbo.poll(); case SNES::Input::JoypadID::X: return x.poll() | xTurbo.poll();
case SNES::Input::JoypadID::L: return l.poll(); case SNES::Input::JoypadID::L: return l.poll() | lTurbo.poll();
case SNES::Input::JoypadID::R: return r.poll(); case SNES::Input::JoypadID::R: return r.poll() | rTurbo.poll();
case SNES::Input::JoypadID::Select: return select.poll(); case SNES::Input::JoypadID::Select: return select.poll();
case SNES::Input::JoypadID::Start: return start.poll(); case SNES::Input::JoypadID::Start: return start.poll();
} }
@ -23,6 +23,7 @@ SnesGamepad::SnesGamepad(const string &name, bool defaultBindings) {
b.name = "B", a.name = "A", y.name = "Y", x.name = "X"; b.name = "B", a.name = "A", y.name = "Y", x.name = "X";
l.name = "L", r.name = "R", select.name = "Select", start.name = "Start"; l.name = "L", r.name = "R", select.name = "Select", start.name = "Start";
bTurbo.name = "Turbo B", aTurbo.name = "Turbo A", yTurbo.name = "Turbo Y", xTurbo.name = "Turbo X"; bTurbo.name = "Turbo B", aTurbo.name = "Turbo A", yTurbo.name = "Turbo Y", xTurbo.name = "Turbo X";
lTurbo.name = "Turbo L", rTurbo.name = "Turbo R";
if(defaultBindings) { if(defaultBindings) {
up.mapping = "KB0::Up"; up.mapping = "KB0::Up";
@ -39,10 +40,8 @@ SnesGamepad::SnesGamepad(const string &name, bool defaultBindings) {
start.mapping = "KB0::Return"; start.mapping = "KB0::Return";
} }
append(up); append(down); append(left); append(right); append(up, down, left, right, b, a, y, x, l, r, select, start);
append(b); append(a); append(y); append(x); append(bTurbo, aTurbo, yTurbo, xTurbo, lTurbo, rTurbo);
append(l); append(r); append(select); append(start);
append(bTurbo); append(aTurbo); append(yTurbo); append(xTurbo);
} }
// //
@ -70,8 +69,7 @@ SnesMouse::SnesMouse(const string &name, bool defaultBindings) {
right.mapping = "MS0::Button2"; right.mapping = "MS0::Button2";
} }
append(xaxis); append(yaxis); append(xaxis, yaxis, left, right);
append(left); append(right);
} }
// //
@ -103,8 +101,7 @@ SnesSuperScope::SnesSuperScope(const string &name, bool defaultBindings) {
pause.mapping = "KB0::P"; pause.mapping = "KB0::P";
} }
append(xaxis); append(yaxis); append(xaxis, yaxis, trigger, cursor, turbo, pause);
append(trigger); append(cursor); append(turbo); append(pause);
} }
// //
@ -132,8 +129,7 @@ SnesJustifier::SnesJustifier(const string &name, bool defaultBindings) {
start.mapping = "MS0::Button2"; start.mapping = "MS0::Button2";
} }
append(xaxis), append(yaxis); append(xaxis, yaxis, trigger, start);
append(trigger), append(start);
} }
// //
@ -184,6 +180,5 @@ justifier2("Justifier - Port 2", false)
SnesInput::SnesInput() { SnesInput::SnesInput() {
name = "SNES"; name = "SNES";
append(port1); append(port1, port2);
append(port2);
} }

View File

@ -3,6 +3,7 @@ struct SnesGamepad : TertiaryInput {
DigitalInput b, a, y, x; DigitalInput b, a, y, x;
DigitalInput l, r, select, start; DigitalInput l, r, select, start;
TurboInput bTurbo, aTurbo, yTurbo, xTurbo; TurboInput bTurbo, aTurbo, yTurbo, xTurbo;
TurboInput lTurbo, rTurbo;
int16_t poll(unsigned n); int16_t poll(unsigned n);
SnesGamepad(const string &name, bool defaultBindings); SnesGamepad(const string &name, bool defaultBindings);

View File

@ -44,7 +44,15 @@ void Interface::setController(unsigned port, unsigned device) {
} }
void Interface::updateDSP() { void Interface::updateDSP() {
audio.set(Audio::Frequency, config->audio.frequency);
audio.set(Audio::Latency, config->audio.latency);
if(config->audio.resampler == "linear" ) dspaudio.setResampler(DSP::ResampleEngine::Linear);
if(config->audio.resampler == "hermite") dspaudio.setResampler(DSP::ResampleEngine::Hermite);
if(config->audio.resampler == "sinc" ) dspaudio.setResampler(DSP::ResampleEngine::Sinc);
dspaudio.setResamplerFrequency(config->audio.frequency);
dspaudio.setVolume(config->audio.mute == false ? (double)config->audio.volume / 100.0 : 0.0); dspaudio.setVolume(config->audio.mute == false ? (double)config->audio.volume / 100.0 : 0.0);
switch(mode()) { switch(mode()) {
case Mode::NES: return dspaudio.setFrequency(config->audio.frequencyNES); case Mode::NES: return dspaudio.setFrequency(config->audio.frequencyNES);
case Mode::SNES: return dspaudio.setFrequency(config->audio.frequencySNES); case Mode::SNES: return dspaudio.setFrequency(config->audio.frequencySNES);

View File

@ -27,7 +27,7 @@ void Application::run() {
} }
Application::Application(int argc, char **argv) { Application::Application(int argc, char **argv) {
title = "bsnes v083.08"; title = "bsnes v083.09";
application = this; application = this;
quit = false; quit = false;
@ -56,6 +56,9 @@ Application::Application(int argc, char **argv) {
boldFont = { fontFamily, "8, Bold" }; boldFont = { fontFamily, "8, Bold" };
titleFont = { fontFamily, "16, Bold" }; titleFont = { fontFamily, "16, Bold" };
compositionEnable = compositor::enabled();
if(config->video.compositionMode == 2) compositor::enable(false);
windowManager = new WindowManager; windowManager = new WindowManager;
mainWindow = new MainWindow; mainWindow = new MainWindow;
fileBrowser = new FileBrowser; fileBrowser = new FileBrowser;
@ -104,6 +107,7 @@ Application::Application(int argc, char **argv) {
interface->unloadCartridge(); interface->unloadCartridge();
windowManager->saveGeometry(); windowManager->saveGeometry();
if(compositionEnable) compositor::enable(true);
} }
Application::~Application() { Application::~Application() {

View File

@ -16,7 +16,7 @@ AdvancedSettings::AdvancedSettings() {
RadioBox::group(focusPolicy[0], focusPolicy[1], focusPolicy[2]); RadioBox::group(focusPolicy[0], focusPolicy[1], focusPolicy[2]);
focusPolicy[config->input.focusPolicy].setChecked(); focusPolicy[config->input.focusPolicy].setChecked();
aboutLabel.setFont(application->boldFont); aboutLabel.setFont(application->boldFont);
aboutLabel.setText("bsnes author: byuu license: GPLv3 website: http://byuu.org/"); aboutLabel.setText("bsnes author: byuu license: GPLv3 website: byuu.org");
lstring list; lstring list;

View File

@ -23,6 +23,33 @@ void AudioSlider::setPosition(unsigned position) {
AudioSettings::AudioSettings() { AudioSettings::AudioSettings() {
title.setFont(application->titleFont); title.setFont(application->titleFont);
title.setText("Audio Settings"); title.setText("Audio Settings");
outputLabel.setFont(application->boldFont);
outputLabel.setText("Output settings:");
frequencyLabel.setText("Frequency:");
frequencySelection.append("32000hz");
frequencySelection.append("44100hz");
frequencySelection.append("48000hz");
frequencySelection.append("96000hz");
latencyLabel.setText("Latency:");
latencySelection.append( "40ms");
latencySelection.append( "60ms");
latencySelection.append( "80ms");
latencySelection.append("100ms");
latencySelection.append("120ms");
resamplerLabel.setText("Resampler:");
resamplerSelection.append("Linear");
resamplerSelection.append("Hermite");
resamplerSelection.append("Sinc");
volume.name.setText("Volume:");
volume.slider.setLength(201);
volume.base = 100;
volume.step = 1;
frequencyAdjustmentLabel.setFont(application->boldFont); frequencyAdjustmentLabel.setFont(application->boldFont);
frequencyAdjustmentLabel.setText("Frequency: (lower to reduce audio crackling; raise to reduce video tearing)"); frequencyAdjustmentLabel.setText("Frequency: (lower to reduce audio crackling; raise to reduce video tearing)");
@ -41,39 +68,79 @@ AudioSettings::AudioSettings() {
gameBoy.base = 4194304; gameBoy.base = 4194304;
gameBoy.step = 131; gameBoy.step = 131;
outputAdjustmentLabel.setFont(application->boldFont);
outputAdjustmentLabel.setText("Output:");
volume.name.setText("Volume:");
volume.slider.setLength(201);
volume.base = 100;
volume.step = 1;
append(title, ~0, 0, 5); append(title, ~0, 0, 5);
append(outputLabel, ~0, 0);
append(outputLayout, ~0, 0, 5);
outputLayout.append(frequencyLabel, 0, 0, 5);
outputLayout.append(frequencySelection, ~0, 0, 5);
outputLayout.append(latencyLabel, 0, 0, 5);
outputLayout.append(latencySelection, ~0, 0, 5);
outputLayout.append(resamplerLabel, 0, 0, 5);
outputLayout.append(resamplerSelection, ~0, 0);
append(volume, ~0, 0, 5);
append(frequencyAdjustmentLabel, ~0, 0); append(frequencyAdjustmentLabel, ~0, 0);
append(nes, ~0, 0); append(nes, ~0, 0);
append(snes, ~0, 0); append(snes, ~0, 0);
append(gameBoy, ~0, 0, 5); append(gameBoy, ~0, 0);
append(outputAdjustmentLabel, ~0, 0);
append(volume, ~0, 0); frequencySelection.setSelection(
config->audio.frequency == 32000 ? 0 :
config->audio.frequency == 44100 ? 1 :
config->audio.frequency == 48000 ? 2 :
config->audio.frequency == 96000 ? 3 : 0
);
latencySelection.setSelection(
config->audio.latency == 40 ? 0 :
config->audio.latency == 60 ? 1 :
config->audio.latency == 80 ? 2 :
config->audio.latency == 100 ? 3 :
config->audio.latency == 120 ? 4 : 0
);
resamplerSelection.setSelection(
config->audio.resampler == "linear" ? 0 :
config->audio.resampler == "hermite" ? 1 :
config->audio.resampler == "sinc" ? 2 : 0
);
volume.setPosition(config->audio.volume);
nes.setPosition(config->audio.frequencyNES); nes.setPosition(config->audio.frequencyNES);
snes.setPosition(config->audio.frequencySNES); snes.setPosition(config->audio.frequencySNES);
gameBoy.setPosition(config->audio.frequencyGameBoy); gameBoy.setPosition(config->audio.frequencyGameBoy);
volume.setPosition(config->audio.volume);
nes.slider.onChange = snes.slider.onChange = gameBoy.slider.onChange = frequencySelection.onChange = latencySelection.onChange = resamplerSelection.onChange =
volume.slider.onChange = volume.slider.onChange = nes.slider.onChange = snes.slider.onChange = gameBoy.slider.onChange =
{ &AudioSettings::synchronize, this }; { &AudioSettings::synchronize, this };
synchronize(); synchronize();
} }
void AudioSettings::synchronize() { void AudioSettings::synchronize() {
config->audio.frequency =
frequencySelection.selection() == 0 ? 32000 :
frequencySelection.selection() == 1 ? 44100 :
frequencySelection.selection() == 2 ? 48000 :
frequencySelection.selection() == 3 ? 96000 : 48000;
config->audio.latency =
latencySelection.selection() == 0 ? 40 :
latencySelection.selection() == 1 ? 60 :
latencySelection.selection() == 2 ? 80 :
latencySelection.selection() == 3 ? 100 :
latencySelection.selection() == 4 ? 120 : 60;
config->audio.resampler =
resamplerSelection.selection() == 0 ? "linear" :
resamplerSelection.selection() == 1 ? "hermite" :
resamplerSelection.selection() == 2 ? "sinc" : "sinc";
config->audio.volume = volume.position();
config->audio.frequencyNES = nes.position(); config->audio.frequencyNES = nes.position();
config->audio.frequencySNES = snes.position(); config->audio.frequencySNES = snes.position();
config->audio.frequencyGameBoy = gameBoy.position(); config->audio.frequencyGameBoy = gameBoy.position();
config->audio.volume = volume.position();
nes.value.setText({ nes.position(), "hz" }); nes.value.setText({ nes.position(), "hz" });
snes.value.setText({ snes.position(), "hz" }); snes.value.setText({ snes.position(), "hz" });

View File

@ -13,12 +13,19 @@ struct AudioSlider : HorizontalLayout {
struct AudioSettings : SettingsLayout { struct AudioSettings : SettingsLayout {
Label title; Label title;
Label outputLabel;
HorizontalLayout outputLayout;
Label frequencyLabel;
ComboBox frequencySelection;
Label latencyLabel;
ComboBox latencySelection;
Label resamplerLabel;
ComboBox resamplerSelection;
AudioSlider volume;
Label frequencyAdjustmentLabel; Label frequencyAdjustmentLabel;
AudioSlider nes; AudioSlider nes;
AudioSlider snes; AudioSlider snes;
AudioSlider gameBoy; AudioSlider gameBoy;
Label outputAdjustmentLabel;
AudioSlider volume;
void synchronize(); void synchronize();
AudioSettings(); AudioSettings();

View File

@ -29,6 +29,12 @@ VideoSettings::VideoSettings() {
fullScreen[1].setText("Scale"); fullScreen[1].setText("Scale");
fullScreen[2].setText("Stretch"); fullScreen[2].setText("Stretch");
RadioBox::group(fullScreen[0], fullScreen[1], fullScreen[2]); RadioBox::group(fullScreen[0], fullScreen[1], fullScreen[2]);
compositorLabel.setText("Disable window compositor:");
compositorLabel.setFont(application->boldFont);
compositor[0].setText("Never");
compositor[1].setText("Fullscreen");
compositor[2].setText("Always");
RadioBox::group(compositor[0], compositor[1], compositor[2]);
append(title, ~0, 0, 5); append(title, ~0, 0, 5);
append(colorAdjustment, ~0, 0); append(colorAdjustment, ~0, 0);
@ -39,10 +45,15 @@ VideoSettings::VideoSettings() {
append(overscanHorizontal, ~0, 0); append(overscanHorizontal, ~0, 0);
append(overscanVertical, ~0, 0, 5); append(overscanVertical, ~0, 0, 5);
append(fullScreenMode, ~0, 0); append(fullScreenMode, ~0, 0);
append(fullScreenLayout, ~0, 0); append(fullScreenLayout, ~0, 0, 5);
fullScreenLayout.append(fullScreen[0], ~0, 0, 5); fullScreenLayout.append(fullScreen[0], ~0, 0, 5);
fullScreenLayout.append(fullScreen[1], ~0, 0, 5); fullScreenLayout.append(fullScreen[1], ~0, 0, 5);
fullScreenLayout.append(fullScreen[2], ~0, 0); fullScreenLayout.append(fullScreen[2], ~0, 0);
append(compositorLabel, ~0, 0);
append(compositorLayout, ~0, 0);
compositorLayout.append(compositor[0], ~0, 0, 5);
compositorLayout.append(compositor[1], ~0, 0, 5);
compositorLayout.append(compositor[2], ~0, 0);
brightness.slider.setPosition(config->video.brightness); brightness.slider.setPosition(config->video.brightness);
contrast.slider.setPosition(config->video.contrast); contrast.slider.setPosition(config->video.contrast);
@ -50,13 +61,32 @@ VideoSettings::VideoSettings() {
overscanHorizontal.slider.setPosition(config->video.maskOverscanHorizontal); overscanHorizontal.slider.setPosition(config->video.maskOverscanHorizontal);
overscanVertical.slider.setPosition(config->video.maskOverscanVertical); overscanVertical.slider.setPosition(config->video.maskOverscanVertical);
fullScreen[config->video.fullScreenMode].setChecked(); fullScreen[config->video.fullScreenMode].setChecked();
compositor[config->video.compositionMode].setChecked();
synchronize(); synchronize();
brightness.slider.onChange = contrast.slider.onChange = gamma.slider.onChange = brightness.slider.onChange = contrast.slider.onChange = gamma.slider.onChange =
overscanHorizontal.slider.onChange = overscanVertical.slider.onChange = overscanHorizontal.slider.onChange = overscanVertical.slider.onChange =
fullScreen[0].onTick = fullScreen[1].onTick = fullScreen[2].onTick =
{ &VideoSettings::synchronize, this }; { &VideoSettings::synchronize, this };
fullScreen[0].onTick = [&] { config->video.fullScreenMode = 0; };
fullScreen[1].onTick = [&] { config->video.fullScreenMode = 1; };
fullScreen[2].onTick = [&] { config->video.fullScreenMode = 2; };
compositor[0].onTick = [&] {
config->video.compositionMode = 0;
compositor::enable(application->compositionEnable);
};
compositor[1].onTick = [&] {
config->video.compositionMode = 1;
compositor::enable(application->compositionEnable && mainWindow->fullScreen() == false);
};
compositor[2].onTick = [&] {
config->video.compositionMode = 2;
compositor::enable(false);
};
} }
void VideoSettings::synchronize() { void VideoSettings::synchronize() {
@ -65,9 +95,9 @@ void VideoSettings::synchronize() {
config->video.gamma = gamma.slider.position(); config->video.gamma = gamma.slider.position();
config->video.maskOverscanHorizontal = overscanHorizontal.slider.position(); config->video.maskOverscanHorizontal = overscanHorizontal.slider.position();
config->video.maskOverscanVertical = overscanVertical.slider.position(); config->video.maskOverscanVertical = overscanVertical.slider.position();
if(fullScreen[0].checked()) config->video.fullScreenMode = 0; if(fullScreen[0].checked()) { config->video.fullScreenMode = 0; }
if(fullScreen[1].checked()) config->video.fullScreenMode = 1; if(fullScreen[1].checked()) { config->video.fullScreenMode = 1; }
if(fullScreen[2].checked()) config->video.fullScreenMode = 2; if(fullScreen[2].checked()) { config->video.fullScreenMode = 2; }
brightness.value.setText({ config->video.brightness, "%" }); brightness.value.setText({ config->video.brightness, "%" });
contrast.value.setText({ config->video.contrast, "%" }); contrast.value.setText({ config->video.contrast, "%" });

View File

@ -18,6 +18,9 @@ struct VideoSettings : SettingsLayout {
Label fullScreenMode; Label fullScreenMode;
HorizontalLayout fullScreenLayout; HorizontalLayout fullScreenLayout;
RadioBox fullScreen[3]; RadioBox fullScreen[3];
Label compositorLabel;
HorizontalLayout compositorLayout;
RadioBox compositor[3];
void synchronize(); void synchronize();
VideoSettings(); VideoSettings();

View File

@ -109,6 +109,11 @@ void Utility::toggleFullScreen() {
} }
resizeMainWindow(); resizeMainWindow();
if(application->compositionEnable) {
if(config->video.compositionMode == 1) {
compositor::enable(mainWindow->fullScreen() == false);
}
}
} }
void Utility::bindVideoFilter() { void Utility::bindVideoFilter() {

View File

@ -4,7 +4,7 @@ using namespace nall;
extern "C" { extern "C" {
void filter_size(unsigned&, unsigned&); void filter_size(unsigned&, unsigned&);
void filter_render(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned); void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned);
}; };
enum { enum {
@ -34,6 +34,15 @@ const uint8_t hqTable[256] = {
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14, 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14,
}; };
static uint16_t rgb555(uint32_t C) {
return ((C >> 9) & 0x7c00) + ((C >> 6) & 0x03e0) + ((C >> 3) & 0x001f);
}
static uint32_t rgb888(uint16_t C) {
return ((C & 0x7c00) << 9) + ((C & 0x03e0) << 6) + ((C & 0x001f) << 3)
+ ((C & 0x7000) << 4) + ((C & 0x0380) << 1) + ((C & 0x001c) >> 2);
}
static void initialize() { static void initialize() {
static bool initialized = false; static bool initialized = false;
if(initialized == true) return; if(initialized == true) return;
@ -42,16 +51,12 @@ static void initialize() {
yuvTable = new uint32_t[32768]; yuvTable = new uint32_t[32768];
for(unsigned i = 0; i < 32768; i++) { for(unsigned i = 0; i < 32768; i++) {
uint8_t R = (i >> 0) & 31; uint32_t C = rgb888(i);
uint8_t G = (i >> 5) & 31;
uint8_t B = (i >> 10) & 31;
//bgr555->bgr888 double r = (uint8_t)(C >> 16);
double r = (R << 3) | (R >> 2); double g = (uint8_t)(C >> 8);
double g = (G << 3) | (G >> 2); double b = (uint8_t)(C >> 0);
double b = (B << 3) | (B >> 2);
//bgr888->yuv
double y = (r + g + b) * (0.25f * (63.5f / 48.0f)); double y = (r + g + b) * (0.25f * (63.5f / 48.0f));
double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f); double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f);
double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f); double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f);
@ -147,18 +152,18 @@ dllexport void filter_size(unsigned &width, unsigned &height) {
} }
dllexport void filter_render( dllexport void filter_render(
uint16_t *output, unsigned outputPitch, uint32_t *output, unsigned outputPitch,
const uint16_t *input, unsigned inputPitch, const uint32_t *input, unsigned inputPitch,
unsigned width, unsigned height unsigned width, unsigned height
) { ) {
initialize(); initialize();
outputPitch >>= 1, inputPitch >>= 1; outputPitch >>= 2, inputPitch >>= 2;
#pragma omp parallel for #pragma omp parallel for
for(unsigned y = 0; y < height; y++) { for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * inputPitch; const uint32_t *in = input + y * inputPitch;
uint16_t *out0 = output + y * outputPitch * 2; uint32_t *out0 = output + y * outputPitch * 2;
uint16_t *out1 = output + y * outputPitch * 2 + outputPitch; uint32_t *out1 = output + y * outputPitch * 2 + outputPitch;
int prevline = (y == 0 ? 0 : inputPitch); int prevline = (y == 0 ? 0 : inputPitch);
int nextline = (y == height - 1 ? 0 : inputPitch); int nextline = (y == height - 1 ? 0 : inputPitch);
@ -168,15 +173,15 @@ dllexport void filter_render(
*out1++ = 0; *out1++ = 0; *out1++ = 0; *out1++ = 0;
for(unsigned x = 1; x < width - 1; x++) { for(unsigned x = 1; x < width - 1; x++) {
uint16_t A = *(in - prevline - 1); uint16_t A = rgb555(*(in - prevline - 1));
uint16_t B = *(in - prevline + 0); uint16_t B = rgb555(*(in - prevline + 0));
uint16_t C = *(in - prevline + 1); uint16_t C = rgb555(*(in - prevline + 1));
uint16_t D = *(in - 1); uint16_t D = rgb555(*(in - 1));
uint16_t E = *(in + 0); uint16_t E = rgb555(*(in + 0));
uint16_t F = *(in + 1); uint16_t F = rgb555(*(in + 1));
uint16_t G = *(in + nextline - 1); uint16_t G = rgb555(*(in + nextline - 1));
uint16_t H = *(in + nextline + 0); uint16_t H = rgb555(*(in + nextline + 0));
uint16_t I = *(in + nextline + 1); uint16_t I = rgb555(*(in + nextline + 1));
uint32_t e = yuvTable[E] + diff_offset; uint32_t e = yuvTable[E] + diff_offset;
uint8_t pattern; uint8_t pattern;
@ -189,10 +194,10 @@ dllexport void filter_render(
pattern |= diff(e, H) << 6; pattern |= diff(e, H) << 6;
pattern |= diff(e, I) << 7; pattern |= diff(e, I) << 7;
*(out0 + 0) = blend(hqTable[pattern], E, A, B, D, F, H); pattern = rotate[pattern]; *(out0 + 0) = rgb888(blend(hqTable[pattern], E, A, B, D, F, H)); pattern = rotate[pattern];
*(out0 + 1) = blend(hqTable[pattern], E, C, F, B, H, D); pattern = rotate[pattern]; *(out0 + 1) = rgb888(blend(hqTable[pattern], E, C, F, B, H, D)); pattern = rotate[pattern];
*(out1 + 1) = blend(hqTable[pattern], E, I, H, F, D, B); pattern = rotate[pattern]; *(out1 + 1) = rgb888(blend(hqTable[pattern], E, I, H, F, D, B)); pattern = rotate[pattern];
*(out1 + 0) = blend(hqTable[pattern], E, G, D, H, B, F); *(out1 + 0) = rgb888(blend(hqTable[pattern], E, G, D, H, B, F));
in++; in++;
out0 += 2; out0 += 2;

View File

@ -4,7 +4,7 @@ using namespace nall;
extern "C" { extern "C" {
void filter_size(unsigned&, unsigned&); void filter_size(unsigned&, unsigned&);
void filter_render(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned); void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned);
}; };
dllexport void filter_size(unsigned &width, unsigned &height) { dllexport void filter_size(unsigned &width, unsigned &height) {
@ -13,33 +13,33 @@ dllexport void filter_size(unsigned &width, unsigned &height) {
} }
dllexport void filter_render( dllexport void filter_render(
uint16_t *output, unsigned outputPitch, uint32_t *output, unsigned outputPitch,
const uint16_t *input, unsigned inputPitch, const uint32_t *input, unsigned inputPitch,
unsigned width, unsigned height unsigned width, unsigned height
) { ) {
outputPitch >>= 1, inputPitch >>= 1; outputPitch >>= 2, inputPitch >>= 2;
#pragma omp parallel for #pragma omp parallel for
for(unsigned y = 0; y < height; y++) { for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * inputPitch; const uint32_t *in = input + y * inputPitch;
uint16_t *out0 = output + y * outputPitch * 2; uint32_t *out0 = output + y * outputPitch * 2;
uint16_t *out1 = output + y * outputPitch * 2 + outputPitch; uint32_t *out1 = output + y * outputPitch * 2 + outputPitch;
int prevline = (y == 0 ? 0 : inputPitch); int prevline = (y == 0 ? 0 : inputPitch);
int nextline = (y == height - 1 ? 0 : inputPitch); int nextline = (y == height - 1 ? 0 : inputPitch);
for(unsigned x = 0; x < width; x++) { for(unsigned x = 0; x < width; x++) {
uint16_t A = *(input - prevline); uint32_t A = *(in - prevline);
uint16_t B = (x > 0) ? *(input - 1) : *input; uint32_t B = (x > 0) ? *(in - 1) : *in;
uint16_t C = *input; uint32_t C = *in;
uint16_t D = (x < width - 1) ? *(input + 1) : *input; uint32_t D = (x < width - 1) ? *(in + 1) : *in;
uint16_t E = *(input++ + nextline); uint32_t E = *(in++ + nextline);
if(A != E && B != D) { if(A != E && B != D) {
*out0++ = (A == B ? C + A - ((C ^ A) & 0x0421) >> 1 : C); *out0++ = (A == B ? C + A - ((C ^ A) & 0x010101) >> 1 : C);
*out0++ = (A == D ? C + A - ((C ^ A) & 0x0421) >> 1 : C); *out0++ = (A == D ? C + A - ((C ^ A) & 0x010101) >> 1 : C);
*out1++ = (E == B ? C + E - ((C ^ E) & 0x0421) >> 1 : C); *out1++ = (E == B ? C + E - ((C ^ E) & 0x010101) >> 1 : C);
*out1++ = (E == D ? C + E - ((C ^ E) & 0x0421) >> 1 : C); *out1++ = (E == D ? C + E - ((C ^ E) & 0x010101) >> 1 : C);
} else { } else {
*out0++ = C; *out0++ = C;
*out0++ = C; *out0++ = C;

View File

@ -16,7 +16,6 @@ objects += out/Scanline-Light.filter
objects += out/Scale2x.filter objects += out/Scale2x.filter
objects += out/LQ2x.filter objects += out/LQ2x.filter
objects += out/HQ2x.filter objects += out/HQ2x.filter
objects += out/Overscan.filter
objects += out/Phosphor3x.filter objects += out/Phosphor3x.filter
compile = $(cpp) $(link) $(flags) -o $@ -shared $< compile = $(cpp) $(link) $(flags) -o $@ -shared $<
@ -31,7 +30,6 @@ out/Scanline-Light.filter: Scanline/Scanline-Light.cpp Scanline/*
out/Scale2x.filter: Scale2x/Scale2x.cpp Scale2x/* out/Scale2x.filter: Scale2x/Scale2x.cpp Scale2x/*
out/LQ2x.filter: LQ2x/LQ2x.cpp LQ2x/* out/LQ2x.filter: LQ2x/LQ2x.cpp LQ2x/*
out/HQ2x.filter: HQ2x/HQ2x.cpp HQ2x/* out/HQ2x.filter: HQ2x/HQ2x.cpp HQ2x/*
out/Overscan.filter: Overscan/Overscan.cpp Overscan/*
out/Phosphor3x.filter: Phosphor3x/Phosphor3x.cpp Phosphor3x/* out/Phosphor3x.filter: Phosphor3x/Phosphor3x.cpp Phosphor3x/*
build: $(objects) build: $(objects)

View File

@ -1,30 +0,0 @@
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
dllexport void filter_size(unsigned &width, unsigned &height) {
}
dllexport void filter_render(
uint16_t *output, unsigned outputPitch,
const uint16_t *input, unsigned inputPitch,
unsigned width, unsigned height
) {
outputPitch >>= 1, inputPitch >>= 1;
#pragma omp parallel for
for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * inputPitch;
uint16_t *out = output + y * outputPitch;
for(unsigned x = 0; x < width; x++) {
uint16_t pixel = *in++;
if(x < 8 || x >= width - 8 || y < 8 || y >= height - 8) pixel = 0;
*out++ = pixel;
}
}
}

View File

@ -4,7 +4,7 @@ using namespace nall;
extern "C" { extern "C" {
void filter_size(unsigned&, unsigned&); void filter_size(unsigned&, unsigned&);
void filter_render(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned); void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned);
}; };
dllexport void filter_size(unsigned &width, unsigned &height) { dllexport void filter_size(unsigned &width, unsigned &height) {
@ -13,33 +13,45 @@ dllexport void filter_size(unsigned &width, unsigned &height) {
} }
dllexport void filter_render( dllexport void filter_render(
uint16_t *output, unsigned outputPitch, uint32_t *output, unsigned outputPitch,
const uint16_t *input, unsigned inputPitch, const uint32_t *input, unsigned inputPitch,
unsigned width, unsigned height unsigned width, unsigned height
) { ) {
outputPitch >>= 1, inputPitch >>= 1; outputPitch >>= 2, inputPitch >>= 2;
#pragma omp parallel for #pragma omp parallel for
for(unsigned y = 0; y < height; y++) { for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * inputPitch; const uint32_t *in = input + y * inputPitch;
uint16_t *out0 = output + y * outputPitch * 3; uint32_t *out0 = output + y * outputPitch * 3;
uint16_t *out1 = output + y * outputPitch * 3 + outputPitch; uint32_t *out1 = output + y * outputPitch * 3 + outputPitch;
uint16_t *out2 = output + y * outputPitch * 3 + outputPitch + outputPitch; uint32_t *out2 = output + y * outputPitch * 3 + outputPitch + outputPitch;
for(unsigned x = 0; x < width; x++) { for(unsigned x = 0; x < width; x++) {
uint16_t full = *in++, half = (full >> 1) & 0x3def; uint32_t A = (x == 0 ? 0 : *(in - 1));
uint32_t B = *in;
uint32_t C = (x == width - 1 ? 0 : *(in + 1));
*out0++ = (full & 0x7c00); uint8_t Ar = A >> 16, Ag = A >> 8, Ab = A >> 0;
*out1++ = (full & 0x7c00); uint8_t Br = B >> 16, Bg = B >> 8, Bb = B >> 0;
*out2++ = (half & 0x7c00); uint8_t Cr = C >> 16, Cg = C >> 8, Cb = C >> 0;
*out0++ = (full & 0x03e0); A = ((Br >> 0) << 16) + ((Bg >> 1) << 8) + ((Ab >> 1) << 0);
*out1++ = (full & 0x03e0); B = ((Br >> 1) << 16) + ((Bg >> 0) << 8) + ((Bb >> 1) << 0);
*out2++ = (half & 0x03e0); C = ((Cr >> 1) << 16) + ((Bg >> 1) << 8) + ((Bb >> 0) << 0);
*out0++ = (full & 0x001f); in++;
*out1++ = (full & 0x001f);
*out2++ = (half & 0x001f); *out0++ = A;
*out1++ = A;
*out2++ = (A & 0xf8f8f8) >> 1;
*out0++ = B;
*out1++ = B;
*out2++ = (B & 0xf8f8f8) >> 1;
*out0++ = C;
*out1++ = C;
*out2++ = (C & 0xf8f8f8) >> 1;
} }
} }
} }

View File

@ -4,7 +4,7 @@ using namespace nall;
extern "C" { extern "C" {
void filter_size(unsigned&, unsigned&); void filter_size(unsigned&, unsigned&);
void filter_render(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned); void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned);
}; };
dllexport void filter_size(unsigned &width, unsigned &height) { dllexport void filter_size(unsigned &width, unsigned &height) {
@ -13,20 +13,20 @@ dllexport void filter_size(unsigned &width, unsigned &height) {
} }
dllexport void filter_render( dllexport void filter_render(
uint16_t *output, unsigned outputPitch, uint32_t *output, unsigned outputPitch,
const uint16_t *input, unsigned inputPitch, const uint32_t *input, unsigned inputPitch,
unsigned width, unsigned height unsigned width, unsigned height
) { ) {
outputPitch >>= 1, inputPitch >>= 1; outputPitch >>= 2, inputPitch >>= 2;
#pragma omp parallel for #pragma omp parallel for
for(unsigned y = 0; y < height; y++) { for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * inputPitch; const uint32_t *in = input + y * inputPitch;
uint16_t *out0 = output + y * outputPitch * 2; uint32_t *out0 = output + y * outputPitch * 2;
uint16_t *out1 = output + y * outputPitch * 2 + outputPitch; uint32_t *out1 = output + y * outputPitch * 2 + outputPitch;
for(unsigned x = 0; x < width; x++) { for(unsigned x = 0; x < width; x++) {
uint16_t pixel = *in++; uint32_t pixel = *in++;
*out0++ = pixel; *out0++ = pixel;
*out0++ = pixel; *out0++ = pixel;
*out1++ = pixel; *out1++ = pixel;

View File

@ -4,7 +4,7 @@ using namespace nall;
extern "C" { extern "C" {
void filter_size(unsigned&, unsigned&); void filter_size(unsigned&, unsigned&);
void filter_render(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned); void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned);
}; };
dllexport void filter_size(unsigned &width, unsigned &height) { dllexport void filter_size(unsigned &width, unsigned &height) {
@ -13,27 +13,27 @@ dllexport void filter_size(unsigned &width, unsigned &height) {
} }
dllexport void filter_render( dllexport void filter_render(
uint16_t *output, unsigned outputPitch, uint32_t *output, unsigned outputPitch,
const uint16_t *input, unsigned inputPitch, const uint32_t *input, unsigned inputPitch,
unsigned width, unsigned height unsigned width, unsigned height
) { ) {
outputPitch >>= 1, inputPitch >>= 1; outputPitch >>= 2, inputPitch >>= 2;
#pragma omp parallel for #pragma omp parallel for
for(unsigned y = 0; y < height; y++) { for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * inputPitch; const uint32_t *in = input + y * inputPitch;
uint16_t *out0 = output + y * outputPitch * 2; uint32_t *out0 = output + y * outputPitch * 2;
uint16_t *out1 = output + y * outputPitch * 2 + outputPitch; uint32_t *out1 = output + y * outputPitch * 2 + outputPitch;
int prevline = (y == 0 ? 0 : inputPitch); int prevline = (y == 0 ? 0 : inputPitch);
int nextline = (y == height - 1 ? 0 : inputPitch); int nextline = (y == height - 1 ? 0 : inputPitch);
for(unsigned x = 0; x < width; x++) { for(unsigned x = 0; x < width; x++) {
uint16_t A = *(input - prevline); uint32_t A = *(in - prevline);
uint16_t B = (x > 0) ? *(input - 1) : *input; uint32_t B = (x > 0) ? *(in - 1) : *in;
uint16_t C = *input; uint32_t C = *in;
uint16_t D = (x < width - 1) ? *(input + 1) : *input; uint32_t D = (x < width - 1) ? *(in + 1) : *in;
uint16_t E = *(input++ + nextline); uint32_t E = *(in++ + nextline);
if(A != E && B != D) { if(A != E && B != D) {
*out0++ = (A == B ? A : C); *out0++ = (A == B ? A : C);

View File

@ -4,7 +4,7 @@ using namespace nall;
extern "C" { extern "C" {
void filter_size(unsigned&, unsigned&); void filter_size(unsigned&, unsigned&);
void filter_render(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned); void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned);
}; };
dllexport void filter_size(unsigned &width, unsigned &height) { dllexport void filter_size(unsigned &width, unsigned &height) {
@ -12,17 +12,17 @@ dllexport void filter_size(unsigned &width, unsigned &height) {
} }
dllexport void filter_render( dllexport void filter_render(
uint16_t *output, unsigned outputPitch, uint32_t *output, unsigned outputPitch,
const uint16_t *input, unsigned inputPitch, const uint32_t *input, unsigned inputPitch,
unsigned width, unsigned height unsigned width, unsigned height
) { ) {
outputPitch >>= 1, inputPitch >>= 1; outputPitch >>= 2, inputPitch >>= 2;
#pragma omp parallel for #pragma omp parallel for
for(unsigned y = 0; y < height; y++) { for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * inputPitch; const uint32_t *in = input + y * inputPitch;
uint16_t *out0 = output + y * outputPitch * 2; uint32_t *out0 = output + y * outputPitch * 2;
uint16_t *out1 = output + y * outputPitch * 2 + outputPitch; uint32_t *out1 = output + y * outputPitch * 2 + outputPitch;
for(unsigned x = 0; x < width; x++) { for(unsigned x = 0; x < width; x++) {
*out0++ = *in++; *out0++ = *in++;

View File

@ -4,7 +4,7 @@ using namespace nall;
extern "C" { extern "C" {
void filter_size(unsigned&, unsigned&); void filter_size(unsigned&, unsigned&);
void filter_render(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned); void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned);
}; };
dllexport void filter_size(unsigned &width, unsigned &height) { dllexport void filter_size(unsigned &width, unsigned &height) {
@ -12,21 +12,21 @@ dllexport void filter_size(unsigned &width, unsigned &height) {
} }
dllexport void filter_render( dllexport void filter_render(
uint16_t *output, unsigned outputPitch, uint32_t *output, unsigned outputPitch,
const uint16_t *input, unsigned inputPitch, const uint32_t *input, unsigned inputPitch,
unsigned width, unsigned height unsigned width, unsigned height
) { ) {
outputPitch >>= 1, inputPitch >>= 1; outputPitch >>= 2, inputPitch >>= 2;
#pragma omp parallel for #pragma omp parallel for
for(unsigned y = 0; y < height; y++) { for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * inputPitch; const uint32_t *in = input + y * inputPitch;
uint16_t *out0 = output + y * outputPitch * 2; uint32_t *out0 = output + y * outputPitch * 2;
uint16_t *out1 = output + y * outputPitch * 2 + outputPitch; uint32_t *out1 = output + y * outputPitch * 2 + outputPitch;
for(unsigned x = 0; x < width; x++) { for(unsigned x = 0; x < width; x++) {
*out0++ = *in; *out0++ = *in;
*out1++ = (*in++ & 0x7bde) >> 1; *out1++ = (*in++ & 0xf8f8f8) >> 1;
} }
} }
} }