quantizer code - space to tabs, other cleanups

This commit is contained in:
adelikat 2020-01-03 18:35:13 -06:00
parent 101a403420
commit 8885b38281
3 changed files with 472 additions and 516 deletions

View File

@ -14,7 +14,7 @@
// Based on: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/colorquant.asp
//Bizhawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize
//BizHawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize
using System;
using System.Collections.Generic;
@ -23,87 +23,91 @@ using System.Drawing.Imaging;
namespace BizHawk.Client.EmuHawk
{
/// <summary>
/// Quantize using an Octree
/// </summary>
unsafe class OctreeQuantizer : Quantizer
{
/// <summary>
/// Stores the tree
/// </summary>
private Octree _octree;
/// <summary>
/// Quantize using an Octree
/// </summary>
internal class OctreeQuantizer : Quantizer
{
/// <summary>
/// Stores the tree
/// </summary>
private readonly Octree _octree;
/// <summary>
/// Maximum allowed color depth
/// </summary>
private int _maxColors;
/// <summary>
/// Maximum allowed color depth
/// </summary>
private readonly int _maxColors;
/// <param name="maxColors">The maximum number of colors to return</param>
/// <param name="maxColorBits">The number of significant bits</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="maxColors"/> &ge; <c>256</c> or <paramref name="maxColorBits"/> outside range <c>1..8</c></exception>
/// <remarks>The Octree quantizer is a two pass algorithm. The initial pass sets up the octree, the second pass quantizes a color based on the nodes in the tree.</remarks>
public OctreeQuantizer(int maxColors, int maxColorBits) : base(false)
{
if (maxColors > 255)
throw new ArgumentOutOfRangeException(nameof(maxColors), maxColors, "The number of colors should be less than 256");
/// <param name="maxColors">The maximum number of colors to return</param>
/// <param name="maxColorBits">The number of significant bits</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="maxColors"/> &ge; <c>256</c> or <paramref name="maxColorBits"/> outside range <c>1..8</c></exception>
/// <remarks>The Octree quantizer is a two pass algorithm. The initial pass sets up the octree, the second pass quantizes a color based on the nodes in the tree.</remarks>
public OctreeQuantizer(int maxColors, int maxColorBits) : base(false)
{
if (maxColors > 255)
{
throw new ArgumentOutOfRangeException(nameof(maxColors), maxColors, "The number of colors should be less than 256");
}
if ((maxColorBits < 1) |(maxColorBits > 8))
throw new ArgumentOutOfRangeException(nameof(maxColorBits), maxColorBits, "This should be between 1 and 8");
if ((maxColorBits < 1) | (maxColorBits > 8))
{
throw new ArgumentOutOfRangeException(nameof(maxColorBits), maxColorBits, "This should be between 1 and 8");
}
_octree = new Octree(maxColorBits);
_maxColors = maxColors;
}
_octree = new Octree(maxColorBits);
_maxColors = maxColors;
}
/// <summary>
/// Process the pixel in the first pass of the algorithm
/// </summary>
/// <param name="pixel">The pixel to quantize</param>
/// <remarks>
/// This function need only be overridden if your quantize algorithm needs two passes,
/// such as an Octree quantizer.
/// </remarks>
protected override void InitialQuantizePixel(int pixel)
{
_octree.AddColor(pixel);
}
/// <summary>
/// Process the pixel in the first pass of the algorithm
/// </summary>
/// <param name="pixel">The pixel to quantize</param>
/// <remarks>
/// This function need only be overridden if your quantize algorithm needs two passes,
/// such as an Octree quantizer.
/// </remarks>
protected override void InitialQuantizePixel(int pixel)
{
_octree.AddColor(pixel);
}
/// <summary>
/// Override this to process the pixel in the second pass of the algorithm
/// </summary>
/// <param name="pixel">The pixel to quantize</param>
/// <returns>The quantized value</returns>
protected override byte QuantizePixel(int pixel)
{
byte paletteIndex = (byte)_maxColors; // The color at [_maxColors] is set to transparent
/// <summary>
/// Override this to process the pixel in the second pass of the algorithm
/// </summary>
/// <param name="pixel">The pixel to quantize</param>
/// <returns>The quantized value</returns>
protected override byte QuantizePixel(int pixel)
{
byte paletteIndex = (byte)_maxColors; // The color at [_maxColors] is set to transparent
// Get the palette index if this non-transparent
int a = (pixel>>24)&0xFF;
// Get the palette index if this non-transparent
int a = (pixel >> 24) & 0xFF;
#if HANDLE_TRANSPARENCY
if (a > 0)
#endif
{
paletteIndex = (byte)_octree.GetPaletteIndex(pixel);
}
{
paletteIndex = (byte)_octree.GetPaletteIndex(pixel);
}
return paletteIndex;
}
return paletteIndex;
}
/// <summary>
/// Retrieve the palette for the quantized image
/// </summary>
/// <param name="original">Any old palette, this is overrwritten</param>
/// <returns>The new color palette</returns>
protected override ColorPalette GetPalette(ColorPalette original)
{
// First off convert the octree to _maxColors colors
List<Color> palette = _octree.Palletize(_maxColors - 1);
/// <summary>
/// Retrieve the palette for the quantized image
/// </summary>
/// <param name="original">Any old palette, this is overwritten</param>
/// <returns>The new color palette</returns>
protected override ColorPalette GetPalette(ColorPalette original)
{
// First off convert the octree to _maxColors colors
List<Color> palette = _octree.Palletize(_maxColors - 1);
// Then convert the palette based on those colors
for (int index = 0; index < palette.Count; index++)
{
original.Entries[index] = palette[index];
}
// Then convert the palette based on those colors
for (int index = 0; index < palette.Count; index++)
{
original.Entries[index] = palette[index];
}
#if ORIGINAL_CODE
for (int i = palette.Count; i < original.Entries.Length; ++i)
@ -114,461 +118,417 @@ namespace BizHawk.Client.EmuHawk
// Add the transparent color
original.Entries[_maxColors] = Color.FromArgb(0, 0, 0, 0);
#else // PCX Plugin
// For PCX: Pad with transparency
for (int i = palette.Count; i < original.Entries.Length; ++i)
original.Entries[i] = Color.Transparent;
// For PCX: Pad with transparency
for (int i = palette.Count; i < original.Entries.Length; ++i)
{
original.Entries[i] = Color.Transparent;
}
#endif
return original;
}
return original;
}
/// <summary>
/// Class which does the actual quantization
/// </summary>
private class Octree
{
/// <summary>
/// Construct the octree
/// </summary>
/// <param name="maxColorBits">The maximum number of significant bits in the image</param>
public Octree(int maxColorBits)
{
_maxColorBits = maxColorBits;
_leafCount = 0;
_reducibleNodes = new OctreeNode[9];
_root = new OctreeNode(0, _maxColorBits, this);
_previousColor = 0;
_previousNode = null;
}
/// <summary>
/// Class which does the actual quantization
/// </summary>
private class Octree
{
/// <summary>
/// Construct the octree
/// </summary>
/// <param name="maxColorBits">The maximum number of significant bits in the image</param>
public Octree(int maxColorBits)
{
_maxColorBits = maxColorBits;
_leafCount = 0;
_reducibleNodes = new OctreeNode[9];
_root = new OctreeNode(0, _maxColorBits, this);
_previousColor = 0;
_previousNode = null;
}
/// <summary>
/// Add a given color value to the octree
/// </summary>
public void AddColor(int pixel)
{
// Check if this request is for the same color as the last
if (_previousColor == pixel)
{
// If so, check if I have a previous node setup. This will only ocurr if the first color in the image
// happens to be black, with an alpha component of zero.
if (null == _previousNode)
{
_previousColor = pixel;
_root.AddColor(pixel, _maxColorBits, 0, this);
}
else
{
// Just update the previous node
_previousNode.Increment(pixel);
}
}
else
{
_previousColor = pixel;
_root.AddColor(pixel, _maxColorBits, 0, this);
}
}
/// <summary>
/// Add a given color value to the octree
/// </summary>
public void AddColor(int pixel)
{
// Check if this request is for the same color as the last
if (_previousColor == pixel)
{
// If so, check if I have a previous node setup. This will only occur if the first color in the image
// happens to be black, with an alpha component of zero.
if (null == _previousNode)
{
_previousColor = pixel;
_root.AddColor(pixel, _maxColorBits, 0, this);
}
else
{
// Just update the previous node
_previousNode.Increment(pixel);
}
}
else
{
_previousColor = pixel;
_root.AddColor(pixel, _maxColorBits, 0, this);
}
}
/// <summary>
/// Reduce the depth of the tree
/// </summary>
public void Reduce()
{
int index;
/// <summary>
/// Reduce the depth of the tree
/// </summary>
private void Reduce()
{
int index;
// Find the deepest level containing at least one reducible node
for (index = _maxColorBits - 1; (index > 0) && (null == _reducibleNodes[index]); index--)
{
// intentionally blank
}
// Find the deepest level containing at least one reducible node
for (index = _maxColorBits - 1; index > 0 && _reducibleNodes[index] == null; index--)
{
// intentionally blank
}
// Reduce the node most recently added to the list at level 'index'
OctreeNode node = _reducibleNodes[index];
_reducibleNodes[index] = node.NextReducible;
// Reduce the node most recently added to the list at level 'index'
OctreeNode node = _reducibleNodes[index];
_reducibleNodes[index] = node.NextReducible;
// Decrement the leaf count after reducing the node
_leafCount -= node.Reduce();
// Decrement the leaf count after reducing the node
_leafCount -= node.Reduce();
// And just in case I've reduced the last color to be added, and the next color to
// be added is the same, invalidate the previousNode...
_previousNode = null;
}
// And just in case I've reduced the last color to be added, and the next color to
// be added is the same, invalidate the previousNode...
_previousNode = null;
}
/// <summary>
/// Get/Set the number of leaves in the tree
/// </summary>
public int Leaves
{
get
{
return _leafCount;
}
/// <summary>
/// Return the array of reducible nodes
/// </summary>
protected OctreeNode[] ReducibleNodes => _reducibleNodes;
set
{
_leafCount = value;
}
}
/// <summary>
/// Keep track of the previous node that was quantized
/// </summary>
/// <param name="node">The node last quantized</param>
protected void TrackPrevious(OctreeNode node)
{
_previousNode = node;
}
/// <summary>
/// Return the array of reducible nodes
/// </summary>
protected OctreeNode[] ReducibleNodes
{
get
{
return _reducibleNodes;
}
}
private Color[] _palette;
private PaletteTable _paletteTable;
/// <summary>
/// Keep track of the previous node that was quantized
/// </summary>
/// <param name="node">The node last quantized</param>
protected void TrackPrevious(OctreeNode node)
{
_previousNode = node;
}
/// <summary>
/// Convert the nodes in the octree to a palette with a maximum of colorCount colors
/// </summary>
/// <param name="colorCount">The maximum number of colors</param>
/// <returns>A list with the palettized colors</returns>
public List<Color> Palletize(int colorCount)
{
while (_leafCount > colorCount)
{
Reduce();
}
private Color[] _palette;
private PaletteTable paletteTable;
// Now palletize the nodes
var palette = new List<Color>(_leafCount);
int paletteIndex = 0;
/// <summary>
/// Convert the nodes in the octree to a palette with a maximum of colorCount colors
/// </summary>
/// <param name="colorCount">The maximum number of colors</param>
/// <returns>A list with the palettized colors</returns>
public List<Color> Palletize(int colorCount)
{
while (Leaves > colorCount)
{
Reduce();
}
_root.ConstructPalette(palette, ref paletteIndex);
// Now palettize the nodes
List<Color> palette = new List<Color>(Leaves);
int paletteIndex = 0;
// And return the palette
_palette = palette.ToArray();
_paletteTable = null;
_root.ConstructPalette(palette, ref paletteIndex);
return palette;
}
// And return the palette
this._palette = palette.ToArray();
this.paletteTable = null;
return palette;
}
/// <summary>
/// Get the palette index for the passed color
/// </summary>
public int GetPaletteIndex(int pixel)
{
var ret = _root.GetPaletteIndex(pixel, 0);
/// <summary>
/// Get the palette index for the passed color
/// </summary>
public int GetPaletteIndex(int pixel)
{
int ret = -1;
ret = _root.GetPaletteIndex(pixel, 0);
if (ret < 0)
{
if (_paletteTable == null)
{
_paletteTable = new PaletteTable(_palette);
}
if (ret < 0)
{
if (this.paletteTable == null)
{
this.paletteTable = new PaletteTable(this._palette);
}
ret = _paletteTable.FindClosestPaletteIndex(Color.FromArgb(pixel));
}
ret = this.paletteTable.FindClosestPaletteIndex(Color.FromArgb(pixel));
}
return ret;
}
return ret;
}
/// <summary>
/// Mask used when getting the appropriate pixels for a given node
/// </summary>
private static readonly int[] Mask = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
/// <summary>
/// Mask used when getting the appropriate pixels for a given node
/// </summary>
private static int[] mask = new int[8] { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
/// <summary>
/// The root of the octree
/// </summary>
private readonly OctreeNode _root;
/// <summary>
/// The root of the octree
/// </summary>
private OctreeNode _root;
/// <summary>
/// Number of leaves in the tree
/// </summary>
private int _leafCount;
/// <summary>
/// Number of leaves in the tree
/// </summary>
private int _leafCount;
/// <summary>
/// Array of reducible nodes
/// </summary>
private readonly OctreeNode[] _reducibleNodes;
/// <summary>
/// Array of reducible nodes
/// </summary>
private OctreeNode[] _reducibleNodes;
/// <summary>
/// Maximum number of significant bits in the image
/// </summary>
private readonly int _maxColorBits;
/// <summary>
/// Maximum number of significant bits in the image
/// </summary>
private int _maxColorBits;
/// <summary>
/// Store the last node quantized
/// </summary>
private OctreeNode _previousNode;
/// <summary>
/// Store the last node quantized
/// </summary>
private OctreeNode _previousNode;
/// <summary>
/// Cache the previous color quantized
/// </summary>
private int _previousColor;
/// <summary>
/// Cache the previous color quantized
/// </summary>
private int _previousColor;
/// <summary>
/// Class which encapsulates each node in the tree
/// </summary>
protected class OctreeNode
{
/// <summary>
/// Construct the node
/// </summary>
/// <param name="level">The level in the tree = 0 - 7</param>
/// <param name="colorBits">The number of significant color bits in the image</param>
/// <param name="octree">The tree to which this node belongs</param>
public OctreeNode(int level, int colorBits, Octree octree)
{
// Construct the new node
_leaf = (level == colorBits);
/// <summary>
/// Class which encapsulates each node in the tree
/// </summary>
protected class OctreeNode
{
/// <summary>
/// Construct the node
/// </summary>
/// <param name="level">The level in the tree = 0 - 7</param>
/// <param name="colorBits">The number of significant color bits in the image</param>
/// <param name="octree">The tree to which this node belongs</param>
public OctreeNode(int level, int colorBits, Octree octree)
{
// Construct the new node
_leaf = (level == colorBits);
_red = 0;
_green = 0;
_blue = 0;
_pixelCount = 0;
_red = 0;
_green = 0;
_blue = 0;
_pixelCount = 0;
// If a leaf, increment the leaf count
if (_leaf)
{
octree._leafCount++;
_nextReducible = null;
_children = null;
}
else
{
// Otherwise add this to the reducible nodes
_nextReducible = octree.ReducibleNodes[level];
octree.ReducibleNodes[level] = this;
_children = new OctreeNode[8];
}
}
// If a leaf, increment the leaf count
if (_leaf)
{
octree.Leaves++;
_nextReducible = null;
_children = null;
}
else
{
// Otherwise add this to the reducible nodes
_nextReducible = octree.ReducibleNodes[level];
octree.ReducibleNodes[level] = this;
_children = new OctreeNode[8];
}
}
/// <summary>
/// Add a color into the tree
/// </summary>
/// <param name="pixel">The color</param>
/// <param name="colorBits">The number of significant color bits</param>
/// <param name="level">The level in the tree</param>
/// <param name="octree">The tree to which this node belongs</param>
public void AddColor(int pixel, int colorBits, int level, Octree octree)
{
// Update the color information if this is a leaf
if (_leaf)
{
Increment(pixel);
/// <summary>
/// Add a color into the tree
/// </summary>
/// <param name="pixel">The color</param>
/// <param name="colorBits">The number of significant color bits</param>
/// <param name="level">The level in the tree</param>
/// <param name="octree">The tree to which this node belongs</param>
public void AddColor(int pixel, int colorBits, int level, Octree octree)
{
// Update the color information if this is a leaf
if (_leaf)
{
Increment(pixel);
// Setup the previous node
octree.TrackPrevious(this);
}
else
{
// Go to the next level down in the tree
int shift = 7 - level;
int b = pixel & 0xFF;
int g = (pixel >> 8) & 0xFF;
int r = (pixel >> 16) & 0xFF;
int index = ((r & Mask[level]) >> (shift - 2)) |
((g & Mask[level]) >> (shift - 1)) |
((b & Mask[level]) >> (shift));
// Setup the previous node
octree.TrackPrevious(this);
}
else
{
// Go to the next level down in the tree
int shift = 7 - level;
int b = pixel & 0xFF;
int g = (pixel >> 8) & 0xFF;
int r = (pixel >> 16) & 0xFF;
int index = ((r & mask[level]) >> (shift - 2)) |
((g & mask[level]) >> (shift - 1)) |
((b & mask[level]) >> (shift));
OctreeNode child = _children[index];
OctreeNode child = _children[index];
if (null == child)
{
// Create a new child node & store in the array
child = new OctreeNode(level + 1, colorBits, octree);
_children[index] = child;
}
if (null == child)
{
// Create a new child node & store in the array
child = new OctreeNode(level + 1, colorBits, octree);
_children[index] = child;
}
// Add the color to the child node
child.AddColor(pixel, colorBits, level + 1, octree);
}
// Add the color to the child node
child.AddColor(pixel, colorBits, level + 1, octree);
}
}
}
/// <summary>
/// Get/Set the next reducible node
/// </summary>
public OctreeNode NextReducible => _nextReducible;
/// <summary>
/// Get/Set the next reducible node
/// </summary>
public OctreeNode NextReducible
{
get
{
return _nextReducible;
}
/// <summary>
/// Reduce this node by removing all of its children
/// </summary>
/// <returns>The number of leaves removed</returns>
public int Reduce()
{
int children = 0;
_red = 0;
_green = 0;
_blue = 0;
set
{
_nextReducible = value;
}
}
// Loop through all children and add their information to this node
for (int index = 0; index < 8; index++)
{
if (null != _children[index])
{
_red += _children[index]._red;
_green += _children[index]._green;
_blue += _children[index]._blue;
_pixelCount += _children[index]._pixelCount;
++children;
_children[index] = null;
}
}
/// <summary>
/// Return the child nodes
/// </summary>
public OctreeNode[] Children
{
get
{
return _children;
}
}
// Now change this to a leaf node
_leaf = true;
/// <summary>
/// Reduce this node by removing all of its children
/// </summary>
/// <returns>The number of leaves removed</returns>
public int Reduce()
{
int children = 0;
_red = 0;
_green = 0;
_blue = 0;
// Return the number of nodes to decrement the leaf count by
return (children - 1);
}
// Loop through all children and add their information to this node
for (int index = 0; index < 8; index++)
{
if (null != _children[index])
{
_red += _children[index]._red;
_green += _children[index]._green;
_blue += _children[index]._blue;
_pixelCount += _children[index]._pixelCount;
++children;
_children[index] = null;
}
}
/// <summary>
/// Traverse the tree, building up the color palette
/// </summary>
/// <param name="palette">The palette</param>
/// <param name="paletteIndex">The current palette index</param>
public void ConstructPalette(List<Color> palette, ref int paletteIndex)
{
if (_leaf)
{
// Consume the next palette index
_paletteIndex = paletteIndex++;
// Now change this to a leaf node
_leaf = true;
// And set the color of the palette entry
int r = _red / _pixelCount;
int g = _green / _pixelCount;
int b = _blue / _pixelCount;
// Return the number of nodes to decrement the leaf count by
return(children - 1);
}
palette.Add(Color.FromArgb(r, g, b));
}
else
{
// Loop through children looking for leaves
for (int index = 0; index < 8; index++)
{
if (null != _children[index])
{
_children[index].ConstructPalette(palette, ref paletteIndex);
}
}
}
}
/// <summary>
/// Traverse the tree, building up the color palette
/// </summary>
/// <param name="palette">The palette</param>
/// <param name="paletteIndex">The current palette index</param>
public void ConstructPalette(List<Color> palette, ref int paletteIndex)
{
if (_leaf)
{
// Consume the next palette index
_paletteIndex = paletteIndex++;
/// <summary>
/// Return the palette index for the passed color
/// </summary>
public int GetPaletteIndex(int pixel, int level)
{
int paletteIndex = _paletteIndex;
// And set the color of the palette entry
int r = _red / _pixelCount;
int g = _green / _pixelCount;
int b = _blue / _pixelCount;
if (!_leaf)
{
int shift = 7 - level;
int b = pixel & 0xFF;
int g = (pixel >> 8) & 0xFF;
int r = (pixel >> 16) & 0xFF;
int index = ((r & Mask[level]) >> (shift - 2)) |
((g & Mask[level]) >> (shift - 1)) |
((b & Mask[level]) >> (shift));
palette.Add(Color.FromArgb(r, g, b));
}
else
{
// Loop through children looking for leaves
for (int index = 0; index < 8; index++)
{
if (null != _children[index])
{
_children[index].ConstructPalette(palette, ref paletteIndex);
}
}
}
}
if (null != _children[index])
{
paletteIndex = _children[index].GetPaletteIndex(pixel, level + 1);
}
else
{
paletteIndex = -1;
}
}
/// <summary>
/// Return the palette index for the passed color
/// </summary>
public int GetPaletteIndex(int pixel, int level)
{
int paletteIndex = _paletteIndex;
return paletteIndex;
}
if (!_leaf)
{
int shift = 7 - level;
int b = pixel & 0xFF;
int g = (pixel >> 8) & 0xFF;
int r = (pixel >> 16) & 0xFF;
int index = ((r & mask[level]) >> (shift - 2)) |
((g & mask[level]) >> (shift - 1)) |
((b & mask[level]) >> (shift));
/// <summary>
/// Increment the pixel count and add to the color information
/// </summary>
public void Increment(int pixel)
{
++_pixelCount;
int b = pixel & 0xFF;
int g = (pixel >> 8) & 0xFF;
int r = (pixel >> 16) & 0xFF;
_red += r;
_green += g;
_blue += b;
}
if (null != _children[index])
{
paletteIndex = _children[index].GetPaletteIndex(pixel, level + 1);
}
else
{
paletteIndex = -1;
}
}
/// <summary>
/// Flag indicating that this is a leaf node
/// </summary>
private bool _leaf;
return paletteIndex;
}
/// <summary>
/// Number of pixels in this node
/// </summary>
private int _pixelCount;
/// <summary>
/// Increment the pixel count and add to the color information
/// </summary>
public void Increment(int pixel)
{
++_pixelCount;
int b = pixel&0xFF;
int g = (pixel>>8) & 0xFF;
int r = (pixel >> 16) & 0xFF;
_red += r;
_green += g;
_blue += b;
}
/// <summary>
/// Red component
/// </summary>
private int _red;
/// <summary>
/// Flag indicating that this is a leaf node
/// </summary>
private bool _leaf;
/// <summary>
/// Green Component
/// </summary>
private int _green;
/// <summary>
/// Number of pixels in this node
/// </summary>
private int _pixelCount;
/// <summary>
/// Blue component
/// </summary>
private int _blue;
/// <summary>
/// Red component
/// </summary>
private int _red;
/// <summary>
/// Pointers to any child nodes
/// </summary>
private readonly OctreeNode[] _children;
/// <summary>
/// Green Component
/// </summary>
private int _green;
/// <summary>
/// Pointer to next reducible node
/// </summary>
private readonly OctreeNode _nextReducible;
/// <summary>
/// Blue component
/// </summary>
private int _blue;
/// <summary>
/// Pointers to any child nodes
/// </summary>
private OctreeNode[] _children;
/// <summary>
/// Pointer to next reducible node
/// </summary>
private OctreeNode _nextReducible;
/// <summary>
/// The index of this node in the palette
/// </summary>
private int _paletteIndex;
}
}
}
/// <summary>
/// The index of this node in the palette
/// </summary>
private int _paletteIndex;
}
}
}
}

View File

@ -12,66 +12,58 @@
// Copyright (C) Joshua Bell
/////////////////////////////////////////////////////////////////////////////////
//Bizhawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize
//BizHawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize
using System.Drawing;
namespace BizHawk.Client.EmuHawk
{
public sealed class PaletteTable
{
private Color[] palette;
public sealed class PaletteTable
{
private readonly Color[] _palette;
public Color this[int index]
{
get
{
return this.palette[index];
}
public Color this[int index]
{
get => _palette[index];
set => _palette[index] = value;
}
set
{
this.palette[index] = value;
}
}
private int GetDistanceSquared(Color a, Color b)
{
int dsq = 0; // delta squared
private int GetDistanceSquared(Color a, Color b)
{
int dsq = 0; // delta squared
int v;
var v = a.B - b.B;
dsq += v * v;
v = a.G - b.G;
dsq += v * v;
v = a.R - b.R;
dsq += v * v;
v = a.B - b.B;
dsq += v * v;
v = a.G - b.G;
dsq += v * v;
v = a.R - b.R;
dsq += v * v;
return dsq;
}
return dsq;
}
public int FindClosestPaletteIndex(Color pixel)
{
int dsqBest = int.MaxValue;
int ret = 0;
public int FindClosestPaletteIndex(Color pixel)
{
int dsqBest = int.MaxValue;
int ret = 0;
for (int i = 0; i < _palette.Length; ++i)
{
int dsq = GetDistanceSquared(_palette[i], pixel);
for (int i = 0; i < this.palette.Length; ++i)
{
int dsq = GetDistanceSquared(this.palette[i], pixel);
if (dsq < dsqBest)
{
dsqBest = dsq;
ret = i;
}
}
if (dsq < dsqBest)
{
dsqBest = dsq;
ret = i;
}
}
return ret;
}
return ret;
}
public PaletteTable(Color[] palette)
{
this.palette = (Color[])palette.Clone();
}
}
public PaletteTable(Color[] palette)
{
_palette = (Color[])palette.Clone();
}
}
}

View File

@ -318,11 +318,14 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Numerics/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=nvidia/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Objs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Octree/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Oeka/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=opcode/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=opengl/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Overdump/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Overscan/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=palettized/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Palletize/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PCFX/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PCSX/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=performant/@EntryIndexedValue">True</s:Boolean>
@ -336,6 +339,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=prescale/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Presize/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Quantizer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=quantizes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=quantizing/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=quickload/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=quicknes/@EntryIndexedValue">True</s:Boolean>