From 7e3def34f504035921d714bc625eb46dcff43f9f Mon Sep 17 00:00:00 2001 From: Souryo Date: Mon, 23 May 2016 17:02:24 -0400 Subject: [PATCH] Video Filters: xBRZ, HQX, Scale2x, 2xSai, Super2xSai, SuperEagle support --- Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 + Core/DefaultVideoFilter.h | 2 +- Core/EmulationSettings.h | 14 + Core/ScaleFilter.cpp | 63 + Core/ScaleFilter.h | 29 + Core/VideoDecoder.cpp | 16 + GUI.NET/Dependencies/resources.en.xml | 14 + GUI.NET/Dependencies/resources.fr.xml | 14 + GUI.NET/Dependencies/resources.ja.xml | 14 + GUI.NET/Forms/frmMain.Designer.cs | 370 +- GUI.NET/Forms/frmMain.cs | 99 +- GUI.NET/Forms/frmMain.resx | 4 +- GUI.NET/InteropEmu.cs | 14 + Utilities/HQX/common.h | 142 + Utilities/HQX/hq2x.cpp | 2811 +++++++++++++ Utilities/HQX/hq3x.cpp | 3789 +++++++++++++++++ Utilities/HQX/hq4x.cpp | 5235 ++++++++++++++++++++++++ Utilities/HQX/hqx.h | 55 + Utilities/HQX/init.cpp | 40 + Utilities/KreedSaiEagle/2xSai.cpp | 164 + Utilities/KreedSaiEagle/SaiEagle.h | 7 + Utilities/KreedSaiEagle/Super2xSai.cpp | 138 + Utilities/KreedSaiEagle/SuperEagle.cpp | 149 + Utilities/Scale2x/scale2x.cpp | 662 +++ Utilities/Scale2x/scale2x.h | 64 + Utilities/Scale2x/scale3x.cpp | 697 ++++ Utilities/Scale2x/scale3x.h | 29 + Utilities/Scale2x/scalebit.cpp | 505 +++ Utilities/Scale2x/scalebit.h | 33 + Utilities/Utilities.vcxproj | 19 + Utilities/Utilities.vcxproj.filters | 69 + Utilities/xBRZ/config.h | 33 + Utilities/xBRZ/xbrz.cpp | 1215 ++++++ Utilities/xBRZ/xbrz.h | 94 + 35 files changed, 16503 insertions(+), 108 deletions(-) create mode 100644 Core/ScaleFilter.cpp create mode 100644 Core/ScaleFilter.h create mode 100644 Utilities/HQX/common.h create mode 100644 Utilities/HQX/hq2x.cpp create mode 100644 Utilities/HQX/hq3x.cpp create mode 100644 Utilities/HQX/hq4x.cpp create mode 100644 Utilities/HQX/hqx.h create mode 100644 Utilities/HQX/init.cpp create mode 100644 Utilities/KreedSaiEagle/2xSai.cpp create mode 100644 Utilities/KreedSaiEagle/SaiEagle.h create mode 100644 Utilities/KreedSaiEagle/Super2xSai.cpp create mode 100644 Utilities/KreedSaiEagle/SuperEagle.cpp create mode 100644 Utilities/Scale2x/scale2x.cpp create mode 100644 Utilities/Scale2x/scale2x.h create mode 100644 Utilities/Scale2x/scale3x.cpp create mode 100644 Utilities/Scale2x/scale3x.h create mode 100644 Utilities/Scale2x/scalebit.cpp create mode 100644 Utilities/Scale2x/scalebit.h create mode 100644 Utilities/xBRZ/config.h create mode 100644 Utilities/xBRZ/xbrz.cpp create mode 100644 Utilities/xBRZ/xbrz.h diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 8a245eda..c3b9fb09 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -534,6 +534,7 @@ + @@ -592,6 +593,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 031d671a..322daa20 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -587,6 +587,9 @@ Nes\Mappers\Unnamed + + VideoDecoder + @@ -730,5 +733,8 @@ Nes\Mappers + + VideoDecoder + \ No newline at end of file diff --git a/Core/DefaultVideoFilter.h b/Core/DefaultVideoFilter.h index 5454d2f8..b44fec69 100644 --- a/Core/DefaultVideoFilter.h +++ b/Core/DefaultVideoFilter.h @@ -5,7 +5,7 @@ class DefaultVideoFilter : public BaseVideoFilter { -private: +protected: uint32_t ProcessIntensifyBits(uint16_t ppuPixel); public: diff --git a/Core/EmulationSettings.h b/Core/EmulationSettings.h index 8996747d..3ea87a89 100644 --- a/Core/EmulationSettings.h +++ b/Core/EmulationSettings.h @@ -56,6 +56,20 @@ enum class VideoFilterType { None = 0, NTSC = 1, + xBRZ2x = 2, + xBRZ3x = 3, + xBRZ4x = 4, + xBRZ5x = 5, + xBRZ6x = 6, + HQ2x = 7, + HQ3x = 8, + HQ4x = 9, + Scale2x = 10, + Scale3x = 11, + Scale4x = 12, + _2xSai = 13, + Super2xSai = 14, + SuperEagle = 15, HdPack = 999 }; diff --git a/Core/ScaleFilter.cpp b/Core/ScaleFilter.cpp new file mode 100644 index 00000000..d06552c0 --- /dev/null +++ b/Core/ScaleFilter.cpp @@ -0,0 +1,63 @@ +#include "stdafx.h" +#include "PPU.h" +#include "ScaleFilter.h" +#include "../Utilities/xBRZ/xbrz.h" +#include "../Utilities/HQX/hqx.h" +#include "../Utilities/Scale2x/scalebit.h" +#include "../Utilities/KreedSaiEagle/SaiEagle.h" + +ScaleFilter::ScaleFilter(ScaleFilterType scaleFilterType, uint32_t scale) +{ + _scaleFilterType = scaleFilterType; + _filterScale = scale; + _decodedPpuBuffer = new uint32_t[PPU::PixelCount]; + + if(_scaleFilterType == ScaleFilterType::HQX) { + hqxInit(); + } +} + +ScaleFilter::~ScaleFilter() +{ + delete[] _decodedPpuBuffer; +} + +FrameInfo ScaleFilter::GetFrameInfo() +{ + OverscanDimensions overscan = GetOverscan(); + return{ overscan.GetScreenWidth()*_filterScale, overscan.GetScreenHeight()*_filterScale, 4 }; +} + +void ScaleFilter::ApplyFilter(uint16_t *ppuOutputBuffer) +{ + OverscanDimensions overscan = EmulationSettings::GetOverscanDimensions(); + + uint32_t* outputBuffer = _decodedPpuBuffer; + for(uint32_t i = overscan.Top, iMax = 240 - overscan.Bottom; i < iMax; i++) { + for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) { + *outputBuffer = ProcessIntensifyBits(ppuOutputBuffer[i * 256 + j]); + outputBuffer++; + } + } + + uint32_t height = overscan.GetScreenHeight(); + uint32_t width = overscan.GetScreenWidth(); + + if(_scaleFilterType == ScaleFilterType::xBRZ) { + xbrz::scale(_filterScale, _decodedPpuBuffer, (uint32_t*)GetOutputBuffer(), width, height, xbrz::ColorFormat::ARGB); + } else if(_scaleFilterType == ScaleFilterType::HQX) { + switch(_filterScale) { + case 2: hq2x_32(_decodedPpuBuffer, (uint32_t*)GetOutputBuffer(), width, height); break; + case 3: hq3x_32(_decodedPpuBuffer, (uint32_t*)GetOutputBuffer(), width, height); break; + case 4: hq4x_32(_decodedPpuBuffer, (uint32_t*)GetOutputBuffer(), width, height); break; + } + } else if(_scaleFilterType == ScaleFilterType::Scale2x) { + scale(_filterScale, GetOutputBuffer(), width*sizeof(uint32_t)*_filterScale, _decodedPpuBuffer, width*sizeof(uint32_t), 4, width, height); + } else if(_scaleFilterType == ScaleFilterType::_2xSai) { + twoxsai_generic_xrgb8888(width, height, _decodedPpuBuffer, width, (uint32_t*)GetOutputBuffer(), width * _filterScale); + } else if(_scaleFilterType == ScaleFilterType::Super2xSai) { + supertwoxsai_generic_xrgb8888(width, height, _decodedPpuBuffer, width, (uint32_t*)GetOutputBuffer(), width * _filterScale); + } else if(_scaleFilterType == ScaleFilterType::SuperEagle) { + supereagle_generic_xrgb8888(width, height, _decodedPpuBuffer, width, (uint32_t*)GetOutputBuffer(), width * _filterScale); + } +} \ No newline at end of file diff --git a/Core/ScaleFilter.h b/Core/ScaleFilter.h new file mode 100644 index 00000000..81faea03 --- /dev/null +++ b/Core/ScaleFilter.h @@ -0,0 +1,29 @@ +#pragma once + +#include "stdafx.h" +#include "DefaultVideoFilter.h" + +enum class ScaleFilterType +{ + xBRZ, + HQX, + Scale2x, + _2xSai, + Super2xSai, + SuperEagle, +}; + +class ScaleFilter : public DefaultVideoFilter +{ +private: + uint32_t *_decodedPpuBuffer; + uint32_t _filterScale; + ScaleFilterType _scaleFilterType; + +public: + ScaleFilter(ScaleFilterType scaleFilterType, uint32_t scale); + virtual ~ScaleFilter(); + + void ApplyFilter(uint16_t *ppuOutputBuffer); + FrameInfo GetFrameInfo(); +}; \ No newline at end of file diff --git a/Core/VideoDecoder.cpp b/Core/VideoDecoder.cpp index 726fc46b..4dc23fed 100644 --- a/Core/VideoDecoder.cpp +++ b/Core/VideoDecoder.cpp @@ -5,6 +5,7 @@ #include "DefaultVideoFilter.h" #include "NtscFilter.h" #include "HdVideoFilter.h" +#include "ScaleFilter.h" #include "VideoRenderer.h" unique_ptr VideoDecoder::Instance; @@ -52,6 +53,21 @@ void VideoDecoder::UpdateVideoFilter() switch(_videoFilterType) { case VideoFilterType::None: _videoFilter.reset(new DefaultVideoFilter()); break; case VideoFilterType::NTSC: _videoFilter.reset(new NtscFilter()); break; + case VideoFilterType::xBRZ2x: _videoFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 2)); break; + case VideoFilterType::xBRZ3x: _videoFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 3)); break; + case VideoFilterType::xBRZ4x: _videoFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 4)); break; + case VideoFilterType::xBRZ5x: _videoFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 5)); break; + case VideoFilterType::xBRZ6x: _videoFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 6)); break; + case VideoFilterType::HQ2x: _videoFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 2)); break; + case VideoFilterType::HQ3x: _videoFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 3)); break; + case VideoFilterType::HQ4x: _videoFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 4)); break; + case VideoFilterType::Scale2x: _videoFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 2)); break; + case VideoFilterType::Scale3x: _videoFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 3)); break; + case VideoFilterType::Scale4x: _videoFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 4)); break; + case VideoFilterType::_2xSai: _videoFilter.reset(new ScaleFilter(ScaleFilterType::_2xSai, 2)); break; + case VideoFilterType::Super2xSai: _videoFilter.reset(new ScaleFilter(ScaleFilterType::Super2xSai, 2)); break; + case VideoFilterType::SuperEagle: _videoFilter.reset(new ScaleFilter(ScaleFilterType::SuperEagle, 2)); break; + case VideoFilterType::HdPack: _videoFilter.reset(new HdVideoFilter()); break; } } diff --git a/GUI.NET/Dependencies/resources.en.xml b/GUI.NET/Dependencies/resources.en.xml index 2a1434cb..f237baf9 100644 --- a/GUI.NET/Dependencies/resources.en.xml +++ b/GUI.NET/Dependencies/resources.en.xml @@ -55,6 +55,20 @@ None NTSC + xBRZ 2x + xBRZ 3x + xBRZ 4x + xBRZ 5x + xBRZ 6x + HQ 2x + HQ 3x + HQ 4x + Scale 2x + Scale 3x + Scale 4x + 2xSai + Super2xSai + SuperEagle NES diff --git a/GUI.NET/Dependencies/resources.fr.xml b/GUI.NET/Dependencies/resources.fr.xml index 419f03fb..9ef5ee1d 100644 --- a/GUI.NET/Dependencies/resources.fr.xml +++ b/GUI.NET/Dependencies/resources.fr.xml @@ -327,6 +327,20 @@ Aucun NTSC + xBRZ 2x + xBRZ 3x + xBRZ 4x + xBRZ 5x + xBRZ 6x + HQ 2x + HQ 3x + HQ 4x + Scale2x + Scale3x + Scale4x + 2xSai + Super2xSai + SuperEagle NES diff --git a/GUI.NET/Dependencies/resources.ja.xml b/GUI.NET/Dependencies/resources.ja.xml index 38508320..4e18def1 100644 --- a/GUI.NET/Dependencies/resources.ja.xml +++ b/GUI.NET/Dependencies/resources.ja.xml @@ -320,6 +320,20 @@ なし NTSC + xBRZ 2x + xBRZ 3x + xBRZ 4x + xBRZ 5x + xBRZ 6x + HQ 2x + HQ 3x + HQ 4x + Scale 2x + Scale 3x + Scale 4x + 2xSai + Super2xSai + SuperEagle NES diff --git a/GUI.NET/Forms/frmMain.Designer.cs b/GUI.NET/Forms/frmMain.Designer.cs index 7ce75ce5..8d622fde 100644 --- a/GUI.NET/Forms/frmMain.Designer.cs +++ b/GUI.NET/Forms/frmMain.Designer.cs @@ -81,6 +81,20 @@ namespace Mesen.GUI.Forms this.mnuVideoFilter = new System.Windows.Forms.ToolStripMenuItem(); this.mnuNoneFilter = new System.Windows.Forms.ToolStripMenuItem(); this.mnuNtscFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem15 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuXBRZ2xFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuXBRZ3xFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuXBRZ4xFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuXBRZ5xFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuXBRZ6xFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem16 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuHQ2xFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuHQ3xFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuHQ4xFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem17 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuScale2xFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuScale3xFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuScale4xFilter = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem10 = new System.Windows.Forms.ToolStripSeparator(); this.mnuAudioConfig = new System.Windows.Forms.ToolStripMenuItem(); this.mnuInput = new System.Windows.Forms.ToolStripMenuItem(); @@ -130,6 +144,10 @@ namespace Mesen.GUI.Forms this.mnuCheckForUpdates = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator(); this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem18 = new System.Windows.Forms.ToolStripSeparator(); + this.mnu2xSaiFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuSuper2xSaiFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuSuperEagleFilter = new System.Windows.Forms.ToolStripMenuItem(); this.panelRenderer.SuspendLayout(); this.menuStrip.SuspendLayout(); this.SuspendLayout(); @@ -143,9 +161,9 @@ namespace Mesen.GUI.Forms this.panelRenderer.BackColor = System.Drawing.Color.Black; this.panelRenderer.Controls.Add(this.ctrlRenderer); this.panelRenderer.Dock = System.Windows.Forms.DockStyle.Fill; - this.panelRenderer.Location = new System.Drawing.Point(0, 26); + this.panelRenderer.Location = new System.Drawing.Point(0, 24); this.panelRenderer.Name = "panelRenderer"; - this.panelRenderer.Size = new System.Drawing.Size(304, 216); + this.panelRenderer.Size = new System.Drawing.Size(304, 218); this.panelRenderer.TabIndex = 2; this.panelRenderer.Click += new System.EventHandler(this.panelRenderer_Click); // @@ -169,7 +187,7 @@ namespace Mesen.GUI.Forms this.mnuHelp}); this.menuStrip.Location = new System.Drawing.Point(0, 0); this.menuStrip.Name = "menuStrip"; - this.menuStrip.Size = new System.Drawing.Size(304, 26); + this.menuStrip.Size = new System.Drawing.Size(304, 24); this.menuStrip.TabIndex = 0; this.menuStrip.Text = "menuStrip1"; this.menuStrip.VisibleChanged += new System.EventHandler(this.menuStrip_VisibleChanged); @@ -187,7 +205,7 @@ namespace Mesen.GUI.Forms this.mnuExit}); this.mnuFile.Name = "mnuFile"; this.mnuFile.ShortcutKeyDisplayString = ""; - this.mnuFile.Size = new System.Drawing.Size(40, 22); + this.mnuFile.Size = new System.Drawing.Size(37, 20); this.mnuFile.Text = "File"; // // mnuOpen @@ -195,50 +213,50 @@ namespace Mesen.GUI.Forms this.mnuOpen.Image = global::Mesen.GUI.Properties.Resources.FolderOpen; this.mnuOpen.Name = "mnuOpen"; this.mnuOpen.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); - this.mnuOpen.Size = new System.Drawing.Size(154, 22); + this.mnuOpen.Size = new System.Drawing.Size(146, 22); this.mnuOpen.Text = "Open"; this.mnuOpen.Click += new System.EventHandler(this.mnuOpen_Click); // // toolStripMenuItem4 // this.toolStripMenuItem4.Name = "toolStripMenuItem4"; - this.toolStripMenuItem4.Size = new System.Drawing.Size(151, 6); + this.toolStripMenuItem4.Size = new System.Drawing.Size(143, 6); // // mnuSaveState // this.mnuSaveState.Name = "mnuSaveState"; - this.mnuSaveState.Size = new System.Drawing.Size(154, 22); + this.mnuSaveState.Size = new System.Drawing.Size(146, 22); this.mnuSaveState.Text = "Save State"; this.mnuSaveState.DropDownOpening += new System.EventHandler(this.mnuSaveState_DropDownOpening); // // mnuLoadState // this.mnuLoadState.Name = "mnuLoadState"; - this.mnuLoadState.Size = new System.Drawing.Size(154, 22); + this.mnuLoadState.Size = new System.Drawing.Size(146, 22); this.mnuLoadState.Text = "Load State"; this.mnuLoadState.DropDownOpening += new System.EventHandler(this.mnuLoadState_DropDownOpening); // // toolStripMenuItem7 // this.toolStripMenuItem7.Name = "toolStripMenuItem7"; - this.toolStripMenuItem7.Size = new System.Drawing.Size(151, 6); + this.toolStripMenuItem7.Size = new System.Drawing.Size(143, 6); // // mnuRecentFiles // this.mnuRecentFiles.Name = "mnuRecentFiles"; - this.mnuRecentFiles.Size = new System.Drawing.Size(154, 22); + this.mnuRecentFiles.Size = new System.Drawing.Size(146, 22); this.mnuRecentFiles.Text = "Recent Files"; // // toolStripMenuItem6 // this.toolStripMenuItem6.Name = "toolStripMenuItem6"; - this.toolStripMenuItem6.Size = new System.Drawing.Size(151, 6); + this.toolStripMenuItem6.Size = new System.Drawing.Size(143, 6); // // mnuExit // this.mnuExit.Image = global::Mesen.GUI.Properties.Resources.Exit; this.mnuExit.Name = "mnuExit"; - this.mnuExit.Size = new System.Drawing.Size(154, 22); + this.mnuExit.Size = new System.Drawing.Size(146, 22); this.mnuExit.Text = "Exit"; this.mnuExit.Click += new System.EventHandler(this.mnuExit_Click); // @@ -257,7 +275,7 @@ namespace Mesen.GUI.Forms this.mnuInsertCoin1, this.mnuInsertCoin2}); this.mnuGame.Name = "mnuGame"; - this.mnuGame.Size = new System.Drawing.Size(55, 22); + this.mnuGame.Size = new System.Drawing.Size(50, 20); this.mnuGame.Text = "Game"; // // mnuPause @@ -266,7 +284,7 @@ namespace Mesen.GUI.Forms this.mnuPause.Image = global::Mesen.GUI.Properties.Resources.Pause; this.mnuPause.Name = "mnuPause"; this.mnuPause.ShortcutKeyDisplayString = "Esc"; - this.mnuPause.Size = new System.Drawing.Size(220, 22); + this.mnuPause.Size = new System.Drawing.Size(200, 22); this.mnuPause.Text = "Pause"; this.mnuPause.Click += new System.EventHandler(this.mnuPause_Click); // @@ -275,7 +293,7 @@ namespace Mesen.GUI.Forms this.mnuReset.Enabled = false; this.mnuReset.Image = global::Mesen.GUI.Properties.Resources.Reset; this.mnuReset.Name = "mnuReset"; - this.mnuReset.Size = new System.Drawing.Size(220, 22); + this.mnuReset.Size = new System.Drawing.Size(200, 22); this.mnuReset.Text = "Reset"; this.mnuReset.Click += new System.EventHandler(this.mnuReset_Click); // @@ -284,20 +302,20 @@ namespace Mesen.GUI.Forms this.mnuStop.Enabled = false; this.mnuStop.Image = global::Mesen.GUI.Properties.Resources.Stop; this.mnuStop.Name = "mnuStop"; - this.mnuStop.Size = new System.Drawing.Size(220, 22); + this.mnuStop.Size = new System.Drawing.Size(200, 22); this.mnuStop.Text = "Stop"; this.mnuStop.Click += new System.EventHandler(this.mnuStop_Click); // // sepFdsDisk // this.sepFdsDisk.Name = "sepFdsDisk"; - this.sepFdsDisk.Size = new System.Drawing.Size(217, 6); + this.sepFdsDisk.Size = new System.Drawing.Size(197, 6); // // mnuSwitchDiskSide // this.mnuSwitchDiskSide.Name = "mnuSwitchDiskSide"; this.mnuSwitchDiskSide.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.B))); - this.mnuSwitchDiskSide.Size = new System.Drawing.Size(220, 22); + this.mnuSwitchDiskSide.Size = new System.Drawing.Size(200, 22); this.mnuSwitchDiskSide.Text = "Switch Disk Side"; this.mnuSwitchDiskSide.Click += new System.EventHandler(this.mnuSwitchDiskSide_Click); // @@ -305,28 +323,28 @@ namespace Mesen.GUI.Forms // this.mnuSelectDisk.Image = global::Mesen.GUI.Properties.Resources.Floppy; this.mnuSelectDisk.Name = "mnuSelectDisk"; - this.mnuSelectDisk.Size = new System.Drawing.Size(220, 22); + this.mnuSelectDisk.Size = new System.Drawing.Size(200, 22); this.mnuSelectDisk.Text = "Select Disk"; // // mnuEjectDisk // this.mnuEjectDisk.Image = global::Mesen.GUI.Properties.Resources.Eject; this.mnuEjectDisk.Name = "mnuEjectDisk"; - this.mnuEjectDisk.Size = new System.Drawing.Size(220, 22); + this.mnuEjectDisk.Size = new System.Drawing.Size(200, 22); this.mnuEjectDisk.Text = "Eject Disk"; this.mnuEjectDisk.Click += new System.EventHandler(this.mnuEjectDisk_Click); // // sepVsSystem // this.sepVsSystem.Name = "sepVsSystem"; - this.sepVsSystem.Size = new System.Drawing.Size(217, 6); + this.sepVsSystem.Size = new System.Drawing.Size(197, 6); this.sepVsSystem.Visible = false; // // mnuVsGameConfig // this.mnuVsGameConfig.Image = global::Mesen.GUI.Properties.Resources.DipSwitches; this.mnuVsGameConfig.Name = "mnuVsGameConfig"; - this.mnuVsGameConfig.Size = new System.Drawing.Size(220, 22); + this.mnuVsGameConfig.Size = new System.Drawing.Size(200, 22); this.mnuVsGameConfig.Text = "Game Configuration"; this.mnuVsGameConfig.Click += new System.EventHandler(this.mnuVsGameConfig_Click); // @@ -334,7 +352,7 @@ namespace Mesen.GUI.Forms // this.mnuInsertCoin1.Image = global::Mesen.GUI.Properties.Resources.coins; this.mnuInsertCoin1.Name = "mnuInsertCoin1"; - this.mnuInsertCoin1.Size = new System.Drawing.Size(220, 22); + this.mnuInsertCoin1.Size = new System.Drawing.Size(200, 22); this.mnuInsertCoin1.Text = "Insert Coin (1)"; this.mnuInsertCoin1.Visible = false; this.mnuInsertCoin1.Click += new System.EventHandler(this.mnuInsertCoin1_Click); @@ -343,7 +361,7 @@ namespace Mesen.GUI.Forms // this.mnuInsertCoin2.Image = global::Mesen.GUI.Properties.Resources.coins; this.mnuInsertCoin2.Name = "mnuInsertCoin2"; - this.mnuInsertCoin2.Size = new System.Drawing.Size(220, 22); + this.mnuInsertCoin2.Size = new System.Drawing.Size(200, 22); this.mnuInsertCoin2.Text = "Insert Coin (2)"; this.mnuInsertCoin2.Visible = false; this.mnuInsertCoin2.Click += new System.EventHandler(this.mnuInsertCoin2_Click); @@ -362,7 +380,7 @@ namespace Mesen.GUI.Forms this.toolStripMenuItem11, this.mnuPreferences}); this.mnuOptions.Name = "mnuOptions"; - this.mnuOptions.Size = new System.Drawing.Size(64, 22); + this.mnuOptions.Size = new System.Drawing.Size(61, 20); this.mnuOptions.Text = "Options"; // // mnuEmulationSpeed @@ -382,26 +400,26 @@ namespace Mesen.GUI.Forms this.mnuShowFPS}); this.mnuEmulationSpeed.Image = global::Mesen.GUI.Properties.Resources.Speed; this.mnuEmulationSpeed.Name = "mnuEmulationSpeed"; - this.mnuEmulationSpeed.Size = new System.Drawing.Size(144, 22); + this.mnuEmulationSpeed.Size = new System.Drawing.Size(152, 22); this.mnuEmulationSpeed.Text = "Speed"; // // mnuEmuSpeedNormal // this.mnuEmuSpeedNormal.Name = "mnuEmuSpeedNormal"; - this.mnuEmuSpeedNormal.Size = new System.Drawing.Size(196, 22); + this.mnuEmuSpeedNormal.Size = new System.Drawing.Size(182, 22); this.mnuEmuSpeedNormal.Text = "Normal (100%)"; this.mnuEmuSpeedNormal.Click += new System.EventHandler(this.mnuEmulationSpeedOption_Click); // // toolStripMenuItem8 // this.toolStripMenuItem8.Name = "toolStripMenuItem8"; - this.toolStripMenuItem8.Size = new System.Drawing.Size(193, 6); + this.toolStripMenuItem8.Size = new System.Drawing.Size(179, 6); // // mnuIncreaseSpeed // this.mnuIncreaseSpeed.Name = "mnuIncreaseSpeed"; this.mnuIncreaseSpeed.ShortcutKeyDisplayString = "="; - this.mnuIncreaseSpeed.Size = new System.Drawing.Size(196, 22); + this.mnuIncreaseSpeed.Size = new System.Drawing.Size(182, 22); this.mnuIncreaseSpeed.Text = "Increase Speed"; this.mnuIncreaseSpeed.Click += new System.EventHandler(this.mnuIncreaseSpeed_Click); // @@ -409,7 +427,7 @@ namespace Mesen.GUI.Forms // this.mnuDecreaseSpeed.Name = "mnuDecreaseSpeed"; this.mnuDecreaseSpeed.ShortcutKeyDisplayString = "-"; - this.mnuDecreaseSpeed.Size = new System.Drawing.Size(196, 22); + this.mnuDecreaseSpeed.Size = new System.Drawing.Size(182, 22); this.mnuDecreaseSpeed.Text = "Decrease Speed"; this.mnuDecreaseSpeed.Click += new System.EventHandler(this.mnuDecreaseSpeed_Click); // @@ -417,19 +435,19 @@ namespace Mesen.GUI.Forms // this.mnuEmuSpeedMaximumSpeed.Name = "mnuEmuSpeedMaximumSpeed"; this.mnuEmuSpeedMaximumSpeed.ShortcutKeys = System.Windows.Forms.Keys.F9; - this.mnuEmuSpeedMaximumSpeed.Size = new System.Drawing.Size(196, 22); + this.mnuEmuSpeedMaximumSpeed.Size = new System.Drawing.Size(182, 22); this.mnuEmuSpeedMaximumSpeed.Text = "Maximum Speed"; this.mnuEmuSpeedMaximumSpeed.Click += new System.EventHandler(this.mnuEmuSpeedMaximumSpeed_Click); // // toolStripMenuItem9 // this.toolStripMenuItem9.Name = "toolStripMenuItem9"; - this.toolStripMenuItem9.Size = new System.Drawing.Size(193, 6); + this.toolStripMenuItem9.Size = new System.Drawing.Size(179, 6); // // mnuEmuSpeedTriple // this.mnuEmuSpeedTriple.Name = "mnuEmuSpeedTriple"; - this.mnuEmuSpeedTriple.Size = new System.Drawing.Size(196, 22); + this.mnuEmuSpeedTriple.Size = new System.Drawing.Size(182, 22); this.mnuEmuSpeedTriple.Tag = ""; this.mnuEmuSpeedTriple.Text = "Triple (300%)"; this.mnuEmuSpeedTriple.Click += new System.EventHandler(this.mnuEmulationSpeedOption_Click); @@ -437,35 +455,35 @@ namespace Mesen.GUI.Forms // mnuEmuSpeedDouble // this.mnuEmuSpeedDouble.Name = "mnuEmuSpeedDouble"; - this.mnuEmuSpeedDouble.Size = new System.Drawing.Size(196, 22); + this.mnuEmuSpeedDouble.Size = new System.Drawing.Size(182, 22); this.mnuEmuSpeedDouble.Text = "Double (200%)"; this.mnuEmuSpeedDouble.Click += new System.EventHandler(this.mnuEmulationSpeedOption_Click); // // mnuEmuSpeedHalf // this.mnuEmuSpeedHalf.Name = "mnuEmuSpeedHalf"; - this.mnuEmuSpeedHalf.Size = new System.Drawing.Size(196, 22); + this.mnuEmuSpeedHalf.Size = new System.Drawing.Size(182, 22); this.mnuEmuSpeedHalf.Text = "Half (50%)"; this.mnuEmuSpeedHalf.Click += new System.EventHandler(this.mnuEmulationSpeedOption_Click); // // mnuEmuSpeedQuarter // this.mnuEmuSpeedQuarter.Name = "mnuEmuSpeedQuarter"; - this.mnuEmuSpeedQuarter.Size = new System.Drawing.Size(196, 22); + this.mnuEmuSpeedQuarter.Size = new System.Drawing.Size(182, 22); this.mnuEmuSpeedQuarter.Text = "Quarter (25%)"; this.mnuEmuSpeedQuarter.Click += new System.EventHandler(this.mnuEmulationSpeedOption_Click); // // toolStripMenuItem14 // this.toolStripMenuItem14.Name = "toolStripMenuItem14"; - this.toolStripMenuItem14.Size = new System.Drawing.Size(193, 6); + this.toolStripMenuItem14.Size = new System.Drawing.Size(179, 6); // // mnuShowFPS // this.mnuShowFPS.CheckOnClick = true; this.mnuShowFPS.Name = "mnuShowFPS"; this.mnuShowFPS.ShortcutKeys = System.Windows.Forms.Keys.F10; - this.mnuShowFPS.Size = new System.Drawing.Size(196, 22); + this.mnuShowFPS.Size = new System.Drawing.Size(182, 22); this.mnuShowFPS.Text = "Show FPS"; this.mnuShowFPS.Click += new System.EventHandler(this.mnuShowFPS_Click); // @@ -481,13 +499,13 @@ namespace Mesen.GUI.Forms this.mnuFullscreen}); this.mnuVideoScale.Image = global::Mesen.GUI.Properties.Resources.Fullscreen; this.mnuVideoScale.Name = "mnuVideoScale"; - this.mnuVideoScale.Size = new System.Drawing.Size(144, 22); + this.mnuVideoScale.Size = new System.Drawing.Size(152, 22); this.mnuVideoScale.Text = "Video Size"; // // mnuScale1x // this.mnuScale1x.Name = "mnuScale1x"; - this.mnuScale1x.Size = new System.Drawing.Size(163, 22); + this.mnuScale1x.Size = new System.Drawing.Size(152, 22); this.mnuScale1x.Tag = "1"; this.mnuScale1x.Text = "1x"; this.mnuScale1x.Click += new System.EventHandler(this.mnuScale_Click); @@ -495,7 +513,7 @@ namespace Mesen.GUI.Forms // mnuScale2x // this.mnuScale2x.Name = "mnuScale2x"; - this.mnuScale2x.Size = new System.Drawing.Size(163, 22); + this.mnuScale2x.Size = new System.Drawing.Size(152, 22); this.mnuScale2x.Tag = "2"; this.mnuScale2x.Text = "2x"; this.mnuScale2x.Click += new System.EventHandler(this.mnuScale_Click); @@ -503,7 +521,7 @@ namespace Mesen.GUI.Forms // mnuScale3x // this.mnuScale3x.Name = "mnuScale3x"; - this.mnuScale3x.Size = new System.Drawing.Size(163, 22); + this.mnuScale3x.Size = new System.Drawing.Size(152, 22); this.mnuScale3x.Tag = "3"; this.mnuScale3x.Text = "3x"; this.mnuScale3x.Click += new System.EventHandler(this.mnuScale_Click); @@ -511,7 +529,7 @@ namespace Mesen.GUI.Forms // mnuScale4x // this.mnuScale4x.Name = "mnuScale4x"; - this.mnuScale4x.Size = new System.Drawing.Size(163, 22); + this.mnuScale4x.Size = new System.Drawing.Size(152, 22); this.mnuScale4x.Tag = "4"; this.mnuScale4x.Text = "4x"; this.mnuScale4x.Click += new System.EventHandler(this.mnuScale_Click); @@ -519,20 +537,20 @@ namespace Mesen.GUI.Forms // mnuScaleCustom // this.mnuScaleCustom.Name = "mnuScaleCustom"; - this.mnuScaleCustom.Size = new System.Drawing.Size(163, 22); + this.mnuScaleCustom.Size = new System.Drawing.Size(152, 22); this.mnuScaleCustom.Text = "Custom"; this.mnuScaleCustom.Click += new System.EventHandler(this.mnuScaleCustom_Click); // // toolStripMenuItem13 // this.toolStripMenuItem13.Name = "toolStripMenuItem13"; - this.toolStripMenuItem13.Size = new System.Drawing.Size(160, 6); + this.toolStripMenuItem13.Size = new System.Drawing.Size(149, 6); // // mnuFullscreen // this.mnuFullscreen.Name = "mnuFullscreen"; this.mnuFullscreen.ShortcutKeys = System.Windows.Forms.Keys.F11; - this.mnuFullscreen.Size = new System.Drawing.Size(163, 22); + this.mnuFullscreen.Size = new System.Drawing.Size(152, 22); this.mnuFullscreen.Text = "Fullscreen"; this.mnuFullscreen.Click += new System.EventHandler(this.mnuFullscreen_Click); // @@ -540,35 +558,145 @@ namespace Mesen.GUI.Forms // this.mnuVideoFilter.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.mnuNoneFilter, - this.mnuNtscFilter}); + this.mnuNtscFilter, + this.toolStripMenuItem15, + this.mnuXBRZ2xFilter, + this.mnuXBRZ3xFilter, + this.mnuXBRZ4xFilter, + this.mnuXBRZ5xFilter, + this.mnuXBRZ6xFilter, + this.toolStripMenuItem16, + this.mnuHQ2xFilter, + this.mnuHQ3xFilter, + this.mnuHQ4xFilter, + this.toolStripMenuItem17, + this.mnuScale2xFilter, + this.mnuScale3xFilter, + this.mnuScale4xFilter, + this.toolStripMenuItem18, + this.mnu2xSaiFilter, + this.mnuSuper2xSaiFilter, + this.mnuSuperEagleFilter}); this.mnuVideoFilter.Name = "mnuVideoFilter"; - this.mnuVideoFilter.Size = new System.Drawing.Size(144, 22); + this.mnuVideoFilter.Size = new System.Drawing.Size(152, 22); this.mnuVideoFilter.Text = "Video Filter"; // // mnuNoneFilter // this.mnuNoneFilter.Name = "mnuNoneFilter"; - this.mnuNoneFilter.Size = new System.Drawing.Size(109, 22); + this.mnuNoneFilter.Size = new System.Drawing.Size(152, 22); this.mnuNoneFilter.Text = "None"; this.mnuNoneFilter.Click += new System.EventHandler(this.mnuNoneFilter_Click); // // mnuNtscFilter // this.mnuNtscFilter.Name = "mnuNtscFilter"; - this.mnuNtscFilter.Size = new System.Drawing.Size(109, 22); + this.mnuNtscFilter.Size = new System.Drawing.Size(152, 22); this.mnuNtscFilter.Text = "NTSC"; this.mnuNtscFilter.Click += new System.EventHandler(this.mnuNtscFilter_Click); // + // toolStripMenuItem15 + // + this.toolStripMenuItem15.Name = "toolStripMenuItem15"; + this.toolStripMenuItem15.Size = new System.Drawing.Size(149, 6); + // + // mnuXBRZ2xFilter + // + this.mnuXBRZ2xFilter.Name = "mnuXBRZ2xFilter"; + this.mnuXBRZ2xFilter.Size = new System.Drawing.Size(152, 22); + this.mnuXBRZ2xFilter.Text = "xBRZ 2x"; + this.mnuXBRZ2xFilter.Click += new System.EventHandler(this.mnuXBRZ2xFilter_Click); + // + // mnuXBRZ3xFilter + // + this.mnuXBRZ3xFilter.Name = "mnuXBRZ3xFilter"; + this.mnuXBRZ3xFilter.Size = new System.Drawing.Size(152, 22); + this.mnuXBRZ3xFilter.Text = "xBRZ 3x"; + this.mnuXBRZ3xFilter.Click += new System.EventHandler(this.mnuXBRZ3xFilter_Click); + // + // mnuXBRZ4xFilter + // + this.mnuXBRZ4xFilter.Name = "mnuXBRZ4xFilter"; + this.mnuXBRZ4xFilter.Size = new System.Drawing.Size(152, 22); + this.mnuXBRZ4xFilter.Text = "xBRZ 4x"; + this.mnuXBRZ4xFilter.Click += new System.EventHandler(this.mnuXBRZ4xFilter_Click); + // + // mnuXBRZ5xFilter + // + this.mnuXBRZ5xFilter.Name = "mnuXBRZ5xFilter"; + this.mnuXBRZ5xFilter.Size = new System.Drawing.Size(152, 22); + this.mnuXBRZ5xFilter.Text = "xBRZ 5x"; + this.mnuXBRZ5xFilter.Click += new System.EventHandler(this.mnuXBRZ5xFilter_Click); + // + // mnuXBRZ6xFilter + // + this.mnuXBRZ6xFilter.Name = "mnuXBRZ6xFilter"; + this.mnuXBRZ6xFilter.Size = new System.Drawing.Size(152, 22); + this.mnuXBRZ6xFilter.Text = "xBRZ 6x"; + this.mnuXBRZ6xFilter.Click += new System.EventHandler(this.mnuXBRZ6xFilter_Click); + // + // toolStripMenuItem16 + // + this.toolStripMenuItem16.Name = "toolStripMenuItem16"; + this.toolStripMenuItem16.Size = new System.Drawing.Size(149, 6); + // + // mnuHQ2xFilter + // + this.mnuHQ2xFilter.Name = "mnuHQ2xFilter"; + this.mnuHQ2xFilter.Size = new System.Drawing.Size(152, 22); + this.mnuHQ2xFilter.Text = "HQ 2x"; + this.mnuHQ2xFilter.Click += new System.EventHandler(this.mnuHQ2xFilter_Click); + // + // mnuHQ3xFilter + // + this.mnuHQ3xFilter.Name = "mnuHQ3xFilter"; + this.mnuHQ3xFilter.Size = new System.Drawing.Size(152, 22); + this.mnuHQ3xFilter.Text = "HQ 3x"; + this.mnuHQ3xFilter.Click += new System.EventHandler(this.mnuHQ3xFilter_Click); + // + // mnuHQ4xFilter + // + this.mnuHQ4xFilter.Name = "mnuHQ4xFilter"; + this.mnuHQ4xFilter.Size = new System.Drawing.Size(152, 22); + this.mnuHQ4xFilter.Text = "HQ 4x"; + this.mnuHQ4xFilter.Click += new System.EventHandler(this.mnuHQ4xFilter_Click); + // + // toolStripMenuItem17 + // + this.toolStripMenuItem17.Name = "toolStripMenuItem17"; + this.toolStripMenuItem17.Size = new System.Drawing.Size(149, 6); + // + // mnuScale2xFilter + // + this.mnuScale2xFilter.Name = "mnuScale2xFilter"; + this.mnuScale2xFilter.Size = new System.Drawing.Size(152, 22); + this.mnuScale2xFilter.Text = "Scale2x"; + this.mnuScale2xFilter.Click += new System.EventHandler(this.mnuScale2xFilter_Click); + // + // mnuScale3xFilter + // + this.mnuScale3xFilter.Name = "mnuScale3xFilter"; + this.mnuScale3xFilter.Size = new System.Drawing.Size(152, 22); + this.mnuScale3xFilter.Text = "Scale3x"; + this.mnuScale3xFilter.Click += new System.EventHandler(this.mnuScale3xFilter_Click); + // + // mnuScale4xFilter + // + this.mnuScale4xFilter.Name = "mnuScale4xFilter"; + this.mnuScale4xFilter.Size = new System.Drawing.Size(152, 22); + this.mnuScale4xFilter.Text = "Scale4x"; + this.mnuScale4xFilter.Click += new System.EventHandler(this.mnuScale4xFilter_Click); + // // toolStripMenuItem10 // this.toolStripMenuItem10.Name = "toolStripMenuItem10"; - this.toolStripMenuItem10.Size = new System.Drawing.Size(141, 6); + this.toolStripMenuItem10.Size = new System.Drawing.Size(149, 6); // // mnuAudioConfig // this.mnuAudioConfig.Image = global::Mesen.GUI.Properties.Resources.Audio; this.mnuAudioConfig.Name = "mnuAudioConfig"; - this.mnuAudioConfig.Size = new System.Drawing.Size(144, 22); + this.mnuAudioConfig.Size = new System.Drawing.Size(152, 22); this.mnuAudioConfig.Text = "Audio"; this.mnuAudioConfig.Click += new System.EventHandler(this.mnuAudioConfig_Click); // @@ -576,7 +704,7 @@ namespace Mesen.GUI.Forms // this.mnuInput.Image = global::Mesen.GUI.Properties.Resources.Controller; this.mnuInput.Name = "mnuInput"; - this.mnuInput.Size = new System.Drawing.Size(144, 22); + this.mnuInput.Size = new System.Drawing.Size(152, 22); this.mnuInput.Text = "Input"; this.mnuInput.Click += new System.EventHandler(this.mnuInput_Click); // @@ -589,34 +717,34 @@ namespace Mesen.GUI.Forms this.mnuRegionDendy}); this.mnuRegion.Image = global::Mesen.GUI.Properties.Resources.Globe; this.mnuRegion.Name = "mnuRegion"; - this.mnuRegion.Size = new System.Drawing.Size(144, 22); + this.mnuRegion.Size = new System.Drawing.Size(152, 22); this.mnuRegion.Text = "Region"; // // mnuRegionAuto // this.mnuRegionAuto.Name = "mnuRegionAuto"; - this.mnuRegionAuto.Size = new System.Drawing.Size(113, 22); + this.mnuRegionAuto.Size = new System.Drawing.Size(108, 22); this.mnuRegionAuto.Text = "Auto"; this.mnuRegionAuto.Click += new System.EventHandler(this.mnuRegion_Click); // // mnuRegionNtsc // this.mnuRegionNtsc.Name = "mnuRegionNtsc"; - this.mnuRegionNtsc.Size = new System.Drawing.Size(113, 22); + this.mnuRegionNtsc.Size = new System.Drawing.Size(108, 22); this.mnuRegionNtsc.Text = "NTSC"; this.mnuRegionNtsc.Click += new System.EventHandler(this.mnuRegion_Click); // // mnuRegionPal // this.mnuRegionPal.Name = "mnuRegionPal"; - this.mnuRegionPal.Size = new System.Drawing.Size(113, 22); + this.mnuRegionPal.Size = new System.Drawing.Size(108, 22); this.mnuRegionPal.Text = "PAL"; this.mnuRegionPal.Click += new System.EventHandler(this.mnuRegion_Click); // // mnuRegionDendy // this.mnuRegionDendy.Name = "mnuRegionDendy"; - this.mnuRegionDendy.Size = new System.Drawing.Size(113, 22); + this.mnuRegionDendy.Size = new System.Drawing.Size(108, 22); this.mnuRegionDendy.Text = "Dendy"; this.mnuRegionDendy.Click += new System.EventHandler(this.mnuRegion_Click); // @@ -624,20 +752,20 @@ namespace Mesen.GUI.Forms // this.mnuVideoConfig.Image = global::Mesen.GUI.Properties.Resources.Video; this.mnuVideoConfig.Name = "mnuVideoConfig"; - this.mnuVideoConfig.Size = new System.Drawing.Size(144, 22); + this.mnuVideoConfig.Size = new System.Drawing.Size(152, 22); this.mnuVideoConfig.Text = "Video"; this.mnuVideoConfig.Click += new System.EventHandler(this.mnuVideoConfig_Click); // // toolStripMenuItem11 // this.toolStripMenuItem11.Name = "toolStripMenuItem11"; - this.toolStripMenuItem11.Size = new System.Drawing.Size(141, 6); + this.toolStripMenuItem11.Size = new System.Drawing.Size(149, 6); // // mnuPreferences // this.mnuPreferences.Image = global::Mesen.GUI.Properties.Resources.Cog; this.mnuPreferences.Name = "mnuPreferences"; - this.mnuPreferences.Size = new System.Drawing.Size(144, 22); + this.mnuPreferences.Size = new System.Drawing.Size(152, 22); this.mnuPreferences.Text = "Preferences"; this.mnuPreferences.Click += new System.EventHandler(this.mnuPreferences_Click); // @@ -653,7 +781,7 @@ namespace Mesen.GUI.Forms this.toolStripMenuItem1, this.mnuTakeScreenshot}); this.mnuTools.Name = "mnuTools"; - this.mnuTools.Size = new System.Drawing.Size(50, 22); + this.mnuTools.Size = new System.Drawing.Size(48, 20); this.mnuTools.Text = "Tools"; // // mnuNetPlay @@ -667,20 +795,20 @@ namespace Mesen.GUI.Forms this.mnuProfile}); this.mnuNetPlay.Image = global::Mesen.GUI.Properties.Resources.NetPlay; this.mnuNetPlay.Name = "mnuNetPlay"; - this.mnuNetPlay.Size = new System.Drawing.Size(202, 22); + this.mnuNetPlay.Size = new System.Drawing.Size(185, 22); this.mnuNetPlay.Text = "Net Play"; // // mnuStartServer // this.mnuStartServer.Name = "mnuStartServer"; - this.mnuStartServer.Size = new System.Drawing.Size(190, 22); + this.mnuStartServer.Size = new System.Drawing.Size(177, 22); this.mnuStartServer.Text = "Start Server"; this.mnuStartServer.Click += new System.EventHandler(this.mnuStartServer_Click); // // mnuConnect // this.mnuConnect.Name = "mnuConnect"; - this.mnuConnect.Size = new System.Drawing.Size(190, 22); + this.mnuConnect.Size = new System.Drawing.Size(177, 22); this.mnuConnect.Text = "Connect to Server"; this.mnuConnect.Click += new System.EventHandler(this.mnuConnect_Click); // @@ -694,66 +822,66 @@ namespace Mesen.GUI.Forms this.toolStripMenuItem3, this.mnuNetPlaySpectator}); this.mnuNetPlaySelectController.Name = "mnuNetPlaySelectController"; - this.mnuNetPlaySelectController.Size = new System.Drawing.Size(190, 22); + this.mnuNetPlaySelectController.Size = new System.Drawing.Size(177, 22); this.mnuNetPlaySelectController.Text = "Select Controller"; // // mnuNetPlayPlayer1 // this.mnuNetPlayPlayer1.Name = "mnuNetPlayPlayer1"; - this.mnuNetPlayPlayer1.Size = new System.Drawing.Size(133, 22); + this.mnuNetPlayPlayer1.Size = new System.Drawing.Size(124, 22); this.mnuNetPlayPlayer1.Text = "Player 1"; this.mnuNetPlayPlayer1.Click += new System.EventHandler(this.mnuNetPlayPlayer1_Click); // // mnuNetPlayPlayer2 // this.mnuNetPlayPlayer2.Name = "mnuNetPlayPlayer2"; - this.mnuNetPlayPlayer2.Size = new System.Drawing.Size(133, 22); + this.mnuNetPlayPlayer2.Size = new System.Drawing.Size(124, 22); this.mnuNetPlayPlayer2.Text = "Player 2"; this.mnuNetPlayPlayer2.Click += new System.EventHandler(this.mnuNetPlayPlayer2_Click); // // mnuNetPlayPlayer3 // this.mnuNetPlayPlayer3.Name = "mnuNetPlayPlayer3"; - this.mnuNetPlayPlayer3.Size = new System.Drawing.Size(133, 22); + this.mnuNetPlayPlayer3.Size = new System.Drawing.Size(124, 22); this.mnuNetPlayPlayer3.Text = "Player 3"; this.mnuNetPlayPlayer3.Click += new System.EventHandler(this.mnuNetPlayPlayer3_Click); // // mnuNetPlayPlayer4 // this.mnuNetPlayPlayer4.Name = "mnuNetPlayPlayer4"; - this.mnuNetPlayPlayer4.Size = new System.Drawing.Size(133, 22); + this.mnuNetPlayPlayer4.Size = new System.Drawing.Size(124, 22); this.mnuNetPlayPlayer4.Text = "Player 4"; this.mnuNetPlayPlayer4.Click += new System.EventHandler(this.mnuNetPlayPlayer4_Click); // // toolStripMenuItem3 // this.toolStripMenuItem3.Name = "toolStripMenuItem3"; - this.toolStripMenuItem3.Size = new System.Drawing.Size(130, 6); + this.toolStripMenuItem3.Size = new System.Drawing.Size(121, 6); // // mnuNetPlaySpectator // this.mnuNetPlaySpectator.Name = "mnuNetPlaySpectator"; - this.mnuNetPlaySpectator.Size = new System.Drawing.Size(133, 22); + this.mnuNetPlaySpectator.Size = new System.Drawing.Size(124, 22); this.mnuNetPlaySpectator.Text = "Spectator"; this.mnuNetPlaySpectator.Click += new System.EventHandler(this.mnuNetPlaySpectator_Click); // // toolStripMenuItem2 // this.toolStripMenuItem2.Name = "toolStripMenuItem2"; - this.toolStripMenuItem2.Size = new System.Drawing.Size(187, 6); + this.toolStripMenuItem2.Size = new System.Drawing.Size(174, 6); // // mnuFindServer // this.mnuFindServer.Enabled = false; this.mnuFindServer.Name = "mnuFindServer"; - this.mnuFindServer.Size = new System.Drawing.Size(190, 22); + this.mnuFindServer.Size = new System.Drawing.Size(177, 22); this.mnuFindServer.Text = "Find Public Server..."; this.mnuFindServer.Visible = false; // // mnuProfile // this.mnuProfile.Name = "mnuProfile"; - this.mnuProfile.Size = new System.Drawing.Size(190, 22); + this.mnuProfile.Size = new System.Drawing.Size(177, 22); this.mnuProfile.Text = "Configure Profile"; this.mnuProfile.Click += new System.EventHandler(this.mnuProfile_Click); // @@ -765,13 +893,13 @@ namespace Mesen.GUI.Forms this.mnuStopMovie}); this.mnuMovies.Image = global::Mesen.GUI.Properties.Resources.Movie; this.mnuMovies.Name = "mnuMovies"; - this.mnuMovies.Size = new System.Drawing.Size(202, 22); + this.mnuMovies.Size = new System.Drawing.Size(185, 22); this.mnuMovies.Text = "Movies"; // // mnuPlayMovie // this.mnuPlayMovie.Name = "mnuPlayMovie"; - this.mnuPlayMovie.Size = new System.Drawing.Size(160, 22); + this.mnuPlayMovie.Size = new System.Drawing.Size(149, 22); this.mnuPlayMovie.Text = "Play..."; this.mnuPlayMovie.Click += new System.EventHandler(this.mnuPlayMovie_Click); // @@ -781,41 +909,41 @@ namespace Mesen.GUI.Forms this.mnuRecordFromStart, this.mnuRecordFromNow}); this.mnuRecordFrom.Name = "mnuRecordFrom"; - this.mnuRecordFrom.Size = new System.Drawing.Size(160, 22); + this.mnuRecordFrom.Size = new System.Drawing.Size(149, 22); this.mnuRecordFrom.Text = "Record from..."; // // mnuRecordFromStart // this.mnuRecordFromStart.Name = "mnuRecordFromStart"; - this.mnuRecordFromStart.Size = new System.Drawing.Size(106, 22); + this.mnuRecordFromStart.Size = new System.Drawing.Size(99, 22); this.mnuRecordFromStart.Text = "Start"; this.mnuRecordFromStart.Click += new System.EventHandler(this.mnuRecordFromStart_Click); // // mnuRecordFromNow // this.mnuRecordFromNow.Name = "mnuRecordFromNow"; - this.mnuRecordFromNow.Size = new System.Drawing.Size(106, 22); + this.mnuRecordFromNow.Size = new System.Drawing.Size(99, 22); this.mnuRecordFromNow.Text = "Now"; this.mnuRecordFromNow.Click += new System.EventHandler(this.mnuRecordFromNow_Click); // // mnuStopMovie // this.mnuStopMovie.Name = "mnuStopMovie"; - this.mnuStopMovie.Size = new System.Drawing.Size(160, 22); + this.mnuStopMovie.Size = new System.Drawing.Size(149, 22); this.mnuStopMovie.Text = "Stop"; this.mnuStopMovie.Click += new System.EventHandler(this.mnuStopMovie_Click); // // mnuCheats // this.mnuCheats.Name = "mnuCheats"; - this.mnuCheats.Size = new System.Drawing.Size(202, 22); + this.mnuCheats.Size = new System.Drawing.Size(185, 22); this.mnuCheats.Text = "Cheats"; this.mnuCheats.Click += new System.EventHandler(this.mnuCheats_Click); // // toolStripMenuItem12 // this.toolStripMenuItem12.Name = "toolStripMenuItem12"; - this.toolStripMenuItem12.Size = new System.Drawing.Size(199, 6); + this.toolStripMenuItem12.Size = new System.Drawing.Size(182, 6); // // mnuTests // @@ -825,13 +953,13 @@ namespace Mesen.GUI.Forms this.mnuTestStopRecording, this.mnuRunAllTests}); this.mnuTests.Name = "mnuTests"; - this.mnuTests.Size = new System.Drawing.Size(202, 22); + this.mnuTests.Size = new System.Drawing.Size(185, 22); this.mnuTests.Text = "Tests"; // // mnuTestRun // this.mnuTestRun.Name = "mnuTestRun"; - this.mnuTestRun.Size = new System.Drawing.Size(208, 22); + this.mnuTestRun.Size = new System.Drawing.Size(193, 22); this.mnuTestRun.Text = "Run..."; this.mnuTestRun.Click += new System.EventHandler(this.mnuTestRun_Click); // @@ -843,35 +971,35 @@ namespace Mesen.GUI.Forms this.mnuTestRecordMovie, this.mnuTestRecordTest}); this.mnuTestRecordFrom.Name = "mnuTestRecordFrom"; - this.mnuTestRecordFrom.Size = new System.Drawing.Size(208, 22); + this.mnuTestRecordFrom.Size = new System.Drawing.Size(193, 22); this.mnuTestRecordFrom.Text = "Record from..."; // // mnuTestRecordStart // this.mnuTestRecordStart.Name = "mnuTestRecordStart"; this.mnuTestRecordStart.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.E))); - this.mnuTestRecordStart.Size = new System.Drawing.Size(152, 22); + this.mnuTestRecordStart.Size = new System.Drawing.Size(138, 22); this.mnuTestRecordStart.Text = "Start"; this.mnuTestRecordStart.Click += new System.EventHandler(this.mnuTestRecordStart_Click); // // mnuTestRecordNow // this.mnuTestRecordNow.Name = "mnuTestRecordNow"; - this.mnuTestRecordNow.Size = new System.Drawing.Size(152, 22); + this.mnuTestRecordNow.Size = new System.Drawing.Size(138, 22); this.mnuTestRecordNow.Text = "Now"; this.mnuTestRecordNow.Click += new System.EventHandler(this.mnuTestRecordNow_Click); // // mnuTestRecordMovie // this.mnuTestRecordMovie.Name = "mnuTestRecordMovie"; - this.mnuTestRecordMovie.Size = new System.Drawing.Size(152, 22); + this.mnuTestRecordMovie.Size = new System.Drawing.Size(138, 22); this.mnuTestRecordMovie.Text = "Movie"; this.mnuTestRecordMovie.Click += new System.EventHandler(this.mnuTestRecordMovie_Click); // // mnuTestRecordTest // this.mnuTestRecordTest.Name = "mnuTestRecordTest"; - this.mnuTestRecordTest.Size = new System.Drawing.Size(152, 22); + this.mnuTestRecordTest.Size = new System.Drawing.Size(138, 22); this.mnuTestRecordTest.Text = "Test"; this.mnuTestRecordTest.Click += new System.EventHandler(this.mnuTestRecordTest_Click); // @@ -879,35 +1007,35 @@ namespace Mesen.GUI.Forms // this.mnuTestStopRecording.Name = "mnuTestStopRecording"; this.mnuTestStopRecording.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.R))); - this.mnuTestStopRecording.Size = new System.Drawing.Size(208, 22); + this.mnuTestStopRecording.Size = new System.Drawing.Size(193, 22); this.mnuTestStopRecording.Text = "Stop recording"; this.mnuTestStopRecording.Click += new System.EventHandler(this.mnuTestStopRecording_Click); // // mnuRunAllTests // this.mnuRunAllTests.Name = "mnuRunAllTests"; - this.mnuRunAllTests.Size = new System.Drawing.Size(208, 22); + this.mnuRunAllTests.Size = new System.Drawing.Size(193, 22); this.mnuRunAllTests.Text = "Run all tests"; this.mnuRunAllTests.Click += new System.EventHandler(this.mnuRunAllTests_Click); // // mnuDebugger // this.mnuDebugger.Name = "mnuDebugger"; - this.mnuDebugger.Size = new System.Drawing.Size(202, 22); + this.mnuDebugger.Size = new System.Drawing.Size(185, 22); this.mnuDebugger.Text = "Debugger"; this.mnuDebugger.Click += new System.EventHandler(this.mnuDebugger_Click); // // toolStripMenuItem1 // this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - this.toolStripMenuItem1.Size = new System.Drawing.Size(199, 6); + this.toolStripMenuItem1.Size = new System.Drawing.Size(182, 6); // // mnuTakeScreenshot // this.mnuTakeScreenshot.Image = global::Mesen.GUI.Properties.Resources.Camera; this.mnuTakeScreenshot.Name = "mnuTakeScreenshot"; this.mnuTakeScreenshot.ShortcutKeys = System.Windows.Forms.Keys.F12; - this.mnuTakeScreenshot.Size = new System.Drawing.Size(202, 22); + this.mnuTakeScreenshot.Size = new System.Drawing.Size(185, 22); this.mnuTakeScreenshot.Text = "Take Screenshot"; this.mnuTakeScreenshot.Click += new System.EventHandler(this.mnuTakeScreenshot_Click); // @@ -918,30 +1046,56 @@ namespace Mesen.GUI.Forms this.toolStripMenuItem5, this.mnuAbout}); this.mnuHelp.Name = "mnuHelp"; - this.mnuHelp.Size = new System.Drawing.Size(46, 22); + this.mnuHelp.Size = new System.Drawing.Size(44, 20); this.mnuHelp.Text = "Help"; // // mnuCheckForUpdates // this.mnuCheckForUpdates.Image = global::Mesen.GUI.Properties.Resources.SoftwareUpdate; this.mnuCheckForUpdates.Name = "mnuCheckForUpdates"; - this.mnuCheckForUpdates.Size = new System.Drawing.Size(181, 22); + this.mnuCheckForUpdates.Size = new System.Drawing.Size(170, 22); this.mnuCheckForUpdates.Text = "Check for updates"; this.mnuCheckForUpdates.Click += new System.EventHandler(this.mnuCheckForUpdates_Click); // // toolStripMenuItem5 // this.toolStripMenuItem5.Name = "toolStripMenuItem5"; - this.toolStripMenuItem5.Size = new System.Drawing.Size(178, 6); + this.toolStripMenuItem5.Size = new System.Drawing.Size(167, 6); // // mnuAbout // this.mnuAbout.Image = global::Mesen.GUI.Properties.Resources.Help; this.mnuAbout.Name = "mnuAbout"; - this.mnuAbout.Size = new System.Drawing.Size(181, 22); + this.mnuAbout.Size = new System.Drawing.Size(170, 22); this.mnuAbout.Text = "About"; this.mnuAbout.Click += new System.EventHandler(this.mnuAbout_Click); // + // toolStripMenuItem18 + // + this.toolStripMenuItem18.Name = "toolStripMenuItem18"; + this.toolStripMenuItem18.Size = new System.Drawing.Size(149, 6); + // + // mnu2xSaiFilter + // + this.mnu2xSaiFilter.Name = "mnu2xSaiFilter"; + this.mnu2xSaiFilter.Size = new System.Drawing.Size(152, 22); + this.mnu2xSaiFilter.Text = "2xSai"; + this.mnu2xSaiFilter.Click += new System.EventHandler(this.mnu2xSaiFilter_Click); + // + // mnuSuper2xSaiFilter + // + this.mnuSuper2xSaiFilter.Name = "mnuSuper2xSaiFilter"; + this.mnuSuper2xSaiFilter.Size = new System.Drawing.Size(152, 22); + this.mnuSuper2xSaiFilter.Text = "Super2xSai"; + this.mnuSuper2xSaiFilter.Click += new System.EventHandler(this.mnuSuper2xSaiFilter_Click); + // + // mnuSuperEagleFilter + // + this.mnuSuperEagleFilter.Name = "mnuSuperEagleFilter"; + this.mnuSuperEagleFilter.Size = new System.Drawing.Size(152, 22); + this.mnuSuperEagleFilter.Text = "SuperEagle"; + this.mnuSuperEagleFilter.Click += new System.EventHandler(this.mnuSuperEagleFilter_Click); + // // frmMain // this.AllowDrop = true; @@ -1067,6 +1221,24 @@ namespace Mesen.GUI.Forms private System.Windows.Forms.ToolStripMenuItem mnuInsertCoin1; private System.Windows.Forms.ToolStripMenuItem mnuVsGameConfig; private System.Windows.Forms.ToolStripMenuItem mnuInsertCoin2; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem15; + private System.Windows.Forms.ToolStripMenuItem mnuXBRZ2xFilter; + private System.Windows.Forms.ToolStripMenuItem mnuXBRZ3xFilter; + private System.Windows.Forms.ToolStripMenuItem mnuXBRZ4xFilter; + private System.Windows.Forms.ToolStripMenuItem mnuXBRZ5xFilter; + private System.Windows.Forms.ToolStripMenuItem mnuXBRZ6xFilter; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem16; + private System.Windows.Forms.ToolStripMenuItem mnuHQ2xFilter; + private System.Windows.Forms.ToolStripMenuItem mnuHQ3xFilter; + private System.Windows.Forms.ToolStripMenuItem mnuHQ4xFilter; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem17; + private System.Windows.Forms.ToolStripMenuItem mnuScale2xFilter; + private System.Windows.Forms.ToolStripMenuItem mnuScale3xFilter; + private System.Windows.Forms.ToolStripMenuItem mnuScale4xFilter; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem18; + private System.Windows.Forms.ToolStripMenuItem mnu2xSaiFilter; + private System.Windows.Forms.ToolStripMenuItem mnuSuper2xSaiFilter; + private System.Windows.Forms.ToolStripMenuItem mnuSuperEagleFilter; } } diff --git a/GUI.NET/Forms/frmMain.cs b/GUI.NET/Forms/frmMain.cs index c4ba9ddb..33b76348 100644 --- a/GUI.NET/Forms/frmMain.cs +++ b/GUI.NET/Forms/frmMain.cs @@ -931,6 +931,20 @@ namespace Mesen.GUI.Forms { mnuNoneFilter.Checked = (filterType == VideoFilterType.None); mnuNtscFilter.Checked = (filterType == VideoFilterType.NTSC); + mnuXBRZ2xFilter.Checked = (filterType == VideoFilterType.xBRZ2x); + mnuXBRZ3xFilter.Checked = (filterType == VideoFilterType.xBRZ3x); + mnuXBRZ4xFilter.Checked = (filterType == VideoFilterType.xBRZ4x); + mnuXBRZ5xFilter.Checked = (filterType == VideoFilterType.xBRZ5x); + mnuXBRZ6xFilter.Checked = (filterType == VideoFilterType.xBRZ6x); + mnuHQ2xFilter.Checked = (filterType == VideoFilterType.HQ2x); + mnuHQ3xFilter.Checked = (filterType == VideoFilterType.HQ3x); + mnuHQ4xFilter.Checked = (filterType == VideoFilterType.HQ4x); + mnuScale2xFilter.Checked = (filterType == VideoFilterType.Scale2x); + mnuScale3xFilter.Checked = (filterType == VideoFilterType.Scale3x); + mnuScale4xFilter.Checked = (filterType == VideoFilterType.Scale4x); + mnu2xSaiFilter.Checked = (filterType == VideoFilterType._2xSai); + mnuSuper2xSaiFilter.Checked = (filterType == VideoFilterType.Super2xSai); + mnuSuperEagleFilter.Checked = (filterType == VideoFilterType.SuperEagle); ConfigManager.Config.VideoInfo.VideoFilter = filterType; ConfigManager.ApplyChanges(); @@ -945,18 +959,91 @@ namespace Mesen.GUI.Forms UpdateScaleMenu(scale); } + private void SetVideoFilter(VideoFilterType type) + { + InteropEmu.SetVideoFilter(type); + UpdateFilterMenu(type); + _customSize = false; + } + private void mnuNoneFilter_Click(object sender, EventArgs e) { - InteropEmu.SetVideoFilter(VideoFilterType.None); - UpdateFilterMenu(VideoFilterType.None); - _customSize = false; + SetVideoFilter(VideoFilterType.None); } private void mnuNtscFilter_Click(object sender, EventArgs e) { - InteropEmu.SetVideoFilter(VideoFilterType.NTSC); - UpdateFilterMenu(VideoFilterType.NTSC); - _customSize = false; + SetVideoFilter(VideoFilterType.NTSC); + } + + private void mnuXBRZ2xFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.xBRZ2x); + } + + private void mnuXBRZ3xFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.xBRZ3x); + } + + private void mnuXBRZ4xFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.xBRZ4x); + } + + private void mnuXBRZ5xFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.xBRZ5x); + } + + private void mnuXBRZ6xFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.xBRZ6x); + } + + private void mnuHQ2xFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.HQ2x); + } + + private void mnuHQ3xFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.HQ3x); + } + + private void mnuHQ4xFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.HQ4x); + } + + private void mnuScale2xFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.Scale2x); + } + + private void mnuScale3xFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.Scale3x); + } + + private void mnuScale4xFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.Scale4x); + } + + private void mnu2xSaiFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType._2xSai); + } + + private void mnuSuper2xSaiFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.Super2xSai); + } + + private void mnuSuperEagleFilter_Click(object sender, EventArgs e) + { + SetVideoFilter(VideoFilterType.SuperEagle); } private void InitializeFdsDiskMenu() diff --git a/GUI.NET/Forms/frmMain.resx b/GUI.NET/Forms/frmMain.resx index 5bc26c97..91a0e7cc 100644 --- a/GUI.NET/Forms/frmMain.resx +++ b/GUI.NET/Forms/frmMain.resx @@ -121,9 +121,9 @@ 17, 17 - 110, 17 + 107, 17 - 231, 17 + 220, 17 \ No newline at end of file diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index acc9da9e..09b528f2 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -634,6 +634,20 @@ namespace Mesen.GUI { None = 0, NTSC = 1, + xBRZ2x = 2, + xBRZ3x = 3, + xBRZ4x = 4, + xBRZ5x = 5, + xBRZ6x = 6, + HQ2x = 7, + HQ3x = 8, + HQ4x = 9, + Scale2x = 10, + Scale3x = 11, + Scale4x = 12, + _2xSai = 13, + Super2xSai = 14, + SuperEagle = 15 } public enum VideoAspectRatio diff --git a/Utilities/HQX/common.h b/Utilities/HQX/common.h new file mode 100644 index 00000000..dbd6c334 --- /dev/null +++ b/Utilities/HQX/common.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2003 Maxim Stepin ( maxst@hiend3d.com ) + * + * Copyright (C) 2010 Cameron Zemek ( grom@zeminvaders.net) + * Copyright (C) 2011 Francois Gannaz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __HQX_COMMON_H_ +#define __HQX_COMMON_H_ + +#include +#include +#include + +#define MASK_2 0x0000FF00 +#define MASK_13 0x00FF00FF +#define MASK_RGB 0x00FFFFFF +#define MASK_ALPHA 0xFF000000 + +#define Ymask 0x00FF0000 +#define Umask 0x0000FF00 +#define Vmask 0x000000FF +#define trY 0x00300000 +#define trU 0x00000700 +#define trV 0x00000006 + +/* RGB to YUV lookup table */ +extern uint32_t RGBtoYUV[16777216]; + +static inline uint32_t rgb_to_yuv(uint32_t c) +{ + // Mask against MASK_RGB to discard the alpha channel + return RGBtoYUV[MASK_RGB & c]; +} + +/* Test if there is difference in color */ +static inline int yuv_diff(uint32_t yuv1, uint32_t yuv2) { + return (( std::abs((int)((yuv1 & Ymask) - (yuv2 & Ymask))) > trY ) || + ( std::abs((int)((yuv1 & Umask) - (yuv2 & Umask))) > trU ) || + ( std::abs((int)((yuv1 & Vmask) - (yuv2 & Vmask))) > trV ) ); +} + +static inline int Diff(uint32_t c1, uint32_t c2) +{ + return yuv_diff(rgb_to_yuv(c1), rgb_to_yuv(c2)); +} + +/* Interpolate functions */ +static inline uint32_t Interpolate_2(uint32_t c1, int w1, uint32_t c2, int w2, int s) +{ + if (c1 == c2) { + return c1; + } + return + (((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2) << (24-s)) & MASK_ALPHA) + + ((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2) >> s) & MASK_2) + + ((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2) >> s) & MASK_13); +} + +static inline uint32_t Interpolate_3(uint32_t c1, int w1, uint32_t c2, int w2, uint32_t c3, int w3, int s) +{ + return + (((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2 + ((c3 & MASK_ALPHA) >> 24) * w3) << (24-s)) & MASK_ALPHA) + + ((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2 + (c3 & MASK_2) * w3) >> s) & MASK_2) + + ((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2 + (c3 & MASK_13) * w3) >> s) & MASK_13); +} + +static inline uint32_t Interp1(uint32_t c1, uint32_t c2) +{ + //(c1*3+c2) >> 2; + return Interpolate_2(c1, 3, c2, 1, 2); +} + +static inline uint32_t Interp2(uint32_t c1, uint32_t c2, uint32_t c3) +{ + //(c1*2+c2+c3) >> 2; + return Interpolate_3(c1, 2, c2, 1, c3, 1, 2); +} + +static inline uint32_t Interp3(uint32_t c1, uint32_t c2) +{ + //(c1*7+c2)/8; + return Interpolate_2(c1, 7, c2, 1, 3); +} + +static inline uint32_t Interp4(uint32_t c1, uint32_t c2, uint32_t c3) +{ + //(c1*2+(c2+c3)*7)/16; + return Interpolate_3(c1, 2, c2, 7, c3, 7, 4); +} + +static inline uint32_t Interp5(uint32_t c1, uint32_t c2) +{ + //(c1+c2) >> 1; + return Interpolate_2(c1, 1, c2, 1, 1); +} + +static inline uint32_t Interp6(uint32_t c1, uint32_t c2, uint32_t c3) +{ + //(c1*5+c2*2+c3)/8; + return Interpolate_3(c1, 5, c2, 2, c3, 1, 3); +} + +static inline uint32_t Interp7(uint32_t c1, uint32_t c2, uint32_t c3) +{ + //(c1*6+c2+c3)/8; + return Interpolate_3(c1, 6, c2, 1, c3, 1, 3); +} + +static inline uint32_t Interp8(uint32_t c1, uint32_t c2) +{ + //(c1*5+c2*3)/8; + return Interpolate_2(c1, 5, c2, 3, 3); +} + +static inline uint32_t Interp9(uint32_t c1, uint32_t c2, uint32_t c3) +{ + //(c1*2+(c2+c3)*3)/8; + return Interpolate_3(c1, 2, c2, 3, c3, 3, 3); +} + +static inline uint32_t Interp10(uint32_t c1, uint32_t c2, uint32_t c3) +{ + //(c1*14+c2+c3)/16; + return Interpolate_3(c1, 14, c2, 1, c3, 1, 4); +} + +#endif diff --git a/Utilities/HQX/hq2x.cpp b/Utilities/HQX/hq2x.cpp new file mode 100644 index 00000000..ee34da75 --- /dev/null +++ b/Utilities/HQX/hq2x.cpp @@ -0,0 +1,2811 @@ +/* + * Copyright (C) 2003 Maxim Stepin ( maxst@hiend3d.com ) + * + * Copyright (C) 2010 Cameron Zemek ( grom@zeminvaders.net) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "stdafx.h" +#include "../stdafx.h" +#include +#include "common.h" +#include "hqx.h" + +#define PIXEL00_0 *dp = w[5]; +#define PIXEL00_10 *dp = Interp1(w[5], w[1]); +#define PIXEL00_11 *dp = Interp1(w[5], w[4]); +#define PIXEL00_12 *dp = Interp1(w[5], w[2]); +#define PIXEL00_20 *dp = Interp2(w[5], w[4], w[2]); +#define PIXEL00_21 *dp = Interp2(w[5], w[1], w[2]); +#define PIXEL00_22 *dp = Interp2(w[5], w[1], w[4]); +#define PIXEL00_60 *dp = Interp6(w[5], w[2], w[4]); +#define PIXEL00_61 *dp = Interp6(w[5], w[4], w[2]); +#define PIXEL00_70 *dp = Interp7(w[5], w[4], w[2]); +#define PIXEL00_90 *dp = Interp9(w[5], w[4], w[2]); +#define PIXEL00_100 *dp = Interp10(w[5], w[4], w[2]); +#define PIXEL01_0 *(dp+1) = w[5]; +#define PIXEL01_10 *(dp+1) = Interp1(w[5], w[3]); +#define PIXEL01_11 *(dp+1) = Interp1(w[5], w[2]); +#define PIXEL01_12 *(dp+1) = Interp1(w[5], w[6]); +#define PIXEL01_20 *(dp+1) = Interp2(w[5], w[2], w[6]); +#define PIXEL01_21 *(dp+1) = Interp2(w[5], w[3], w[6]); +#define PIXEL01_22 *(dp+1) = Interp2(w[5], w[3], w[2]); +#define PIXEL01_60 *(dp+1) = Interp6(w[5], w[6], w[2]); +#define PIXEL01_61 *(dp+1) = Interp6(w[5], w[2], w[6]); +#define PIXEL01_70 *(dp+1) = Interp7(w[5], w[2], w[6]); +#define PIXEL01_90 *(dp+1) = Interp9(w[5], w[2], w[6]); +#define PIXEL01_100 *(dp+1) = Interp10(w[5], w[2], w[6]); +#define PIXEL10_0 *(dp+dpL) = w[5]; +#define PIXEL10_10 *(dp+dpL) = Interp1(w[5], w[7]); +#define PIXEL10_11 *(dp+dpL) = Interp1(w[5], w[8]); +#define PIXEL10_12 *(dp+dpL) = Interp1(w[5], w[4]); +#define PIXEL10_20 *(dp+dpL) = Interp2(w[5], w[8], w[4]); +#define PIXEL10_21 *(dp+dpL) = Interp2(w[5], w[7], w[4]); +#define PIXEL10_22 *(dp+dpL) = Interp2(w[5], w[7], w[8]); +#define PIXEL10_60 *(dp+dpL) = Interp6(w[5], w[4], w[8]); +#define PIXEL10_61 *(dp+dpL) = Interp6(w[5], w[8], w[4]); +#define PIXEL10_70 *(dp+dpL) = Interp7(w[5], w[8], w[4]); +#define PIXEL10_90 *(dp+dpL) = Interp9(w[5], w[8], w[4]); +#define PIXEL10_100 *(dp+dpL) = Interp10(w[5], w[8], w[4]); +#define PIXEL11_0 *(dp+dpL+1) = w[5]; +#define PIXEL11_10 *(dp+dpL+1) = Interp1(w[5], w[9]); +#define PIXEL11_11 *(dp+dpL+1) = Interp1(w[5], w[6]); +#define PIXEL11_12 *(dp+dpL+1) = Interp1(w[5], w[8]); +#define PIXEL11_20 *(dp+dpL+1) = Interp2(w[5], w[6], w[8]); +#define PIXEL11_21 *(dp+dpL+1) = Interp2(w[5], w[9], w[8]); +#define PIXEL11_22 *(dp+dpL+1) = Interp2(w[5], w[9], w[6]); +#define PIXEL11_60 *(dp+dpL+1) = Interp6(w[5], w[8], w[6]); +#define PIXEL11_61 *(dp+dpL+1) = Interp6(w[5], w[6], w[8]); +#define PIXEL11_70 *(dp+dpL+1) = Interp7(w[5], w[6], w[8]); +#define PIXEL11_90 *(dp+dpL+1) = Interp9(w[5], w[6], w[8]); +#define PIXEL11_100 *(dp+dpL+1) = Interp10(w[5], w[6], w[8]); + +void HQX_CALLCONV hq2x_32_rb( uint32_t * sp, uint32_t srb, uint32_t * dp, uint32_t drb, int Xres, int Yres ) +{ + int i, j, k; + int prevline, nextline; + uint32_t w[10]; + int dpL = (drb >> 2); + int spL = (srb >> 2); + uint8_t *sRowP = (uint8_t *) sp; + uint8_t *dRowP = (uint8_t *) dp; + uint32_t yuv1, yuv2; + + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ + + for (j=0; j0) prevline = -spL; else prevline = 0; + if (j0) + { + w[1] = *(sp + prevline - 1); + w[4] = *(sp - 1); + w[7] = *(sp + nextline - 1); + } + else + { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } + + if (i +#include "common.h" +#include "hqx.h" + +#define PIXEL00_1M *dp = Interp1(w[5], w[1]); +#define PIXEL00_1U *dp = Interp1(w[5], w[2]); +#define PIXEL00_1L *dp = Interp1(w[5], w[4]); +#define PIXEL00_2 *dp = Interp2(w[5], w[4], w[2]); +#define PIXEL00_4 *dp = Interp4(w[5], w[4], w[2]); +#define PIXEL00_5 *dp = Interp5(w[4], w[2]); +#define PIXEL00_C *dp = w[5]; + +#define PIXEL01_1 *(dp+1) = Interp1(w[5], w[2]); +#define PIXEL01_3 *(dp+1) = Interp3(w[5], w[2]); +#define PIXEL01_6 *(dp+1) = Interp1(w[2], w[5]); +#define PIXEL01_C *(dp+1) = w[5]; + +#define PIXEL02_1M *(dp+2) = Interp1(w[5], w[3]); +#define PIXEL02_1U *(dp+2) = Interp1(w[5], w[2]); +#define PIXEL02_1R *(dp+2) = Interp1(w[5], w[6]); +#define PIXEL02_2 *(dp+2) = Interp2(w[5], w[2], w[6]); +#define PIXEL02_4 *(dp+2) = Interp4(w[5], w[2], w[6]); +#define PIXEL02_5 *(dp+2) = Interp5(w[2], w[6]); +#define PIXEL02_C *(dp+2) = w[5]; + +#define PIXEL10_1 *(dp+dpL) = Interp1(w[5], w[4]); +#define PIXEL10_3 *(dp+dpL) = Interp3(w[5], w[4]); +#define PIXEL10_6 *(dp+dpL) = Interp1(w[4], w[5]); +#define PIXEL10_C *(dp+dpL) = w[5]; + +#define PIXEL11 *(dp+dpL+1) = w[5]; + +#define PIXEL12_1 *(dp+dpL+2) = Interp1(w[5], w[6]); +#define PIXEL12_3 *(dp+dpL+2) = Interp3(w[5], w[6]); +#define PIXEL12_6 *(dp+dpL+2) = Interp1(w[6], w[5]); +#define PIXEL12_C *(dp+dpL+2) = w[5]; + +#define PIXEL20_1M *(dp+dpL+dpL) = Interp1(w[5], w[7]); +#define PIXEL20_1D *(dp+dpL+dpL) = Interp1(w[5], w[8]); +#define PIXEL20_1L *(dp+dpL+dpL) = Interp1(w[5], w[4]); +#define PIXEL20_2 *(dp+dpL+dpL) = Interp2(w[5], w[8], w[4]); +#define PIXEL20_4 *(dp+dpL+dpL) = Interp4(w[5], w[8], w[4]); +#define PIXEL20_5 *(dp+dpL+dpL) = Interp5(w[8], w[4]); +#define PIXEL20_C *(dp+dpL+dpL) = w[5]; + +#define PIXEL21_1 *(dp+dpL+dpL+1) = Interp1(w[5], w[8]); +#define PIXEL21_3 *(dp+dpL+dpL+1) = Interp3(w[5], w[8]); +#define PIXEL21_6 *(dp+dpL+dpL+1) = Interp1(w[8], w[5]); +#define PIXEL21_C *(dp+dpL+dpL+1) = w[5]; + +#define PIXEL22_1M *(dp+dpL+dpL+2) = Interp1(w[5], w[9]); +#define PIXEL22_1D *(dp+dpL+dpL+2) = Interp1(w[5], w[8]); +#define PIXEL22_1R *(dp+dpL+dpL+2) = Interp1(w[5], w[6]); +#define PIXEL22_2 *(dp+dpL+dpL+2) = Interp2(w[5], w[6], w[8]); +#define PIXEL22_4 *(dp+dpL+dpL+2) = Interp4(w[5], w[6], w[8]); +#define PIXEL22_5 *(dp+dpL+dpL+2) = Interp5(w[6], w[8]); +#define PIXEL22_C *(dp+dpL+dpL+2) = w[5]; + +void HQX_CALLCONV hq3x_32_rb( uint32_t * sp, uint32_t srb, uint32_t * dp, uint32_t drb, int Xres, int Yres ) +{ + int i, j, k; + int prevline, nextline; + uint32_t w[10]; + int dpL = (drb >> 2); + int spL = (srb >> 2); + uint8_t *sRowP = (uint8_t *) sp; + uint8_t *dRowP = (uint8_t *) dp; + uint32_t yuv1, yuv2; + + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ + + for (j=0; j0) prevline = -spL; else prevline = 0; + if (j0) + { + w[1] = *(sp + prevline - 1); + w[4] = *(sp - 1); + w[7] = *(sp + nextline - 1); + } + else + { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } + + if (i +#include "common.h" +#include "hqx.h" + +#define PIXEL00_0 *dp = w[5]; +#define PIXEL00_11 *dp = Interp1(w[5], w[4]); +#define PIXEL00_12 *dp = Interp1(w[5], w[2]); +#define PIXEL00_20 *dp = Interp2(w[5], w[2], w[4]); +#define PIXEL00_50 *dp = Interp5(w[2], w[4]); +#define PIXEL00_80 *dp = Interp8(w[5], w[1]); +#define PIXEL00_81 *dp = Interp8(w[5], w[4]); +#define PIXEL00_82 *dp = Interp8(w[5], w[2]); +#define PIXEL01_0 *(dp+1) = w[5]; +#define PIXEL01_10 *(dp+1) = Interp1(w[5], w[1]); +#define PIXEL01_12 *(dp+1) = Interp1(w[5], w[2]); +#define PIXEL01_14 *(dp+1) = Interp1(w[2], w[5]); +#define PIXEL01_21 *(dp+1) = Interp2(w[2], w[5], w[4]); +#define PIXEL01_31 *(dp+1) = Interp3(w[5], w[4]); +#define PIXEL01_50 *(dp+1) = Interp5(w[2], w[5]); +#define PIXEL01_60 *(dp+1) = Interp6(w[5], w[2], w[4]); +#define PIXEL01_61 *(dp+1) = Interp6(w[5], w[2], w[1]); +#define PIXEL01_82 *(dp+1) = Interp8(w[5], w[2]); +#define PIXEL01_83 *(dp+1) = Interp8(w[2], w[4]); +#define PIXEL02_0 *(dp+2) = w[5]; +#define PIXEL02_10 *(dp+2) = Interp1(w[5], w[3]); +#define PIXEL02_11 *(dp+2) = Interp1(w[5], w[2]); +#define PIXEL02_13 *(dp+2) = Interp1(w[2], w[5]); +#define PIXEL02_21 *(dp+2) = Interp2(w[2], w[5], w[6]); +#define PIXEL02_32 *(dp+2) = Interp3(w[5], w[6]); +#define PIXEL02_50 *(dp+2) = Interp5(w[2], w[5]); +#define PIXEL02_60 *(dp+2) = Interp6(w[5], w[2], w[6]); +#define PIXEL02_61 *(dp+2) = Interp6(w[5], w[2], w[3]); +#define PIXEL02_81 *(dp+2) = Interp8(w[5], w[2]); +#define PIXEL02_83 *(dp+2) = Interp8(w[2], w[6]); +#define PIXEL03_0 *(dp+3) = w[5]; +#define PIXEL03_11 *(dp+3) = Interp1(w[5], w[2]); +#define PIXEL03_12 *(dp+3) = Interp1(w[5], w[6]); +#define PIXEL03_20 *(dp+3) = Interp2(w[5], w[2], w[6]); +#define PIXEL03_50 *(dp+3) = Interp5(w[2], w[6]); +#define PIXEL03_80 *(dp+3) = Interp8(w[5], w[3]); +#define PIXEL03_81 *(dp+3) = Interp8(w[5], w[2]); +#define PIXEL03_82 *(dp+3) = Interp8(w[5], w[6]); +#define PIXEL10_0 *(dp+dpL) = w[5]; +#define PIXEL10_10 *(dp+dpL) = Interp1(w[5], w[1]); +#define PIXEL10_11 *(dp+dpL) = Interp1(w[5], w[4]); +#define PIXEL10_13 *(dp+dpL) = Interp1(w[4], w[5]); +#define PIXEL10_21 *(dp+dpL) = Interp2(w[4], w[5], w[2]); +#define PIXEL10_32 *(dp+dpL) = Interp3(w[5], w[2]); +#define PIXEL10_50 *(dp+dpL) = Interp5(w[4], w[5]); +#define PIXEL10_60 *(dp+dpL) = Interp6(w[5], w[4], w[2]); +#define PIXEL10_61 *(dp+dpL) = Interp6(w[5], w[4], w[1]); +#define PIXEL10_81 *(dp+dpL) = Interp8(w[5], w[4]); +#define PIXEL10_83 *(dp+dpL) = Interp8(w[4], w[2]); +#define PIXEL11_0 *(dp+dpL+1) = w[5]; +#define PIXEL11_30 *(dp+dpL+1) = Interp3(w[5], w[1]); +#define PIXEL11_31 *(dp+dpL+1) = Interp3(w[5], w[4]); +#define PIXEL11_32 *(dp+dpL+1) = Interp3(w[5], w[2]); +#define PIXEL11_70 *(dp+dpL+1) = Interp7(w[5], w[4], w[2]); +#define PIXEL12_0 *(dp+dpL+2) = w[5]; +#define PIXEL12_30 *(dp+dpL+2) = Interp3(w[5], w[3]); +#define PIXEL12_31 *(dp+dpL+2) = Interp3(w[5], w[2]); +#define PIXEL12_32 *(dp+dpL+2) = Interp3(w[5], w[6]); +#define PIXEL12_70 *(dp+dpL+2) = Interp7(w[5], w[6], w[2]); +#define PIXEL13_0 *(dp+dpL+3) = w[5]; +#define PIXEL13_10 *(dp+dpL+3) = Interp1(w[5], w[3]); +#define PIXEL13_12 *(dp+dpL+3) = Interp1(w[5], w[6]); +#define PIXEL13_14 *(dp+dpL+3) = Interp1(w[6], w[5]); +#define PIXEL13_21 *(dp+dpL+3) = Interp2(w[6], w[5], w[2]); +#define PIXEL13_31 *(dp+dpL+3) = Interp3(w[5], w[2]); +#define PIXEL13_50 *(dp+dpL+3) = Interp5(w[6], w[5]); +#define PIXEL13_60 *(dp+dpL+3) = Interp6(w[5], w[6], w[2]); +#define PIXEL13_61 *(dp+dpL+3) = Interp6(w[5], w[6], w[3]); +#define PIXEL13_82 *(dp+dpL+3) = Interp8(w[5], w[6]); +#define PIXEL13_83 *(dp+dpL+3) = Interp8(w[6], w[2]); +#define PIXEL20_0 *(dp+dpL+dpL) = w[5]; +#define PIXEL20_10 *(dp+dpL+dpL) = Interp1(w[5], w[7]); +#define PIXEL20_12 *(dp+dpL+dpL) = Interp1(w[5], w[4]); +#define PIXEL20_14 *(dp+dpL+dpL) = Interp1(w[4], w[5]); +#define PIXEL20_21 *(dp+dpL+dpL) = Interp2(w[4], w[5], w[8]); +#define PIXEL20_31 *(dp+dpL+dpL) = Interp3(w[5], w[8]); +#define PIXEL20_50 *(dp+dpL+dpL) = Interp5(w[4], w[5]); +#define PIXEL20_60 *(dp+dpL+dpL) = Interp6(w[5], w[4], w[8]); +#define PIXEL20_61 *(dp+dpL+dpL) = Interp6(w[5], w[4], w[7]); +#define PIXEL20_82 *(dp+dpL+dpL) = Interp8(w[5], w[4]); +#define PIXEL20_83 *(dp+dpL+dpL) = Interp8(w[4], w[8]); +#define PIXEL21_0 *(dp+dpL+dpL+1) = w[5]; +#define PIXEL21_30 *(dp+dpL+dpL+1) = Interp3(w[5], w[7]); +#define PIXEL21_31 *(dp+dpL+dpL+1) = Interp3(w[5], w[8]); +#define PIXEL21_32 *(dp+dpL+dpL+1) = Interp3(w[5], w[4]); +#define PIXEL21_70 *(dp+dpL+dpL+1) = Interp7(w[5], w[4], w[8]); +#define PIXEL22_0 *(dp+dpL+dpL+2) = w[5]; +#define PIXEL22_30 *(dp+dpL+dpL+2) = Interp3(w[5], w[9]); +#define PIXEL22_31 *(dp+dpL+dpL+2) = Interp3(w[5], w[6]); +#define PIXEL22_32 *(dp+dpL+dpL+2) = Interp3(w[5], w[8]); +#define PIXEL22_70 *(dp+dpL+dpL+2) = Interp7(w[5], w[6], w[8]); +#define PIXEL23_0 *(dp+dpL+dpL+3) = w[5]; +#define PIXEL23_10 *(dp+dpL+dpL+3) = Interp1(w[5], w[9]); +#define PIXEL23_11 *(dp+dpL+dpL+3) = Interp1(w[5], w[6]); +#define PIXEL23_13 *(dp+dpL+dpL+3) = Interp1(w[6], w[5]); +#define PIXEL23_21 *(dp+dpL+dpL+3) = Interp2(w[6], w[5], w[8]); +#define PIXEL23_32 *(dp+dpL+dpL+3) = Interp3(w[5], w[8]); +#define PIXEL23_50 *(dp+dpL+dpL+3) = Interp5(w[6], w[5]); +#define PIXEL23_60 *(dp+dpL+dpL+3) = Interp6(w[5], w[6], w[8]); +#define PIXEL23_61 *(dp+dpL+dpL+3) = Interp6(w[5], w[6], w[9]); +#define PIXEL23_81 *(dp+dpL+dpL+3) = Interp8(w[5], w[6]); +#define PIXEL23_83 *(dp+dpL+dpL+3) = Interp8(w[6], w[8]); +#define PIXEL30_0 *(dp+dpL+dpL+dpL) = w[5]; +#define PIXEL30_11 *(dp+dpL+dpL+dpL) = Interp1(w[5], w[8]); +#define PIXEL30_12 *(dp+dpL+dpL+dpL) = Interp1(w[5], w[4]); +#define PIXEL30_20 *(dp+dpL+dpL+dpL) = Interp2(w[5], w[8], w[4]); +#define PIXEL30_50 *(dp+dpL+dpL+dpL) = Interp5(w[8], w[4]); +#define PIXEL30_80 *(dp+dpL+dpL+dpL) = Interp8(w[5], w[7]); +#define PIXEL30_81 *(dp+dpL+dpL+dpL) = Interp8(w[5], w[8]); +#define PIXEL30_82 *(dp+dpL+dpL+dpL) = Interp8(w[5], w[4]); +#define PIXEL31_0 *(dp+dpL+dpL+dpL+1) = w[5]; +#define PIXEL31_10 *(dp+dpL+dpL+dpL+1) = Interp1(w[5], w[7]); +#define PIXEL31_11 *(dp+dpL+dpL+dpL+1) = Interp1(w[5], w[8]); +#define PIXEL31_13 *(dp+dpL+dpL+dpL+1) = Interp1(w[8], w[5]); +#define PIXEL31_21 *(dp+dpL+dpL+dpL+1) = Interp2(w[8], w[5], w[4]); +#define PIXEL31_32 *(dp+dpL+dpL+dpL+1) = Interp3(w[5], w[4]); +#define PIXEL31_50 *(dp+dpL+dpL+dpL+1) = Interp5(w[8], w[5]); +#define PIXEL31_60 *(dp+dpL+dpL+dpL+1) = Interp6(w[5], w[8], w[4]); +#define PIXEL31_61 *(dp+dpL+dpL+dpL+1) = Interp6(w[5], w[8], w[7]); +#define PIXEL31_81 *(dp+dpL+dpL+dpL+1) = Interp8(w[5], w[8]); +#define PIXEL31_83 *(dp+dpL+dpL+dpL+1) = Interp8(w[8], w[4]); +#define PIXEL32_0 *(dp+dpL+dpL+dpL+2) = w[5]; +#define PIXEL32_10 *(dp+dpL+dpL+dpL+2) = Interp1(w[5], w[9]); +#define PIXEL32_12 *(dp+dpL+dpL+dpL+2) = Interp1(w[5], w[8]); +#define PIXEL32_14 *(dp+dpL+dpL+dpL+2) = Interp1(w[8], w[5]); +#define PIXEL32_21 *(dp+dpL+dpL+dpL+2) = Interp2(w[8], w[5], w[6]); +#define PIXEL32_31 *(dp+dpL+dpL+dpL+2) = Interp3(w[5], w[6]); +#define PIXEL32_50 *(dp+dpL+dpL+dpL+2) = Interp5(w[8], w[5]); +#define PIXEL32_60 *(dp+dpL+dpL+dpL+2) = Interp6(w[5], w[8], w[6]); +#define PIXEL32_61 *(dp+dpL+dpL+dpL+2) = Interp6(w[5], w[8], w[9]); +#define PIXEL32_82 *(dp+dpL+dpL+dpL+2) = Interp8(w[5], w[8]); +#define PIXEL32_83 *(dp+dpL+dpL+dpL+2) = Interp8(w[8], w[6]); +#define PIXEL33_0 *(dp+dpL+dpL+dpL+3) = w[5]; +#define PIXEL33_11 *(dp+dpL+dpL+dpL+3) = Interp1(w[5], w[6]); +#define PIXEL33_12 *(dp+dpL+dpL+dpL+3) = Interp1(w[5], w[8]); +#define PIXEL33_20 *(dp+dpL+dpL+dpL+3) = Interp2(w[5], w[8], w[6]); +#define PIXEL33_50 *(dp+dpL+dpL+dpL+3) = Interp5(w[8], w[6]); +#define PIXEL33_80 *(dp+dpL+dpL+dpL+3) = Interp8(w[5], w[9]); +#define PIXEL33_81 *(dp+dpL+dpL+dpL+3) = Interp8(w[5], w[6]); +#define PIXEL33_82 *(dp+dpL+dpL+dpL+3) = Interp8(w[5], w[8]); + +void HQX_CALLCONV hq4x_32_rb( uint32_t * sp, uint32_t srb, uint32_t * dp, uint32_t drb, int Xres, int Yres ) +{ + int i, j, k; + int prevline, nextline; + uint32_t w[10]; + int dpL = (drb >> 2); + int spL = (srb >> 2); + uint8_t *sRowP = (uint8_t *) sp; + uint8_t *dRowP = (uint8_t *) dp; + uint32_t yuv1, yuv2; + + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ + + for (j=0; j0) prevline = -spL; else prevline = 0; + if (j0) + { + w[1] = *(sp + prevline - 1); + w[4] = *(sp - 1); + w[7] = *(sp + nextline - 1); + } + else + { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } + + if (i + +#if defined( __GNUC__ ) + #ifdef __MINGW32__ + #define HQX_CALLCONV __stdcall + #else + #define HQX_CALLCONV + #endif +#else + #define HQX_CALLCONV +#endif + +#if defined(_WIN32) + #ifdef DLL_EXPORT + #define HQX_API __declspec(dllexport) + #else + #define HQX_API __declspec(dllimport) + #endif +#else + #define HQX_API +#endif + +void HQX_CALLCONV hqxInit(void); +void HQX_CALLCONV hq2x_32( uint32_t * src, uint32_t * dest, int width, int height ); +void HQX_CALLCONV hq3x_32( uint32_t * src, uint32_t * dest, int width, int height ); +void HQX_CALLCONV hq4x_32( uint32_t * src, uint32_t * dest, int width, int height ); + +void HQX_CALLCONV hq2x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height ); +void HQX_CALLCONV hq3x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height ); +void HQX_CALLCONV hq4x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height ); + +#endif diff --git a/Utilities/HQX/init.cpp b/Utilities/HQX/init.cpp new file mode 100644 index 00000000..8f71198b --- /dev/null +++ b/Utilities/HQX/init.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 Cameron Zemek ( grom@zeminvaders.net) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "stdafx.h" +#include "../stdafx.h" +#include +#include "hqx.h" + +uint32_t RGBtoYUV[16777216]; +uint32_t YUV1, YUV2; + +void HQX_CALLCONV hqxInit(void) +{ + /* Initalize RGB to YUV lookup table */ + uint32_t c, r, g, b, y, u, v; + for (c = 0; c < 16777215; c++) { + r = (c & 0xFF0000) >> 16; + g = (c & 0x00FF00) >> 8; + b = c & 0x0000FF; + y = (uint32_t)(0.299*r + 0.587*g + 0.114*b); + u = (uint32_t)(-0.169*r - 0.331*g + 0.5*b) + 128; + v = (uint32_t)(0.5*r - 0.419*g - 0.081*b) + 128; + RGBtoYUV[c] = (y << 16) + (u << 8) + v; + } +} diff --git a/Utilities/KreedSaiEagle/2xSai.cpp b/Utilities/KreedSaiEagle/2xSai.cpp new file mode 100644 index 00000000..843893ab --- /dev/null +++ b/Utilities/KreedSaiEagle/2xSai.cpp @@ -0,0 +1,164 @@ +/* This is a heavily modified version of the file used in RetroArch */ + +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2014 - Daniel De Matteis + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include "stdafx.h" +#include "../stdafx.h" + +#define twoxsai_interpolate_xrgb8888(A, B) ((((A) & 0xFEFEFEFE) >> 1) + (((B) & 0xFEFEFEFE) >> 1) + ((A) & (B) & 0x01010101)) + +#define twoxsai_interpolate2_xrgb8888(A, B, C, D) ((((A) & 0xFCFCFCFC) >> 2) + (((B) & 0xFCFCFCFC) >> 2) + (((C) & 0xFCFCFCFC) >> 2) + (((D) & 0xFCFCFCFC) >> 2) + (((((A) & 0x03030303) + ((B) & 0x03030303) + ((C) & 0x03030303) + ((D) & 0x03030303)) >> 2) & 0x03030303)) + +#define twoxsai_interpolate_rgb565(A, B) ((((A) & 0xF7DE) >> 1) + (((B) & 0xF7DE) >> 1) + ((A) & (B) & 0x0821)) + +#define twoxsai_interpolate2_rgb565(A, B, C, D) ((((A) & 0xE79C) >> 2) + (((B) & 0xE79C) >> 2) + (((C) & 0xE79C) >> 2) + (((D) & 0xE79C) >> 2) + (((((A) & 0x1863) + ((B) & 0x1863) + ((C) & 0x1863) + ((D) & 0x1863)) >> 2) & 0x1863)) + +#define twoxsai_interpolate_4444(A, B) (((A & 0xEEEE) >> 1) + ((B & 0xEEEE) >> 1) + (A & B & 0x1111)) +#define twoxsai_interpolate2_4444(A, B, C, D) (((A & 0xCCCC) >> 2) + ((B & 0xCCCC) >> 2) + ((C & 0xCCCC) >> 2) + ((D & 0xCCCC) >> 2) + ((((A & 0x3333) + (B & 0x3333) + (C & 0x3333) + (D & 0x3333)) >> 2) & 0x3333)) + +#define twoxsai_result(A, B, C, D) (((A) != (C) || (A) != (D)) - ((B) != (C) || (B) != (D))); + +#define twoxsai_declare_variables(typename_t, in, nextline) \ + typename_t product, product1, product2; \ + typename_t colorI = *(in - nextline - 1); \ + typename_t colorE = *(in - nextline + 0); \ + typename_t colorF = *(in - nextline + 1); \ + typename_t colorJ = *(in - nextline + 2); \ + typename_t colorG = *(in - 1); \ + typename_t colorA = *(in + 0); \ + typename_t colorB = *(in + 1); \ + typename_t colorK = *(in + 2); \ + typename_t colorH = *(in + nextline - 1); \ + typename_t colorC = *(in + nextline + 0); \ + typename_t colorD = *(in + nextline + 1); \ + typename_t colorL = *(in + nextline + 2); \ + typename_t colorM = *(in + nextline + nextline - 1); \ + typename_t colorN = *(in + nextline + nextline + 0); \ + typename_t colorO = *(in + nextline + nextline + 1); + +#ifndef twoxsai_function +#define twoxsai_function(result_cb, interpolate_cb, interpolate2_cb) \ + if (colorA == colorD && colorB != colorC) \ + { \ + if ((colorA == colorE && colorB == colorL) || (colorA == colorC && colorA == colorF && colorB != colorE && colorB == colorJ)) \ + product = colorA; \ + else \ + { \ + product = interpolate_cb(colorA, colorB); \ + } \ + if ((colorA == colorG && colorC == colorO) || (colorA == colorB && colorA == colorH && colorG != colorC && colorC == colorM)) \ + product1 = colorA; \ + else \ + { \ + product1 = interpolate_cb(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_cb(colorA, colorB); \ + } \ + if ((colorC == colorH && colorA == colorF) || (colorC == colorG && colorC == colorD && colorA != colorH && colorA == colorI)) \ + product1 = colorC; \ + else \ + { \ + product1 = interpolate_cb(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_cb(colorA, colorC); \ + product = interpolate_cb(colorA, colorB); \ + r += result_cb(colorA, colorB, colorG, colorE); \ + r += result_cb(colorB, colorA, colorK, colorF); \ + r += result_cb(colorB, colorA, colorH, colorN); \ + r += result_cb(colorA, colorB, colorL, colorO); \ + if (r > 0) \ + product2 = colorA; \ + else if (r < 0) \ + product2 = colorB; \ + else \ + { \ + product2 = interpolate2_cb(colorA, colorB, colorC, colorD); \ + } \ + } \ + } \ + else \ + { \ + product2 = interpolate2_cb(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_cb(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_cb(colorA, colorC); \ + } \ + } \ + out[0] = colorA; \ + out[1] = product; \ + out[dst_stride] = product1; \ + out[dst_stride + 1] = product2; \ + ++in; \ + out += 2 +#endif + +void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride) +{ + unsigned finish; + for(; height; height--) { + uint32_t *in = (uint32_t*)src; + uint32_t *out = (uint32_t*)dst; + + for(finish = width; finish; finish -= 1) { + twoxsai_declare_variables(uint32_t, in, (height > 1 ? src_stride : 0)); + + /* + * Map of the pixels: I|E F|J + * G|A B|K + * H|C D|L + * M|N O|P + */ + + twoxsai_function(twoxsai_result, twoxsai_interpolate_xrgb8888, twoxsai_interpolate2_xrgb8888); + } + + src += src_stride; + dst += 2 * dst_stride; + } +} diff --git a/Utilities/KreedSaiEagle/SaiEagle.h b/Utilities/KreedSaiEagle/SaiEagle.h new file mode 100644 index 00000000..129f6b1c --- /dev/null +++ b/Utilities/KreedSaiEagle/SaiEagle.h @@ -0,0 +1,7 @@ +#pragma once +#include "../stdafx.h" + +extern void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride); +extern void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride); +extern void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride); + diff --git a/Utilities/KreedSaiEagle/Super2xSai.cpp b/Utilities/KreedSaiEagle/Super2xSai.cpp new file mode 100644 index 00000000..d631dccf --- /dev/null +++ b/Utilities/KreedSaiEagle/Super2xSai.cpp @@ -0,0 +1,138 @@ +/* This is a heavily modified version of the file used in RetroArch */ + +/* RetroArch - A frontend for libretro. +* Copyright (C) 2010-2014 - Hans-Kristian Arntzen +* Copyright (C) 2010-2014 - Daniel De Matteis +* +* RetroArch 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 Found- +* ation, either version 3 of the License, or (at your option) any later version. +* +* RetroArch 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 RetroArch. +* If not, see . +*/ + +#include "stdafx.h" +#include "../stdafx.h" + +#define supertwoxsai_interpolate_xrgb8888(A, B) ((((A) & 0xFEFEFEFE) >> 1) + (((B) & 0xFEFEFEFE) >> 1) + ((A) & (B) & 0x01010101)) + +#define supertwoxsai_interpolate2_xrgb8888(A, B, C, D) ((((A) & 0xFCFCFCFC) >> 2) + (((B) & 0xFCFCFCFC) >> 2) + (((C) & 0xFCFCFCFC) >> 2) + (((D) & 0xFCFCFCFC) >> 2) + (((((A) & 0x03030303) + ((B) & 0x03030303) + ((C) & 0x03030303) + ((D) & 0x03030303)) >> 2) & 0x03030303)) + +#define supertwoxsai_interpolate_rgb565(A, B) ((((A) & 0xF7DE) >> 1) + (((B) & 0xF7DE) >> 1) + ((A) & (B) & 0x0821)); + +#define supertwoxsai_interpolate2_rgb565(A, B, C, D) ((((A) & 0xE79C) >> 2) + (((B) & 0xE79C) >> 2) + (((C) & 0xE79C) >> 2) + (((D) & 0xE79C) >> 2) + (((((A) & 0x1863) + ((B) & 0x1863) + ((C) & 0x1863) + ((D) & 0x1863)) >> 2) & 0x1863)) + +#define supertwoxsai_result(A, B, C, D) (((A) != (C) || (A) != (D)) - ((B) != (C) || (B) != (D))) + +#ifndef supertwoxsai_declare_variables +#define supertwoxsai_declare_variables(typename_t, in, nextline) \ + typename_t product1a, product1b, product2a, product2b; \ + const typename_t colorB0 = *(in - nextline - 1); \ + const typename_t colorB1 = *(in - nextline + 0); \ + const typename_t colorB2 = *(in - nextline + 1); \ + const typename_t colorB3 = *(in - nextline + 2); \ + const typename_t color4 = *(in - 1); \ + const typename_t color5 = *(in + 0); \ + const typename_t color6 = *(in + 1); \ + const typename_t colorS2 = *(in + 2); \ + const typename_t color1 = *(in + nextline - 1); \ + const typename_t color2 = *(in + nextline + 0); \ + const typename_t color3 = *(in + nextline + 1); \ + const typename_t colorS1 = *(in + nextline + 2); \ + const typename_t colorA0 = *(in + nextline + nextline - 1); \ + const typename_t colorA1 = *(in + nextline + nextline + 0); \ + const typename_t colorA2 = *(in + nextline + nextline + 1); \ + const typename_t colorA3 = *(in + nextline + nextline + 2) +#endif + +#ifndef supertwoxsai_function +#define supertwoxsai_function(result_cb, interpolate_cb, interpolate2_cb) \ + 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 += result_cb(color6, color5, color1, colorA1); \ + r += result_cb(color6, color5, color4, colorB1); \ + r += result_cb(color6, color5, colorA2, colorS1); \ + r += result_cb(color6, color5, colorB2, colorS2); \ + if (r > 0) \ + product2b = product1b = color6; \ + else if (r < 0) \ + product2b = product1b = color5; \ + else \ + product2b = product1b = interpolate_cb(color5, color6); \ + } \ + else \ + { \ + if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) \ + product2b = interpolate2_cb(color3, color3, color3, color2); \ + else if ((color5 == color2 && color2 == colorA2) & (colorA1 != color3 && color2 != colorA3)) \ + product2b = interpolate2_cb(color2, color2, color2, color3); \ + else \ + product2b = interpolate_cb(color2, color3); \ + if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) \ + product1b = interpolate2_cb(color6, color6, color6, color5); \ + else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) \ + product1b = interpolate2_cb(color6, color5, color5, color5); \ + else \ + product1b = interpolate_cb(color5, color6); \ + } \ + if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) \ + { \ + product2a = interpolate_cb(color2, color5); \ + } \ + else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) \ + { \ + product2a = interpolate_cb(color2, color5); \ + } \ + else \ + product2a = color2; \ + if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) \ + { \ + product1a = interpolate_cb(color2, color5); \ + } \ + else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) \ + { \ + product1a = interpolate_cb(color2, color5); \ + } \ + else \ + product1a = color5; \ + out[0] = product1a; \ + out[1] = product1b; \ + out[dst_stride] = product2a; \ + out[dst_stride + 1] = product2b; \ + ++in; \ + out += 2 +#endif + +void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride) +{ + unsigned finish; + for(; height; height--) { + uint32_t *in = (uint32_t*)src; + uint32_t *out = (uint32_t*)dst; + + for(finish = width; finish; finish -= 1) { + supertwoxsai_declare_variables(uint32_t, in, (height > 1 ? src_stride : 0)); + + //--------------------------- B1 B2 + // 4 5 6 S2 + // 1 2 3 S1 + // A1 A2 + //-------------------------------------- + + supertwoxsai_function(supertwoxsai_result, supertwoxsai_interpolate_xrgb8888, supertwoxsai_interpolate2_xrgb8888); + } + + src += src_stride; + dst += 2 * dst_stride; + } +} \ No newline at end of file diff --git a/Utilities/KreedSaiEagle/SuperEagle.cpp b/Utilities/KreedSaiEagle/SuperEagle.cpp new file mode 100644 index 00000000..7751d563 --- /dev/null +++ b/Utilities/KreedSaiEagle/SuperEagle.cpp @@ -0,0 +1,149 @@ +/* This is a heavily modified version of the file used in RetroArch */ + +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2014 - Daniel De Matteis + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include "stdafx.h" +#include "../stdafx.h" + +#define supereagle_interpolate_xrgb8888(A, B) ((((A) & 0xFEFEFEFE) >> 1) + (((B) & 0xFEFEFEFE) >> 1) + ((A) & (B) & 0x01010101)) + +#define supereagle_interpolate2_xrgb8888(A, B, C, D) ((((A) & 0xFCFCFCFC) >> 2) + (((B) & 0xFCFCFCFC) >> 2) + (((C) & 0xFCFCFCFC) >> 2) + (((D) & 0xFCFCFCFC) >> 2) + (((((A) & 0x03030303) + ((B) & 0x03030303) + ((C) & 0x03030303) + ((D) & 0x03030303)) >> 2) & 0x03030303)) + +#define supereagle_interpolate_rgb565(A, B) ((((A) & 0xF7DE) >> 1) + (((B) & 0xF7DE) >> 1) + ((A) & (B) & 0x0821)); + +#define supereagle_interpolate2_rgb565(A, B, C, D) ((((A) & 0xE79C) >> 2) + (((B) & 0xE79C) >> 2) + (((C) & 0xE79C) >> 2) + (((D) & 0xE79C) >> 2) + (((((A) & 0x1863) + ((B) & 0x1863) + ((C) & 0x1863) + ((D) & 0x1863)) >> 2) & 0x1863)) + +#define supereagle_result(A, B, C, D) (((A) != (C) || (A) != (D)) - ((B) != (C) || (B) != (D))); + +#define supereagle_declare_variables(typename_t, in, nextline) \ + typename_t product1a, product1b, product2a, product2b; \ + const typename_t colorB1 = *(in - nextline + 0); \ + const typename_t colorB2 = *(in - nextline + 1); \ + const typename_t color4 = *(in - 1); \ + const typename_t color5 = *(in + 0); \ + const typename_t color6 = *(in + 1); \ + const typename_t colorS2 = *(in + 2); \ + const typename_t color1 = *(in + nextline - 1); \ + const typename_t color2 = *(in + nextline + 0); \ + const typename_t color3 = *(in + nextline + 1); \ + const typename_t colorS1 = *(in + nextline + 2); \ + const typename_t colorA1 = *(in + nextline + nextline + 0); \ + const typename_t colorA2 = *(in + nextline + nextline + 1) + +#ifndef supereagle_function +#define supereagle_function(result_cb, interpolate_cb, interpolate2_cb) \ + if (color2 == color6 && color5 != color3) \ + { \ + product1b = product2a = color2; \ + if ((color1 == color2) || (color6 == colorB2)) \ + { \ + product1a = interpolate_cb(color2, color5); \ + product1a = interpolate_cb(color2, product1a); \ + } \ + else \ + { \ + product1a = interpolate_cb(color5, color6); \ + } \ + if ((color6 == colorS2) || (color2 == colorA1)) \ + { \ + product2b = interpolate_cb(color2, color3); \ + product2b = interpolate_cb(color2, product2b); \ + } \ + else \ + { \ + product2b = interpolate_cb(color2, color3); \ + } \ + } \ + else if (color5 == color3 && color2 != color6) \ + { \ + product2b = product1a = color5; \ + if ((colorB1 == color5) || (color3 == colorS1)) \ + { \ + product1b = interpolate_cb(color5, color6); \ + product1b = interpolate_cb(color5, product1b); \ + } \ + else \ + { \ + product1b = interpolate_cb(color5, color6); \ + } \ + if ((color3 == colorA2) || (color4 == color5)) \ + { \ + product2a = interpolate_cb(color5, color2); \ + product2a = interpolate_cb(color5, product2a); \ + } \ + else \ + { \ + product2a = interpolate_cb(color2, color3); \ + } \ + } \ + else if (color5 == color3 && color2 == color6) \ + { \ + int r = 0; \ + r += supereagle_result(color6, color5, color1, colorA1); \ + r += supereagle_result(color6, color5, color4, colorB1); \ + r += supereagle_result(color6, color5, colorA2, colorS1); \ + r += supereagle_result(color6, color5, colorB2, colorS2); \ + if (r > 0) \ + { \ + product1b = product2a = color2; \ + product1a = product2b = interpolate_cb(color5, color6); \ + } \ + else if (r < 0) \ + { \ + product2b = product1a = color5; \ + product1b = product2a = interpolate_cb(color5, color6); \ + } \ + else \ + { \ + product2b = product1a = color5; \ + product1b = product2a = color2; \ + } \ + } \ + else \ + { \ + product2b = product1a = interpolate_cb(color2, color6); \ + product2b = interpolate2_cb(color3, color3, color3, product2b); \ + product1a = interpolate2_cb(color5, color5, color5, product1a); \ + product2a = product1b = interpolate_cb(color5, color3); \ + product2a = interpolate2_cb(color2, color2, color2, product2a); \ + product1b = interpolate2_cb(color6, color6, color6, product1b); \ + } \ + out[0] = product1a; \ + out[1] = product1b; \ + out[dst_stride] = product2a; \ + out[dst_stride + 1] = product2b; \ + ++in; \ + out += 2 +#endif + +void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride) +{ + unsigned finish; + for(; height; height--) { + uint32_t *in = (uint32_t*)src; + uint32_t *out = (uint32_t*)dst; + + for(finish = width; finish; finish -= 1) { + supereagle_declare_variables(uint32_t, in, (height > 1 ? src_stride : 0)); + + supereagle_function(supereagle_result, supereagle_interpolate_xrgb8888, supereagle_interpolate2_xrgb8888); + } + + src += src_stride; + dst += 2 * dst_stride; + } +} \ No newline at end of file diff --git a/Utilities/Scale2x/scale2x.cpp b/Utilities/Scale2x/scale2x.cpp new file mode 100644 index 00000000..005e00b8 --- /dev/null +++ b/Utilities/Scale2x/scale2x.cpp @@ -0,0 +1,662 @@ +/* + * 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. + */ + +/* + * This file contains a C and MMX implementation of the Scale2x effect. + * + * You can find an high level description of the effect at : + * + * http://www.scale2x.it/ + */ + +#include "stdafx.h" +#include "../stdafx.h" + +#if HAVE_CONFIG_H +#include +#endif + +#include "scale2x.h" + +#include + +/***************************************************************************/ +/* Scale2x C implementation */ + +/** + * Define the macro USE_SCALE_RANDOMWRITE to enable + * an optimized version which writes memory in random order. + * This version is a little faster if you write in system memory. + * But it's a lot slower if you write in video memory. + * So, enable it only if you are sure to never write directly in video memory. + */ +/* #define USE_SCALE_RANDOMWRITE */ + +static inline void scale2x_8_def_whole(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst0[0] = src1[0] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[1] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[0] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[1] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src0[0] != src2[0] && src1[-1] != src1[1]) { + dst0[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[1] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[-1] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[1] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst0[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[0] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[-1] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[0] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } +} + +static inline void scale2x_8_def_border(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = src1[0] == 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; + + /* central pixels */ + count -= 2; + 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; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst[1] = src1[0] == src0[0] ? src0[0] : src1[0]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + } +} + +static inline void scale2x_8_def_center(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = src1[0]; + dst[1] = (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]; + } + ++src0; + ++src1; + ++src2; + dst += 2; + + /* central pixels */ + count -= 2; + 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[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]; + } + + ++src0; + ++src1; + ++src2; + dst += 2; + --count; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + 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]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + } +} + +static inline void scale2x_16_def_whole(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst0[0] = src1[0] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[1] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[0] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[1] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src0[0] != src2[0] && src1[-1] != src1[1]) { + dst0[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[1] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[-1] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[1] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst0[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[0] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[-1] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[0] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } +} + +static inline void scale2x_16_def_border(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = src1[0] == 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; + + /* central pixels */ + count -= 2; + 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; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst[1] = src1[0] == src0[0] ? src0[0] : src1[0]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + } +} + +static inline void scale2x_16_def_center(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = src1[0]; + dst[1] = (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]; + } + ++src0; + ++src1; + ++src2; + dst += 2; + + /* central pixels */ + count -= 2; + 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[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]; + } + + ++src0; + ++src1; + ++src2; + dst += 2; + --count; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + 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]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + } +} + +static inline void scale2x_32_def_whole(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst0[0] = src1[0] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[1] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[0] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[1] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src0[0] != src2[0] && src1[-1] != src1[1]) { + dst0[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[1] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[-1] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[1] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst0[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[0] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[-1] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[0] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } +} + +static inline void scale2x_32_def_border(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = src1[0] == 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; + + /* central pixels */ + count -= 2; + 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; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst[1] = src1[0] == src0[0] ? src0[0] : src1[0]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + } +} + +static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = src1[0]; + dst[1] = (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]; + } + ++src0; + ++src1; + ++src2; + dst += 2; + + /* central pixels */ + count -= 2; + 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[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]; + } + + ++src0; + ++src1; + ++src2; + dst += 2; + --count; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + 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]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + } +} + +/** + * 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. + * Note that the implementation is optimized to write data sequentially to + * maximize the bandwidth on video memory. + * \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) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale2x_8_def_whole(dst0, dst1, src0, src1, src2, count); +#else + scale2x_8_def_border(dst0, src0, src1, src2, count); + scale2x_8_def_border(dst1, src2, src1, src0, count); +#endif +} + +/** + * 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) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale2x_16_def_whole(dst0, dst1, src0, src1, src2, count); +#else + scale2x_16_def_border(dst0, src0, src1, src2, count); + scale2x_16_def_border(dst1, src2, src1, src0, count); +#endif +} + +/** + * 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) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale2x_32_def_whole(dst0, dst1, src0, src1, src2, count); +#else + scale2x_32_def_border(dst0, src0, src1, src2, count); + scale2x_32_def_border(dst1, src2, src1, src0, count); +#endif +} + +/** + * Scale by a factor of 2x3 a row of pixels of 8 bits. + * \note Like scale2x_8_def(); + */ +void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale2x_8_def_whole(dst0, dst2, src0, src1, src2, count); + scale2x_8_def_center(dst1, src0, src1, src2, count); +#else + scale2x_8_def_border(dst0, src0, src1, src2, count); + scale2x_8_def_center(dst1, src0, src1, src2, count); + scale2x_8_def_border(dst2, src2, src1, src0, count); +#endif +} + +/** + * Scale by a factor of 2x3 a row of pixels of 16 bits. + * \note Like scale2x_16_def(); + */ +void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale2x_16_def_whole(dst0, dst2, src0, src1, src2, count); + scale2x_16_def_center(dst1, src0, src1, src2, count); +#else + scale2x_16_def_border(dst0, src0, src1, src2, count); + scale2x_16_def_center(dst1, src0, src1, src2, count); + scale2x_16_def_border(dst2, src2, src1, src0, count); +#endif +} + +/** + * Scale by a factor of 2x3 a row of pixels of 32 bits. + * \note Like scale2x_32_def(); + */ +void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale2x_32_def_whole(dst0, dst2, src0, src1, src2, count); + scale2x_32_def_center(dst1, src0, src1, src2, count); +#else + scale2x_32_def_border(dst0, src0, src1, src2, count); + scale2x_32_def_center(dst1, src0, src1, src2, count); + scale2x_32_def_border(dst2, src2, src1, src0, count); +#endif +} + +/** + * Scale by a factor of 2x4 a row of pixels of 8 bits. + * \note Like scale2x_8_def(); + */ +void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale2x_8_def_whole(dst0, dst3, src0, src1, src2, count); + scale2x_8_def_center(dst1, src0, src1, src2, count); + scale2x_8_def_center(dst2, src0, src1, src2, count); +#else + scale2x_8_def_border(dst0, src0, src1, src2, count); + scale2x_8_def_center(dst1, src0, src1, src2, count); + scale2x_8_def_center(dst2, src0, src1, src2, count); + scale2x_8_def_border(dst3, src2, src1, src0, count); +#endif +} + +/** + * Scale by a factor of 2x4 a row of pixels of 16 bits. + * \note Like scale2x_16_def(); + */ +void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale2x_16_def_whole(dst0, dst3, src0, src1, src2, count); + scale2x_16_def_center(dst1, src0, src1, src2, count); + scale2x_16_def_center(dst2, src0, src1, src2, count); +#else + scale2x_16_def_border(dst0, src0, src1, src2, count); + scale2x_16_def_center(dst1, src0, src1, src2, count); + scale2x_16_def_center(dst2, src0, src1, src2, count); + scale2x_16_def_border(dst3, src2, src1, src0, count); +#endif +} + +/** + * Scale by a factor of 2x4 a row of pixels of 32 bits. + * \note Like scale2x_32_def(); + */ +void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale2x_32_def_whole(dst0, dst3, src0, src1, src2, count); + scale2x_32_def_center(dst1, src0, src1, src2, count); + scale2x_32_def_center(dst2, src0, src1, src2, count); +#else + scale2x_32_def_border(dst0, src0, src1, src2, count); + scale2x_32_def_center(dst1, src0, src1, src2, count); + scale2x_32_def_center(dst2, src0, src1, src2, count); + scale2x_32_def_border(dst3, src2, src1, src0, count); +#endif +} diff --git a/Utilities/Scale2x/scale2x.h b/Utilities/Scale2x/scale2x.h new file mode 100644 index 00000000..df1b72ca --- /dev/null +++ b/Utilities/Scale2x/scale2x.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef __SCALE2X_H +#define __SCALE2X_H + +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); + +void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count); +void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count); +void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count); + +void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count); +void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count); +void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3, 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); + +void scale2x3_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count); +void scale2x3_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count); +void scale2x3_32_mmx(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count); + +void scale2x4_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count); +void scale2x4_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count); +void scale2x4_32_mmx(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3, 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 + +#endif + diff --git a/Utilities/Scale2x/scale3x.cpp b/Utilities/Scale2x/scale3x.cpp new file mode 100644 index 00000000..3bee221d --- /dev/null +++ b/Utilities/Scale2x/scale3x.cpp @@ -0,0 +1,697 @@ +/* + * 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. + */ + +/* + * This file contains a C and MMX implementation of the Scale2x effect. + * + * You can find an high level description of the effect at : + * + * http://www.scale2x.it/ + */ + +#include "stdafx.h" +#include "../stdafx.h" + +#if HAVE_CONFIG_H +#include +#endif + +#include "scale3x.h" + +#include + +/***************************************************************************/ +/* Scale3x C implementation */ + +/** + * Define the macro USE_SCALE_RANDOMWRITE to enable + * an optimized version which writes memory in random order. + * This version is a little faster if you write in system memory. + * But it's a lot slower if you write in video memory. + * So, enable it only if you are sure to never write directly in video memory. + */ +/* #define USE_SCALE_RANDOMWRITE */ + +static inline void scale3x_8_def_whole(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst0[0] = src1[0]; + dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0]; + dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0]; + dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; + dst2[0] = src1[0]; + dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0]; + dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } + ++src0; + ++src1; + ++src2; + dst0 += 3; + dst1 += 3; + dst2 += 3; + + /* central pixels */ + count -= 2; + while (count) { + if (src0[0] != src2[0] && src1[-1] != src1[1]) { + dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0]; + dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; + dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0]; + dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0]; + dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } + + ++src0; + ++src1; + ++src2; + dst0 += 3; + dst1 += 3; + dst2 += 3; + --count; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst0[2] = src1[0]; + dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0]; + dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0]; + dst2[2] = src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } +} + +static inline void scale3x_8_def_border(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = src1[0]; + dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? 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; + + /* central pixels */ + count -= 2; + 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; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst[2] = src1[0]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + dst[2] = src1[0]; + } +} + +static inline void scale3x_8_def_center(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : 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; + + /* central pixels */ + count -= 2; + 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; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + 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[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + dst[2] = src1[0]; + } +} + +static inline void scale3x_16_def_whole(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst0[0] = src1[0]; + dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0]; + dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0]; + dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; + dst2[0] = src1[0]; + dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0]; + dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } + ++src0; + ++src1; + ++src2; + dst0 += 3; + dst1 += 3; + dst2 += 3; + + /* central pixels */ + count -= 2; + while (count) { + if (src0[0] != src2[0] && src1[-1] != src1[1]) { + dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0]; + dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; + dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0]; + dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0]; + dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } + + ++src0; + ++src1; + ++src2; + dst0 += 3; + dst1 += 3; + dst2 += 3; + --count; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst0[2] = src1[0]; + dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0]; + dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0]; + dst2[2] = src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } +} + +static inline void scale3x_16_def_border(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = src1[0]; + dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? 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; + + /* central pixels */ + count -= 2; + 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; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst[2] = src1[0]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + dst[2] = src1[0]; + } +} + +static inline void scale3x_16_def_center(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : 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; + + /* central pixels */ + count -= 2; + 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; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + 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[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + dst[2] = src1[0]; + } +} + +static inline void scale3x_32_def_whole(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst0[0] = src1[0]; + dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0]; + dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0]; + dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; + dst2[0] = src1[0]; + dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0]; + dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } + ++src0; + ++src1; + ++src2; + dst0 += 3; + dst1 += 3; + dst2 += 3; + + /* central pixels */ + count -= 2; + while (count) { + if (src0[0] != src2[0] && src1[-1] != src1[1]) { + dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0]; + dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; + dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0]; + dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0]; + dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } + + ++src0; + ++src1; + ++src2; + dst0 += 3; + dst1 += 3; + dst2 += 3; + --count; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst0[2] = src1[0]; + dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0]; + dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0]; + dst2[2] = src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } +} + +static inline void scale3x_32_def_border(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = src1[0]; + dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? 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; + + /* central pixels */ + count -= 2; + 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; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst[2] = src1[0]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + dst[2] = src1[0]; + } +} + +static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count) +{ + assert(count >= 2); + + /* first pixel */ + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : 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; + + /* central pixels */ + count -= 2; + 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; + } + + /* last pixel */ + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + 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[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + dst[2] = src1[0]; + } +} + +/** + * 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) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale3x_8_def_whole(dst0, dst1, dst2, src0, src1, src2, count); +#else + 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); +#endif +} + +/** + * 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) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale3x_16_def_whole(dst0, dst1, dst2, src0, src1, src2, count); +#else + 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); +#endif +} + +/** + * 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) +{ +#ifdef USE_SCALE_RANDOMWRITE + scale3x_32_def_whole(dst0, dst1, dst2, src0, src1, src2, count); +#else + 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); +#endif +} + diff --git a/Utilities/Scale2x/scale3x.h b/Utilities/Scale2x/scale3x.h new file mode 100644 index 00000000..895752a9 --- /dev/null +++ b/Utilities/Scale2x/scale3x.h @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#ifndef __SCALE3X_H +#define __SCALE3X_H + +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 + diff --git a/Utilities/Scale2x/scalebit.cpp b/Utilities/Scale2x/scalebit.cpp new file mode 100644 index 00000000..3c305982 --- /dev/null +++ b/Utilities/Scale2x/scalebit.cpp @@ -0,0 +1,505 @@ +/* + * This file is part of the Scale2x project. + * + * Copyright (C) 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. + */ + +/* + * 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://www.scale2x.it/ + */ + +#include "stdafx.h" +#include "../stdafx.h" + +#if HAVE_CONFIG_H +#include +#endif + +#include "scale2x.h" +#include "scale3x.h" + +#if HAVE_ALLOCA_H +#include +#endif + +#include +#include +#include + +#define SSDST(bits, num) (scale2x_uint##bits *)dst##num +#define SSSRC(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(SSDST(8,0), SSDST(8,1), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break; + case 2 : scale2x_16_mmx(SSDST(16,0), SSDST(16,1), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break; + case 4 : scale2x_32_mmx(SSDST(32,0), SSDST(32,1), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break; +#else + case 1 : scale2x_8_def(SSDST(8,0), SSDST(8,1), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break; + case 2 : scale2x_16_def(SSDST(16,0), SSDST(16,1), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break; + case 4 : scale2x_32_def(SSDST(32,0), SSDST(32,1), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break; +#endif + } +} + +/** + * Apply the Scale2x3 effect on a group of rows. Used internally. + */ +static inline void stage_scale2x3(void* dst0, void* dst1, void* dst2, 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 : scale2x3_8_mmx(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break; + case 2 : scale2x3_16_mmx(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break; + case 4 : scale2x3_32_mmx(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break; +#else + case 1 : scale2x3_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break; + case 2 : scale2x3_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break; + case 4 : scale2x3_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break; +#endif + } +} + +/** + * Apply the Scale2x4 effect on a group of rows. Used internally. + */ +static inline void stage_scale2x4(void* dst0, void* dst1, void* dst2, void* dst3, 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 : scale2x4_8_mmx(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSDST(8,3), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break; + case 2 : scale2x4_16_mmx(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSDST(16,3), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break; + case 4 : scale2x4_32_mmx(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSDST(32,3), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break; +#else + case 1 : scale2x4_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSDST(8,3), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break; + case 2 : scale2x4_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSDST(16,3), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break; + case 4 : scale2x4_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSDST(32,3), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break; +#endif + } +} + +/** + * 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(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break; + case 2 : scale3x_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break; + case 4 : scale3x_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); 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; + + stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width); + + dst = SCDST(2); + + count -= 2; + while (count) { + stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width); + + dst = SCDST(2); + src = SCSRC(1); + + --count; + } + + stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width); + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + scale2x_mmx_emms(); +#endif +} + +/** + * Apply the Scale2x3 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 2x3 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 scale2x3(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; + + stage_scale2x3(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width); + + dst = SCDST(3); + + count -= 2; + while (count) { + stage_scale2x3(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width); + + dst = SCDST(3); + src = SCSRC(1); + + --count; + } + + stage_scale2x3(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width); + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + scale2x_mmx_emms(); +#endif +} + +/** + * Apply the Scale2x4 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 2x4 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 scale2x4(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; + + stage_scale2x4(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width); + + dst = SCDST(4); + + count -= 2; + while (count) { + stage_scale2x4(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width); + + dst = SCDST(4); + src = SCSRC(1); + + --count; + } + + stage_scale2x4(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width); + +#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; + + stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width); + + dst = SCDST(3); + + count -= 2; + 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; + } + + stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width); +} + +/** + * 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 choice. + * \param void_dst Pointer at the first pixel of the destination bitmap. + * \param dst_slice Size in bytes of a destination bitmap row. + * \param void_mid Pointer at the first pixel of the buffer bitmap. + * \param mid_slice Size in bytes of a buffer bitmap row. + * \param void_src Pointer at the first pixel of the source bitmap. + * \param src_slice Size in bytes of a source bitmap row. + * \param pixel Bytes per pixel of the source and destination bitmap. + * \param width Horizontal size in pixels of the source bitmap. + * \param height Vertical size in pixels of the source bitmap. + */ +static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsigned mid_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) +{ + unsigned char* dst = (unsigned char*)void_dst; + const unsigned char* src = (const unsigned char*)void_src; + unsigned count; + unsigned char* mid[6]; + + assert(height >= 4); + + count = height; + + /* set the 6 buffer pointers */ + mid[0] = (unsigned char*)void_mid; + mid[1] = mid[0] + mid_slice; + mid[2] = mid[1] + mid_slice; + mid[3] = mid[2] + mid_slice; + mid[4] = mid[3] + mid_slice; + mid[5] = mid[4] + mid_slice; + + stage_scale2x(SCMID(-2+6), SCMID(-1+6), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width); + stage_scale2x(SCMID(0), SCMID(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width); + stage_scale2x(SCMID(2), SCMID(3), SCSRC(1), SCSRC(2), SCSRC(3), pixel, width); + stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(-2+6), SCMID(-2+6), SCMID(-1+6), SCMID(0), pixel, width); + + dst = SCDST(4); + + stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(-1+6), SCMID(0), SCMID(1), SCMID(2), pixel, width); + + dst = SCDST(4); + + count -= 4; + 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; + } + + stage_scale2x(SCMID(4), SCMID(5), SCSRC(2), SCSRC(3), SCSRC(3), 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); + + stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(3), SCMID(4), SCMID(5), SCMID(5), pixel, width); + +#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 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 !HAVE_ALLOCA + free(mid); +#endif +} + +/** + * Check if the scale implementation is applicable at the given arguments. + * \param scale Scale factor. 2, 203 (fox 2x3), 204 (for 2x4), 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 (pixel != 1 && pixel != 2 && pixel != 4) + return -1; + + switch (scale) { + case 202 : + case 203 : + case 204 : + case 2 : + case 303 : + case 3 : + if (height < 2) + return -1; + break; + case 404 : + case 4 : + if (height < 4) + return -1; + break; + default: + return -1; + } + + if (width < 2) + return -1; + + 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, 203 (fox 2x3), 204 (for 2x4), 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 202 : + case 2 : + scale2x(void_dst, dst_slice, void_src, src_slice, pixel, width, height); + break; + case 203 : + scale2x3(void_dst, dst_slice, void_src, src_slice, pixel, width, height); + break; + case 204 : + scale2x4(void_dst, dst_slice, void_src, src_slice, pixel, width, height); + break; + case 303 : + case 3 : + scale3x(void_dst, dst_slice, void_src, src_slice, pixel, width, height); + break; + case 404 : + case 4 : + scale4x(void_dst, dst_slice, void_src, src_slice, pixel, width, height); + break; + } +} + diff --git a/Utilities/Scale2x/scalebit.h b/Utilities/Scale2x/scalebit.h new file mode 100644 index 00000000..29dd5f57 --- /dev/null +++ b/Utilities/Scale2x/scalebit.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/* + * 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://www.scale2x.it/ + */ + +#ifndef __SCALEBIT_H +#define __SCALEBIT_H + +int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned height); +void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height); + +#endif + diff --git a/Utilities/Utilities.vcxproj b/Utilities/Utilities.vcxproj index f5c64b97..f3940de2 100644 --- a/Utilities/Utilities.vcxproj +++ b/Utilities/Utilities.vcxproj @@ -388,7 +388,10 @@ + + + @@ -397,6 +400,9 @@ + + + @@ -404,6 +410,8 @@ + + @@ -411,12 +419,22 @@ + + + + + + + + + + @@ -434,6 +452,7 @@ + diff --git a/Utilities/Utilities.vcxproj.filters b/Utilities/Utilities.vcxproj.filters index f0920363..b2b08f07 100644 --- a/Utilities/Utilities.vcxproj.filters +++ b/Utilities/Utilities.vcxproj.filters @@ -9,6 +9,18 @@ {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd + + {34df7dd9-5f1b-4aec-9212-1b70f1fada59} + + + {c29925fd-7698-4db8-a328-73ef7f8993a9} + + + {87329bd1-28ac-4ced-a4c2-b51777018d16} + + + {8e159744-fb91-4e16-aa82-8d8703ba2762} + @@ -74,6 +86,30 @@ Header Files + + xBRZ + + + xBRZ + + + HQX + + + HQX + + + Scale2x + + + Scale2x + + + Scale2x + + + KreedSaiEagle + @@ -127,5 +163,38 @@ Source Files + + xBRZ + + + HQX + + + HQX + + + HQX + + + HQX + + + Scale2x + + + Scale2x + + + Scale2x + + + KreedSaiEagle + + + KreedSaiEagle + + + KreedSaiEagle + \ No newline at end of file diff --git a/Utilities/xBRZ/config.h b/Utilities/xBRZ/config.h new file mode 100644 index 00000000..824ed5a2 --- /dev/null +++ b/Utilities/xBRZ/config.h @@ -0,0 +1,33 @@ +// **************************************************************************** +// * This file is part of the HqMAME project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * +// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * +// * * +// * Additionally and as a special exception, the author gives permission * +// * to link the code of this program with the MAME library (or with modified * +// * versions of MAME that use the same license as MAME), and distribute * +// * linked combinations including the two. You must obey the GNU General * +// * Public License in all respects for all of the code used other than MAME. * +// * If you modify this file, you may extend this exception to your version * +// * of the file, but you are not obligated to do so. If you do not wish to * +// * do so, delete this exception statement from your version. * +// **************************************************************************** + +#ifndef XBRZ_CONFIG_HEADER_284578425345 +#define XBRZ_CONFIG_HEADER_284578425345 + +//do NOT include any headers here! used by xBRZ_dll!!! + +namespace xbrz +{ +struct ScalerCfg +{ + double luminanceWeight = 1; + double equalColorTolerance = 30; + double dominantDirectionThreshold = 3.6; + double steepDirectionThreshold = 2.2; + double newTestAttribute = 0; //unused; test new parameters +}; +} + +#endif \ No newline at end of file diff --git a/Utilities/xBRZ/xbrz.cpp b/Utilities/xBRZ/xbrz.cpp new file mode 100644 index 00000000..9fa1572c --- /dev/null +++ b/Utilities/xBRZ/xbrz.cpp @@ -0,0 +1,1215 @@ +// **************************************************************************** +// * This file is part of the HqMAME project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * +// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * +// * * +// * Additionally and as a special exception, the author gives permission * +// * to link the code of this program with the MAME library (or with modified * +// * versions of MAME that use the same license as MAME), and distribute * +// * linked combinations including the two. You must obey the GNU General * +// * Public License in all respects for all of the code used other than MAME. * +// * If you modify this file, you may extend this exception to your version * +// * of the file, but you are not obligated to do so. If you do not wish to * +// * do so, delete this exception statement from your version. * +// **************************************************************************** + +#include "stdafx.h" +#include "../stdafx.h" +#include "xbrz.h" +#include +#include +#include + +namespace +{ +template inline +unsigned char getByte(uint32_t val) { return static_cast((val >> (8 * N)) & 0xff); } + +inline unsigned char getAlpha(uint32_t pix) { return getByte<3>(pix); } +inline unsigned char getRed (uint32_t pix) { return getByte<2>(pix); } +inline unsigned char getGreen(uint32_t pix) { return getByte<1>(pix); } +inline unsigned char getBlue (uint32_t pix) { return getByte<0>(pix); } + +inline uint32_t makePixel( unsigned char r, unsigned char g, unsigned char b) { return (r << 16) | (g << 8) | b; } +inline uint32_t makePixel(unsigned char a, unsigned char r, unsigned char g, unsigned char b) { return (a << 24) | (r << 16) | (g << 8) | b; } + + +template inline +uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) //blend front color with opacity M / N over opaque background: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending +{ + static_assert(0 < M && M < N && N <= 1000, ""); + + auto calcColor = [](unsigned char colFront, unsigned char colBack) -> unsigned char { return (colFront * M + colBack * (N - M)) / N; }; + + return makePixel(calcColor(getRed (pixFront), getRed (pixBack)), + calcColor(getGreen(pixFront), getGreen(pixBack)), + calcColor(getBlue (pixFront), getBlue (pixBack))); +} + + +template inline +uint32_t gradientARGB(uint32_t pixFront, uint32_t pixBack) //find intermediate color between two colors with alpha channels (=> NO alpha blending!!!) +{ + static_assert(0 < M && M < N && N <= 1000, ""); + + const unsigned int weightFront = getAlpha(pixFront) * M; + const unsigned int weightBack = getAlpha(pixBack) * (N - M); + const unsigned int weightSum = weightFront + weightBack; + if (weightSum == 0) + return 0; + + auto calcColor = [=](unsigned char colFront, unsigned char colBack) + { + return static_cast((colFront * weightFront + colBack * weightBack) / weightSum); + }; + + return makePixel(static_cast(weightSum / N), + calcColor(getRed (pixFront), getRed (pixBack)), + calcColor(getGreen(pixFront), getGreen(pixBack)), + calcColor(getBlue (pixFront), getBlue (pixBack))); +} + + +//inline +//double fastSqrt(double n) +//{ +// __asm //speeds up xBRZ by about 9% compared to std::sqrt which internally uses the same assembler instructions but adds some "fluff" +// { +// fld n +// fsqrt +// } +//} +// + + +uint32_t* byteAdvance( uint32_t* ptr, int bytes) { return reinterpret_cast< uint32_t*>(reinterpret_cast< char*>(ptr) + bytes); } +const uint32_t* byteAdvance(const uint32_t* ptr, int bytes) { return reinterpret_cast(reinterpret_cast(ptr) + bytes); } + + +//fill block with the given color +inline +void fillBlock(uint32_t* trg, int pitch, uint32_t col, int blockWidth, int blockHeight) +{ + //for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch)) + // std::fill(trg, trg + blockWidth, col); + + for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch)) + for (int x = 0; x < blockWidth; ++x) + trg[x] = col; +} + +inline +void fillBlock(uint32_t* trg, int pitch, uint32_t col, int n) { fillBlock(trg, pitch, col, n, n); } + + +#ifdef _MSC_VER + #define FORCE_INLINE __forceinline +#elif defined __GNUC__ + #define FORCE_INLINE __attribute__((always_inline)) inline +#else + #define FORCE_INLINE inline +#endif + + +enum RotationDegree //clock-wise +{ + ROT_0, + ROT_90, + ROT_180, + ROT_270 +}; + +//calculate input matrix coordinates after rotation at compile time +template +struct MatrixRotation; + +template +struct MatrixRotation +{ + static const size_t I_old = I; + static const size_t J_old = J; +}; + +template //(i, j) = (row, col) indices, N = size of (square) matrix +struct MatrixRotation +{ + static const size_t I_old = N - 1 - MatrixRotation(rotDeg - 1), I, J, N>::J_old; //old coordinates before rotation! + static const size_t J_old = MatrixRotation(rotDeg - 1), I, J, N>::I_old; // +}; + + +template +class OutputMatrix +{ +public: + OutputMatrix(uint32_t* out, int outWidth) : //access matrix area, top-left at position "out" for image with given width + out_(out), + outWidth_(outWidth) {} + + template + uint32_t& ref() const + { + static const size_t I_old = MatrixRotation::I_old; + static const size_t J_old = MatrixRotation::J_old; + return *(out_ + J_old + I_old * outWidth_); + } + +private: + uint32_t* out_; + const int outWidth_; +}; + + +template inline +T square(T value) { return value * value; } + + + +inline +double distRGB(uint32_t pix1, uint32_t pix2) +{ + const double r_diff = static_cast(getRed (pix1)) - getRed (pix2); + const double g_diff = static_cast(getGreen(pix1)) - getGreen(pix2); + const double b_diff = static_cast(getBlue (pix1)) - getBlue (pix2); + + //euklidean RGB distance + return std::sqrt(square(r_diff) + square(g_diff) + square(b_diff)); +} + + +inline +double distYCbCr(uint32_t pix1, uint32_t pix2, double lumaWeight) +{ + //http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion + //YCbCr conversion is a matrix multiplication => take advantage of linearity by subtracting first! + const int r_diff = static_cast(getRed (pix1)) - getRed (pix2); //we may delay division by 255 to after matrix multiplication + const int g_diff = static_cast(getGreen(pix1)) - getGreen(pix2); // + const int b_diff = static_cast(getBlue (pix1)) - getBlue (pix2); //substraction for int is noticeable faster than for double! + + //const double k_b = 0.0722; //ITU-R BT.709 conversion + //const double k_r = 0.2126; // + const double k_b = 0.0593; //ITU-R BT.2020 conversion + const double k_r = 0.2627; // + const double k_g = 1 - k_b - k_r; + + const double scale_b = 0.5 / (1 - k_b); + const double scale_r = 0.5 / (1 - k_r); + + const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff; //[!], analog YCbCr! + const double c_b = scale_b * (b_diff - y); + const double c_r = scale_r * (r_diff - y); + + //we skip division by 255 to have similar range like other distance functions + return std::sqrt(square(lumaWeight * y) + square(c_b) + square(c_r)); +} + + +struct DistYCbCrBuffer //30% perf boost compared to distYCbCr()! +{ +public: + static double dist(uint32_t pix1, uint32_t pix2) + { +#if defined _MSC_VER && _MSC_VER < 1900 +#error function scope static initialization is not yet thread-safe! +#endif + static const DistYCbCrBuffer inst; + return inst.distImpl(pix1, pix2); + } + +private: + DistYCbCrBuffer() : buffer(256 * 256 * 256) + { + for (uint32_t i = 0; i < 256 * 256 * 256; ++i) //startup time: 114 ms on Intel Core i5 (four cores) + { + const int r_diff = getByte<2>(i) * 2 - 255; + const int g_diff = getByte<1>(i) * 2 - 255; + const int b_diff = getByte<0>(i) * 2 - 255; + + const double k_b = 0.0593; //ITU-R BT.2020 conversion + const double k_r = 0.2627; // + const double k_g = 1 - k_b - k_r; + + const double scale_b = 0.5 / (1 - k_b); + const double scale_r = 0.5 / (1 - k_r); + + const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff; //[!], analog YCbCr! + const double c_b = scale_b * (b_diff - y); + const double c_r = scale_r * (r_diff - y); + + buffer[i] = static_cast(std::sqrt(square(y) + square(c_b) + square(c_r))); + } + } + + double distImpl(uint32_t pix1, uint32_t pix2) const + { + //if (pix1 == pix2) -> 8% perf degradation! + // return 0; + //if (pix1 > pix2) + // std::swap(pix1, pix2); -> 30% perf degradation!!! + + const int r_diff = static_cast(getRed (pix1)) - getRed (pix2); + const int g_diff = static_cast(getGreen(pix1)) - getGreen(pix2); + const int b_diff = static_cast(getBlue (pix1)) - getBlue (pix2); + + return buffer[(((r_diff + 255) / 2) << 16) | //slightly reduce precision (division by 2) to squeeze value into single byte + (((g_diff + 255) / 2) << 8) | + (( b_diff + 255) / 2)]; + } + + std::vector buffer; //consumes 64 MB memory; using double is only 2% faster, but takes 128 MB +}; + + +enum BlendType +{ + BLEND_NONE = 0, + BLEND_NORMAL, //a normal indication to blend + BLEND_DOMINANT, //a strong indication to blend + //attention: BlendType must fit into the value range of 2 bit!!! +}; + +struct BlendResult +{ + BlendType + /**/blend_f, blend_g, + /**/blend_j, blend_k; +}; + + +struct Kernel_4x4 //kernel for preprocessing step +{ + uint32_t + /**/a, b, c, d, + /**/e, f, g, h, + /**/i, j, k, l, + /**/m, n, o, p; +}; + +/* +input kernel area naming convention: +----------------- +| A | B | C | D | +----|---|---|---| +| E | F | G | H | //evaluate the four corners between F, G, J, K +----|---|---|---| //input pixel is at position F +| I | J | K | L | +----|---|---|---| +| M | N | O | P | +----------------- +*/ +template +FORCE_INLINE //detect blend direction +BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg) //result: F, G, J, K corners of "GradientType" +{ + BlendResult result = {}; + + if ((ker.f == ker.g && + ker.j == ker.k) || + (ker.f == ker.j && + ker.g == ker.k)) + return result; + + auto dist = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); }; + + const int weight = 4; + double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + weight * dist(ker.j, ker.g); + double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + weight * dist(ker.f, ker.k); + + if (jg < fk) //test sample: 70% of values max(jg, fk) / min(jg, fk) are between 1.1 and 3.7 with median being 1.8 + { + const bool dominantGradient = cfg.dominantDirectionThreshold * jg < fk; + if (ker.f != ker.g && ker.f != ker.j) + result.blend_f = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + + if (ker.k != ker.j && ker.k != ker.g) + result.blend_k = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + } + else if (fk < jg) + { + const bool dominantGradient = cfg.dominantDirectionThreshold * fk < jg; + if (ker.j != ker.f && ker.j != ker.k) + result.blend_j = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + + if (ker.g != ker.f && ker.g != ker.k) + result.blend_g = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + } + return result; +} + +struct Kernel_3x3 +{ + uint32_t + /**/a, b, c, + /**/d, e, f, + /**/g, h, i; +}; + +#define DEF_GETTER(x) template uint32_t inline get_##x(const Kernel_3x3& ker) { return ker.x; } +//we cannot and NEED NOT write "ker.##x" since ## concatenates preprocessor tokens but "." is not a token +DEF_GETTER(a) DEF_GETTER(b) DEF_GETTER(c) +DEF_GETTER(d) DEF_GETTER(e) DEF_GETTER(f) +DEF_GETTER(g) DEF_GETTER(h) DEF_GETTER(i) +#undef DEF_GETTER + +#define DEF_GETTER(x, y) template <> inline uint32_t get_##x(const Kernel_3x3& ker) { return ker.y; } +DEF_GETTER(a, g) DEF_GETTER(b, d) DEF_GETTER(c, a) +DEF_GETTER(d, h) DEF_GETTER(e, e) DEF_GETTER(f, b) +DEF_GETTER(g, i) DEF_GETTER(h, f) DEF_GETTER(i, c) +#undef DEF_GETTER + +#define DEF_GETTER(x, y) template <> inline uint32_t get_##x(const Kernel_3x3& ker) { return ker.y; } +DEF_GETTER(a, i) DEF_GETTER(b, h) DEF_GETTER(c, g) +DEF_GETTER(d, f) DEF_GETTER(e, e) DEF_GETTER(f, d) +DEF_GETTER(g, c) DEF_GETTER(h, b) DEF_GETTER(i, a) +#undef DEF_GETTER + +#define DEF_GETTER(x, y) template <> inline uint32_t get_##x(const Kernel_3x3& ker) { return ker.y; } +DEF_GETTER(a, c) DEF_GETTER(b, f) DEF_GETTER(c, i) +DEF_GETTER(d, b) DEF_GETTER(e, e) DEF_GETTER(f, h) +DEF_GETTER(g, a) DEF_GETTER(h, d) DEF_GETTER(i, g) +#undef DEF_GETTER + + +//compress four blend types into a single byte +inline BlendType getTopL (unsigned char b) { return static_cast(0x3 & b); } +inline BlendType getTopR (unsigned char b) { return static_cast(0x3 & (b >> 2)); } +inline BlendType getBottomR(unsigned char b) { return static_cast(0x3 & (b >> 4)); } +inline BlendType getBottomL(unsigned char b) { return static_cast(0x3 & (b >> 6)); } + +inline void setTopL (unsigned char& b, BlendType bt) { b |= bt; } //buffer is assumed to be initialized before preprocessing! +inline void setTopR (unsigned char& b, BlendType bt) { b |= (bt << 2); } +inline void setBottomR(unsigned char& b, BlendType bt) { b |= (bt << 4); } +inline void setBottomL(unsigned char& b, BlendType bt) { b |= (bt << 6); } + +inline bool blendingNeeded(unsigned char b) { return b != 0; } + +template inline +unsigned char rotateBlendInfo(unsigned char b) { return b; } +template <> inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 2) | (b >> 6)) & 0xff; } +template <> inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 4) | (b >> 4)) & 0xff; } +template <> inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 6) | (b >> 2)) & 0xff; } + + +#ifndef NDEBUG + int debugPixelX = -1; + int debugPixelY = 12; + __declspec(thread) bool breakIntoDebugger = false; +#endif + + +/* +input kernel area naming convention: +------------- +| A | B | C | +----|---|---| +| D | E | F | //input pixel is at position E +----|---|---| +| G | H | I | +------------- +*/ +template +FORCE_INLINE //perf: quite worth it! +void blendPixel(const Kernel_3x3& ker, + uint32_t* target, int trgWidth, + unsigned char blendInfo, //result of preprocessing all four corners of pixel "e" + const xbrz::ScalerCfg& cfg) +{ +#define a get_a(ker) +#define b get_b(ker) +#define c get_c(ker) +#define d get_d(ker) +#define e get_e(ker) +#define f get_f(ker) +#define g get_g(ker) +#define h get_h(ker) +#define i get_i(ker) + +#ifndef NDEBUG + if (breakIntoDebugger) + __debugbreak(); //__asm int 3; +#endif + + const unsigned char blend = rotateBlendInfo(blendInfo); + + if (getBottomR(blend) >= BLEND_NORMAL) + { + auto eq = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight) < cfg.equalColorTolerance; }; + auto dist = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); }; + + const bool doLineBlend = [&]() -> bool + { + if (getBottomR(blend) >= BLEND_DOMINANT) + return true; + + //make sure there is no second blending in an adjacent rotation for this pixel: handles insular pixels, mario eyes + if (getTopR(blend) != BLEND_NONE && !eq(e, g)) //but support double-blending for 90 corners + return false; + if (getBottomL(blend) != BLEND_NONE && !eq(e, c)) + return false; + + //no full blending for L-shapes; blend corner only (handles "mario mushroom eyes") + if (!eq(e, i) && eq(g, h) && eq(h , i) && eq(i, f) && eq(f, c)) + return false; + + return true; + }(); + + const uint32_t px = dist(e, f) <= dist(e, h) ? f : h; //choose most similar color + + OutputMatrix out(target, trgWidth); + + if (doLineBlend) + { + const double fg = dist(f, g); //test sample: 70% of values max(fg, hc) / min(fg, hc) are between 1.1 and 3.7 with median being 1.9 + const double hc = dist(h, c); // + + const bool haveShallowLine = cfg.steepDirectionThreshold * fg <= hc && e != g && d != g; + const bool haveSteepLine = cfg.steepDirectionThreshold * hc <= fg && e != c && b != c; + + if (haveShallowLine) + { + if (haveSteepLine) + Scaler::blendLineSteepAndShallow(px, out); + else + Scaler::blendLineShallow(px, out); + } + else + { + if (haveSteepLine) + Scaler::blendLineSteep(px, out); + else + Scaler::blendLineDiagonal(px,out); + } + } + else + Scaler::blendCorner(px, out); + } + +#undef a +#undef b +#undef c +#undef d +#undef e +#undef f +#undef g +#undef h +#undef i +} + + +template //scaler policy: see "Scaler2x" reference implementation +void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) +{ + yFirst = std::max(yFirst, 0); + yLast = std::min(yLast, srcHeight); + if (yFirst >= yLast || srcWidth <= 0) + return; + + const int trgWidth = srcWidth * Scaler::scale; + + //"use" space at the end of the image as temporary buffer for "on the fly preprocessing": we even could use larger area of + //"sizeof(uint32_t) * srcWidth * (yLast - yFirst)" bytes without risk of accidental overwriting before accessing + const int bufferSize = srcWidth; + unsigned char* preProcBuffer = reinterpret_cast(trg + yLast * Scaler::scale * trgWidth) - bufferSize; + std::fill(preProcBuffer, preProcBuffer + bufferSize, 0); + static_assert(BLEND_NONE == 0, ""); + + //initialize preprocessing buffer for first row of current stripe: detect upper left and right corner blending + //this cannot be optimized for adjacent processing stripes; we must not allow for a memory race condition! + if (yFirst > 0) + { + const int y = yFirst - 1; + + const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); + const uint32_t* s_0 = src + srcWidth * y; //center line + const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); + const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); + + for (int x = 0; x < srcWidth; ++x) + { + const int x_m1 = std::max(x - 1, 0); + const int x_p1 = std::min(x + 1, srcWidth - 1); + const int x_p2 = std::min(x + 2, srcWidth - 1); + + Kernel_4x4 ker = {}; //perf: initialization is negligible + ker.a = s_m1[x_m1]; //read sequentially from memory as far as possible + ker.b = s_m1[x]; + ker.c = s_m1[x_p1]; + ker.d = s_m1[x_p2]; + + ker.e = s_0[x_m1]; + ker.f = s_0[x]; + ker.g = s_0[x_p1]; + ker.h = s_0[x_p2]; + + ker.i = s_p1[x_m1]; + ker.j = s_p1[x]; + ker.k = s_p1[x_p1]; + ker.l = s_p1[x_p2]; + + ker.m = s_p2[x_m1]; + ker.n = s_p2[x]; + ker.o = s_p2[x_p1]; + ker.p = s_p2[x_p2]; + + const BlendResult res = preProcessCorners(ker, cfg); + /* + preprocessing blend result: + --------- + | F | G | //evalute corner between F, G, J, K + ----|---| //input pixel is at position F + | J | K | + --------- + */ + setTopR(preProcBuffer[x], res.blend_j); + + if (x + 1 < bufferSize) + setTopL(preProcBuffer[x + 1], res.blend_k); + } + } + //------------------------------------------------------------------------------------ + + for (int y = yFirst; y < yLast; ++y) + { + uint32_t* out = trg + Scaler::scale * y * trgWidth; //consider MT "striped" access + + const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); + const uint32_t* s_0 = src + srcWidth * y; //center line + const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); + const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); + + unsigned char blend_xy1 = 0; //corner blending for current (x, y + 1) position + + for (int x = 0; x < srcWidth; ++x, out += Scaler::scale) + { +#ifndef NDEBUG + breakIntoDebugger = debugPixelX == x && debugPixelY == y; +#endif + //all those bounds checks have only insignificant impact on performance! + const int x_m1 = std::max(x - 1, 0); //perf: prefer array indexing to additional pointers! + const int x_p1 = std::min(x + 1, srcWidth - 1); + const int x_p2 = std::min(x + 2, srcWidth - 1); + + Kernel_4x4 ker4 = {}; //perf: initialization is negligible + + ker4.a = s_m1[x_m1]; //read sequentially from memory as far as possible + ker4.b = s_m1[x]; + ker4.c = s_m1[x_p1]; + ker4.d = s_m1[x_p2]; + + ker4.e = s_0[x_m1]; + ker4.f = s_0[x]; + ker4.g = s_0[x_p1]; + ker4.h = s_0[x_p2]; + + ker4.i = s_p1[x_m1]; + ker4.j = s_p1[x]; + ker4.k = s_p1[x_p1]; + ker4.l = s_p1[x_p2]; + + ker4.m = s_p2[x_m1]; + ker4.n = s_p2[x]; + ker4.o = s_p2[x_p1]; + ker4.p = s_p2[x_p2]; + + //evaluate the four corners on bottom-right of current pixel + unsigned char blend_xy = 0; //for current (x, y) position + { + const BlendResult res = preProcessCorners(ker4, cfg); + /* + preprocessing blend result: + --------- + | F | G | //evalute corner between F, G, J, K + ----|---| //current input pixel is at position F + | J | K | + --------- + */ + blend_xy = preProcBuffer[x]; + setBottomR(blend_xy, res.blend_f); //all four corners of (x, y) have been determined at this point due to processing sequence! + + setTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1) + preProcBuffer[x] = blend_xy1; //store on current buffer position for use on next row + + blend_xy1 = 0; + setTopL(blend_xy1, res.blend_k); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column + + if (x + 1 < bufferSize) //set 3rd known corner for (x + 1, y) + setBottomL(preProcBuffer[x + 1], res.blend_g); + } + + //fill block of size scale * scale with the given color + fillBlock(out, trgWidth * sizeof(uint32_t), ker4.f, Scaler::scale); //place *after* preprocessing step, to not overwrite the results while processing the the last pixel! + + //blend four corners of current pixel + if (blendingNeeded(blend_xy)) //good 5% perf-improvement + { + Kernel_3x3 ker3 = {}; //perf: initialization is negligible + + ker3.a = ker4.a; + ker3.b = ker4.b; + ker3.c = ker4.c; + + ker3.d = ker4.e; + ker3.e = ker4.f; + ker3.f = ker4.g; + + ker3.g = ker4.i; + ker3.h = ker4.j; + ker3.i = ker4.k; + + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + } + } + } +} + +//------------------------------------------------------------------------------------ + +template +struct Scaler2x : public ColorGradient +{ + static const int scale = 2; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<1, 0>(), col); + alphaGrad<1, 4>(out.template ref<0, 1>(), col); + alphaGrad<5, 6>(out.template ref<1, 1>(), col); //[!] fixes 7/8 used in xBR + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 2>(out.template ref<1, 1>(), col); + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<21, 100>(out.template ref<1, 1>(), col); //exact: 1 - pi/4 = 0.2146018366 + } +}; + + +template +struct Scaler3x : public ColorGradient +{ + static const int scale = 3; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + out.template ref<2, scale - 1>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<2, 0>(), col); + alphaGrad<1, 4>(out.template ref<0, 2>(), col); + alphaGrad<3, 4>(out.template ref<2, 1>(), col); + alphaGrad<3, 4>(out.template ref<1, 2>(), col); + out.template ref<2, 2>() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 8>(out.template ref<1, 2>(), col); //conflict with other rotations for this odd scale + alphaGrad<1, 8>(out.template ref<2, 1>(), col); + alphaGrad<7, 8>(out.template ref<2, 2>(), col); // + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<45, 100>(out.template ref<2, 2>(), col); //exact: 0.4545939598 + //alphaGrad<7, 256>(out.template ref<2, 1>(), col); //0.02826017254 -> negligible + avoid conflicts with other rotations for this odd scale + //alphaGrad<7, 256>(out.template ref<1, 2>(), col); //0.02826017254 + } +}; + + +template +struct Scaler4x : public ColorGradient +{ + static const int scale = 4; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<3, 4>(out.template ref<3, 1>(), col); + alphaGrad<3, 4>(out.template ref<1, 3>(), col); + alphaGrad<1, 4>(out.template ref<3, 0>(), col); + alphaGrad<1, 4>(out.template ref<0, 3>(), col); + + alphaGrad<1, 3>(out.template ref<2, 2>(), col); //[!] fixes 1/4 used in xBR + + out.template ref<3, 3>() = col; + out.template ref<3, 2>() = col; + out.template ref<2, 3>() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 2>(out.template ref(), col); + alphaGrad<1, 2>(out.template ref(), col); + out.template ref() = col; + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<68, 100>(out.template ref<3, 3>(), col); //exact: 0.6848532563 + alphaGrad< 9, 100>(out.template ref<3, 2>(), col); //0.08677704501 + alphaGrad< 9, 100>(out.template ref<2, 3>(), col); //0.08677704501 + } +}; + + +template +struct Scaler5x : public ColorGradient +{ + static const int scale = 5; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + out.template ref<4, scale - 2>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + alphaGrad<2, 3>(out.template ref<3, 3>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 8>(out.template ref(), col); //conflict with other rotations for this odd scale + alphaGrad<1, 8>(out.template ref(), col); + alphaGrad<1, 8>(out.template ref(), col); // + + alphaGrad<7, 8>(out.template ref<4, 3>(), col); + alphaGrad<7, 8>(out.template ref<3, 4>(), col); + + out.template ref<4, 4>() = col; + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<86, 100>(out.template ref<4, 4>(), col); //exact: 0.8631434088 + alphaGrad<23, 100>(out.template ref<4, 3>(), col); //0.2306749731 + alphaGrad<23, 100>(out.template ref<3, 4>(), col); //0.2306749731 + //alphaGrad<1, 64>(out.template ref<4, 2>(), col); //0.01676812367 -> negligible + avoid conflicts with other rotations for this odd scale + //alphaGrad<1, 64>(out.template ref<2, 4>(), col); //0.01676812367 + } +}; + + +template +struct Scaler6x : public ColorGradient +{ + static const int scale = 6; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + alphaGrad<3, 4>(out.template ref<5, scale - 3>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + out.template ref<5, scale - 1>() = col; + + out.template ref<4, scale - 2>() = col; + out.template ref<5, scale - 2>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + out.template ref<5, scale - 1>() = col; + + out.template ref<4, scale - 2>() = col; + out.template ref<5, scale - 2>() = col; + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 2>(out.template ref(), col); + alphaGrad<1, 2>(out.template ref(), col); + alphaGrad<1, 2>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<97, 100>(out.template ref<5, 5>(), col); //exact: 0.9711013910 + alphaGrad<42, 100>(out.template ref<4, 5>(), col); //0.4236372243 + alphaGrad<42, 100>(out.template ref<5, 4>(), col); //0.4236372243 + alphaGrad< 6, 100>(out.template ref<5, 3>(), col); //0.05652034508 + alphaGrad< 6, 100>(out.template ref<3, 5>(), col); //0.05652034508 + } +}; + +//------------------------------------------------------------------------------------ + +struct ColorDistanceRGB +{ + static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight) + { + return DistYCbCrBuffer::dist(pix1, pix2); + + //if (pix1 == pix2) //about 4% perf boost + // return 0; + //return distYCbCr(pix1, pix2, luminanceWeight); + } +}; + +struct ColorDistanceARGB +{ + static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight) + { + const double a1 = getAlpha(pix1) / 255.0 ; + const double a2 = getAlpha(pix2) / 255.0 ; + /* + Requirements for a color distance handling alpha channel: with a1, a2 in [0, 1] + + 1. if a1 = a2, distance should be: a1 * distYCbCr() + 2. if a1 = 0, distance should be: a2 * distYCbCr(black, white) = a2 * 255 + 3. if a1 = 1, ??? maybe: 255 * (1 - a2) + a2 * distYCbCr() + */ + + //return std::min(a1, a2) * DistYCbCrBuffer::dist(pix1, pix2) + 255 * abs(a1 - a2); + //=> following code is 15% faster: + const double d = DistYCbCrBuffer::dist(pix1, pix2); + if (a1 < a2) + return a1 * d + 255 * (a2 - a1); + else + return a2 * d + 255 * (a1 - a2); + + //alternative? return std::sqrt(a1 * a2 * square(DistYCbCrBuffer::dist(pix1, pix2)) + square(255 * (a1 - a2))); + } +}; + + +struct ColorGradientRGB +{ + template + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) + { + pixBack = gradientRGB(pixFront, pixBack); + } +}; + +struct ColorGradientARGB +{ + template + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) + { + pixBack = gradientARGB(pixFront, pixBack); + } +}; +} + + +void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, ColorFormat colFmt, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) +{ + switch (colFmt) + { + case ColorFormat::ARGB: + switch (factor) + { + case 2: + return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 3: + return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 4: + return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 5: + return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 6: + return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + } + break; + + case ColorFormat::RGB: + switch (factor) + { + case 2: + return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 3: + return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 4: + return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 5: + return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 6: + return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + } + break; + } + assert(false); +} + + +bool xbrz::equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, double equalColorTolerance) +{ + switch (colFmt) + { + case ColorFormat::ARGB: + return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance; + + case ColorFormat::RGB: + return ColorDistanceRGB::dist(col1, col2, luminanceWeight) < equalColorTolerance; + } + assert(false); + return false; +} + + +void xbrz::nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, int srcPitch, + uint32_t* trg, int trgWidth, int trgHeight, int trgPitch, + SliceType st, int yFirst, int yLast) +{ + if (srcPitch < srcWidth * static_cast(sizeof(uint32_t)) || + trgPitch < trgWidth * static_cast(sizeof(uint32_t))) + { + assert(false); + return; + } + + switch (st) + { + case NN_SCALE_SLICE_SOURCE: + //nearest-neighbor (going over source image - fast for upscaling, since source is read only once + yFirst = std::max(yFirst, 0); + yLast = std::min(yLast, srcHeight); + if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0) return; + + for (int y = yFirst; y < yLast; ++y) + { + //mathematically: ySrc = floor(srcHeight * yTrg / trgHeight) + // => search for integers in: [ySrc, ySrc + 1) * trgHeight / srcHeight + + //keep within for loop to support MT input slices! + const int yTrg_first = ( y * trgHeight + srcHeight - 1) / srcHeight; //=ceil(y * trgHeight / srcHeight) + const int yTrg_last = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight; //=ceil(((y + 1) * trgHeight) / srcHeight) + const int blockHeight = yTrg_last - yTrg_first; + + if (blockHeight > 0) + { + const uint32_t* srcLine = byteAdvance(src, y * srcPitch); + uint32_t* trgLine = byteAdvance(trg, yTrg_first * trgPitch); + int xTrg_first = 0; + + for (int x = 0; x < srcWidth; ++x) + { + int xTrg_last = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth; + const int blockWidth = xTrg_last - xTrg_first; + if (blockWidth > 0) + { + xTrg_first = xTrg_last; + fillBlock(trgLine, trgPitch, srcLine[x], blockWidth, blockHeight); + trgLine += blockWidth; + } + } + } + } + break; + + case NN_SCALE_SLICE_TARGET: + //nearest-neighbor (going over target image - slow for upscaling, since source is read multiple times missing out on cache! Fast for similar image sizes!) + yFirst = std::max(yFirst, 0); + yLast = std::min(yLast, trgHeight); + if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return; + + for (int y = yFirst; y < yLast; ++y) + { + uint32_t* trgLine = byteAdvance(trg, y * trgPitch); + const int ySrc = srcHeight * y / trgHeight; + const uint32_t* srcLine = byteAdvance(src, ySrc * srcPitch); + for (int x = 0; x < trgWidth; ++x) + { + const int xSrc = srcWidth * x / trgWidth; + trgLine[x] = srcLine[xSrc]; + } + } + break; + } +} diff --git a/Utilities/xBRZ/xbrz.h b/Utilities/xBRZ/xbrz.h new file mode 100644 index 00000000..40dd4105 --- /dev/null +++ b/Utilities/xBRZ/xbrz.h @@ -0,0 +1,94 @@ +// **************************************************************************** +// * This file is part of the HqMAME project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * +// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * +// * * +// * Additionally and as a special exception, the author gives permission * +// * to link the code of this program with the MAME library (or with modified * +// * versions of MAME that use the same license as MAME), and distribute * +// * linked combinations including the two. You must obey the GNU General * +// * Public License in all respects for all of the code used other than MAME. * +// * If you modify this file, you may extend this exception to your version * +// * of the file, but you are not obligated to do so. If you do not wish to * +// * do so, delete this exception statement from your version. * +// **************************************************************************** + +#ifndef XBRZ_HEADER_3847894708239054 +#define XBRZ_HEADER_3847894708239054 + +#include //size_t +#include //uint32_t +#include +#include "config.h" + +namespace xbrz +{ +/* +------------------------------------------------------------------------- +| xBRZ: "Scale by rules" - high quality image upscaling filter by Zenju | +------------------------------------------------------------------------- +using a modified approach of xBR: +http://board.byuu.org/viewtopic.php?f=10&t=2248 +- new rule set preserving small image features +- highly optimized for performance +- support alpha channel +- support multithreading +- support 64-bit architectures +- support processing image slices +- support scaling up to 6xBRZ +*/ + +enum class ColorFormat //from high bits -> low bits, 8 bit per channel +{ + RGB, //8 bit for each red, green, blue, upper 8 bits unused + ARGB, //including alpha channel, BGRA byte order on little-endian machines +}; + +/* +-> map source (srcWidth * srcHeight) to target (scale * width x scale * height) image, optionally processing a half-open slice of rows [yFirst, yLast) only +-> support for source/target pitch in bytes! +-> if your emulator changes only a few image slices during each cycle (e.g. DOSBox) then there's no need to run xBRZ on the complete image: + Just make sure you enlarge the source image slice by 2 rows on top and 2 on bottom (this is the additional range the xBRZ algorithm is using during analysis) + Caveat: If there are multiple changed slices, make sure they do not overlap after adding these additional rows in order to avoid a memory race condition + in the target image data if you are using multiple threads for processing each enlarged slice! + +THREAD-SAFETY: - parts of the same image may be scaled by multiple threads as long as the [yFirst, yLast) ranges do not overlap! + - there is a minor inefficiency for the first row of a slice, so avoid processing single rows only; suggestion: process 8-16 rows at least +*/ +void scale(size_t factor, //valid range: 2 - 6 + const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, + ColorFormat colFmt, + const ScalerCfg& cfg = ScalerCfg(), + int yFirst = 0, int yLast = std::numeric_limits::max()); //slice of source image + +void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, + uint32_t* trg, int trgWidth, int trgHeight); + +enum SliceType +{ + NN_SCALE_SLICE_SOURCE, + NN_SCALE_SLICE_TARGET, +}; +void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, int srcPitch, //pitch in bytes! + uint32_t* trg, int trgWidth, int trgHeight, int trgPitch, + SliceType st, int yFirst, int yLast); + +//parameter tuning +bool equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, double equalColorTolerance); + + + + + +//########################### implementation ########################### +inline +void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, + uint32_t* trg, int trgWidth, int trgHeight) +{ + nearestNeighborScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t), + trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t), + NN_SCALE_SLICE_TARGET, 0, trgHeight); +} +} + +#endif