mirror of https://github.com/aseprite/aseprite.git
				
				
				
			
		
			
				
	
	
		
			198 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			198 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
| // Aseprite Document Library
 | |
| // Copyright (C) 2019-2021  Igara Studio S.A.
 | |
| // Copyright (C) 2001-2016  David Capello
 | |
| //
 | |
| // This file is released under the terms of the MIT license.
 | |
| // Read LICENSE.txt for more information.
 | |
| 
 | |
| #ifdef HAVE_CONFIG_H
 | |
|   #include "config.h"
 | |
| #endif
 | |
| 
 | |
| #include "doc/remap.h"
 | |
| 
 | |
| #include "base/base.h"
 | |
| #include "doc/palette.h"
 | |
| #include "doc/palette_picks.h"
 | |
| 
 | |
| #include <algorithm>
 | |
| 
 | |
| namespace doc {
 | |
| 
 | |
| Remap create_remap_to_move_picks(const PalettePicks& picks, int beforeIndex)
 | |
| {
 | |
|   Remap map(picks.size());
 | |
| 
 | |
|   int selectedTotal = 0;
 | |
|   int selectedBeforeIndex = 0;
 | |
| 
 | |
|   for (int i = 0; i < map.size(); ++i) {
 | |
|     if (picks[i]) {
 | |
|       ++selectedTotal;
 | |
|       if (i < beforeIndex)
 | |
|         ++selectedBeforeIndex;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (int i = 0, j = 0, k = 0; i < map.size(); ++i) {
 | |
|     if (k == beforeIndex - selectedBeforeIndex)
 | |
|       k += selectedTotal;
 | |
| 
 | |
|     if (picks[i]) {
 | |
|       map.map(i, beforeIndex - selectedBeforeIndex + j);
 | |
|       ++j;
 | |
|     }
 | |
|     else {
 | |
|       map.map(i, k++);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return map;
 | |
| }
 | |
| 
 | |
| Remap create_remap_to_expand_palette(int size, int count, int beforeIndex)
 | |
| {
 | |
|   Remap map(size);
 | |
| 
 | |
|   int j, k = 0;
 | |
|   for (int i = 0; i < size; ++i) {
 | |
|     if (i < beforeIndex)
 | |
|       j = i;
 | |
|     else if (i + count < size)
 | |
|       j = i + count;
 | |
|     else
 | |
|       j = beforeIndex + (k++);
 | |
| 
 | |
|     map.map(i, j);
 | |
|   }
 | |
|   return map;
 | |
| }
 | |
| 
 | |
| Remap create_remap_to_change_palette(const Palette* oldPalette,
 | |
|                                      const Palette* newPalette,
 | |
|                                      const int oldMaskIndex,
 | |
|                                      const bool remapMaskIndex)
 | |
| {
 | |
|   Remap remap(std::max(oldPalette->size(), newPalette->size()));
 | |
|   int maskIndex = oldMaskIndex;
 | |
| 
 | |
|   if (maskIndex >= 0) {
 | |
|     if (remapMaskIndex && oldPalette->getEntry(maskIndex) != newPalette->getEntry(maskIndex)) {
 | |
|       color_t maskColor = oldPalette->getEntry(maskIndex);
 | |
|       int r = rgba_getr(maskColor);
 | |
|       int g = rgba_getg(maskColor);
 | |
|       int b = rgba_getb(maskColor);
 | |
|       int a = rgba_geta(maskColor);
 | |
| 
 | |
|       // Find the new mask color
 | |
|       maskIndex = newPalette->findExactMatch(r, g, b, a, -1);
 | |
|       if (maskIndex >= 0)
 | |
|         remap.map(oldMaskIndex, maskIndex);
 | |
|     }
 | |
|     else {
 | |
|       remap.map(maskIndex, maskIndex);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (int i = 0; i < oldPalette->size(); ++i) {
 | |
|     if (i == oldMaskIndex)
 | |
|       continue;
 | |
| 
 | |
|     const color_t color = oldPalette->getEntry(i);
 | |
| 
 | |
|     // If in both palettes, it's the same color, we don't need to
 | |
|     // remap this entry.
 | |
|     if (color == newPalette->getEntry(i)) {
 | |
|       remap.map(i, i);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     int j = newPalette->findExactMatch(rgba_getr(color),
 | |
|                                        rgba_getg(color),
 | |
|                                        rgba_getb(color),
 | |
|                                        rgba_geta(color),
 | |
|                                        maskIndex);
 | |
| 
 | |
|     if (j < 0)
 | |
|       j = newPalette->findBestfit(rgba_getr(color),
 | |
|                                   rgba_getg(color),
 | |
|                                   rgba_getb(color),
 | |
|                                   rgba_geta(color),
 | |
|                                   maskIndex);
 | |
| 
 | |
|     remap.map(i, j);
 | |
|   }
 | |
|   return remap;
 | |
| }
 | |
| 
 | |
| void Remap::merge(const Remap& other)
 | |
| {
 | |
|   for (int i = 0; i < size(); ++i) {
 | |
|     m_map[i] = other[m_map[i]];
 | |
|   }
 | |
| }
 | |
| 
 | |
| Remap Remap::invert() const
 | |
| {
 | |
|   Remap inv(size());
 | |
| 
 | |
|   for (int i = 0; i < size(); ++i)
 | |
|     inv.unused(i);
 | |
| 
 | |
|   for (int i = 0; i < size(); ++i) {
 | |
|     int j = m_map[i];
 | |
|     if (j == kUnused || j == kNoTile || inv.m_map[j] != kUnused) { // Already mapped (strange case,
 | |
|                                                                    // we cannot invert this Remap)
 | |
|       continue;
 | |
|     }
 | |
|     inv.map(j, i);
 | |
|   }
 | |
| 
 | |
|   return inv;
 | |
| }
 | |
| 
 | |
| bool Remap::isFor8bit() const
 | |
| {
 | |
|   for (int i = 0; i < size(); ++i) {
 | |
|     // Moving entries between [0,255] range to or from [256,+inf)
 | |
|     // range are invalid for 8-bit images.
 | |
|     if ((i < 256 && m_map[i] >= 256) || (i >= 256 && m_map[i] < 256))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool Remap::isInvertible(const PalettePicks& usedEntries) const
 | |
| {
 | |
|   PalettePicks picks(size());
 | |
|   const int n = std::min(size(), usedEntries.size());
 | |
|   for (int i = 0; i < n; ++i) {
 | |
|     if (!usedEntries[i])
 | |
|       continue;
 | |
| 
 | |
|     int j = m_map[i];
 | |
|     if (j == kUnused || j == kNoTile) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (picks[j])
 | |
|       return false;
 | |
| 
 | |
|     picks[j] = true;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool Remap::isIdentity() const
 | |
| {
 | |
|   for (int i = 0; i < size(); ++i) {
 | |
|     int j = m_map[i];
 | |
|     if (j != i && j != kUnused) {
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| } // namespace doc
 |