| 
									
										
										
										
											2015-03-23 23:25:32 +08:00
										 |  |  | // Aseprite Document Library
 | 
					
						
							| 
									
										
										
										
											2021-05-12 03:31:59 +08:00
										 |  |  | // Copyright (C) 2019-2021  Igara Studio S.A.
 | 
					
						
							| 
									
										
										
										
											2019-08-05 19:36:47 +08:00
										 |  |  | // Copyright (C) 2001-2016  David Capello
 | 
					
						
							| 
									
										
										
										
											2015-03-23 23:25:32 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 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"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-04 06:18:46 +08:00
										 |  |  | #include "base/base.h"
 | 
					
						
							| 
									
										
										
										
											2015-07-29 04:16:32 +08:00
										 |  |  | #include "doc/palette.h"
 | 
					
						
							| 
									
										
										
										
											2015-05-09 23:20:58 +08:00
										 |  |  | #include "doc/palette_picks.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 23:03:32 +08:00
										 |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 23:25:32 +08:00
										 |  |  | namespace doc { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-10 02:57:46 +08:00
										 |  |  | Remap create_remap_to_move_picks(const PalettePicks& picks, int beforeIndex) | 
					
						
							| 
									
										
										
										
											2015-03-23 23:25:32 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-05-09 23:20:58 +08:00
										 |  |  |   Remap map(picks.size()); | 
					
						
							| 
									
										
										
										
											2015-03-23 23:25:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   int selectedTotal = 0; | 
					
						
							|  |  |  |   int selectedBeforeIndex = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0; i < map.size(); ++i) { | 
					
						
							| 
									
										
										
										
											2015-05-09 23:20:58 +08:00
										 |  |  |     if (picks[i]) { | 
					
						
							| 
									
										
										
										
											2015-03-23 23:25:32 +08:00
										 |  |  |       ++selectedTotal; | 
					
						
							|  |  |  |       if (i < beforeIndex) | 
					
						
							|  |  |  |         ++selectedBeforeIndex; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0, j = 0, k = 0; i < map.size(); ++i) { | 
					
						
							|  |  |  |     if (k == beforeIndex - selectedBeforeIndex) | 
					
						
							|  |  |  |       k += selectedTotal; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-09 23:20:58 +08:00
										 |  |  |     if (picks[i]) { | 
					
						
							| 
									
										
										
										
											2015-03-23 23:25:32 +08:00
										 |  |  |       map.map(i, beforeIndex - selectedBeforeIndex + j); | 
					
						
							|  |  |  |       ++j; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       map.map(i, k++); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return map; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-10 02:57:46 +08:00
										 |  |  | 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-29 04:16:32 +08:00
										 |  |  | Remap create_remap_to_change_palette(const Palette* oldPalette, | 
					
						
							|  |  |  |                                      const Palette* newPalette, | 
					
						
							| 
									
										
										
										
											2015-08-01 00:32:23 +08:00
										 |  |  |                                      const int oldMaskIndex, | 
					
						
							|  |  |  |                                      const bool remapMaskIndex) | 
					
						
							| 
									
										
										
										
											2015-07-29 04:16:32 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-04-08 23:03:32 +08:00
										 |  |  |   Remap remap(std::max(oldPalette->size(), newPalette->size())); | 
					
						
							| 
									
										
										
										
											2015-07-29 04:16:32 +08:00
										 |  |  |   int maskIndex = oldMaskIndex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (maskIndex >= 0) { | 
					
						
							| 
									
										
										
										
											2015-08-01 00:32:23 +08:00
										 |  |  |     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); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-07-29 04:16:32 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0; i < oldPalette->size(); ++i) { | 
					
						
							|  |  |  |     if (i == oldMaskIndex) | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const color_t color = oldPalette->getEntry(i); | 
					
						
							| 
									
										
										
										
											2016-03-25 04:37:04 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // 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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-29 04:16:32 +08:00
										 |  |  |     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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 23:57:59 +08:00
										 |  |  | 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()); | 
					
						
							| 
									
										
										
										
											2020-07-21 03:25:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0; i < size(); ++i) | 
					
						
							| 
									
										
										
										
											2021-05-21 06:43:18 +08:00
										 |  |  |     inv.unused(i); | 
					
						
							| 
									
										
										
										
											2020-07-21 03:25:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 19:36:47 +08:00
										 |  |  |   for (int i = 0; i < size(); ++i) { | 
					
						
							|  |  |  |     int j = m_map[i]; | 
					
						
							| 
									
										
										
										
											2021-05-24 00:16:36 +08:00
										 |  |  |     if (j == kUnused || j == kNoTile || inv.m_map[j] != kUnused) { // Already mapped (strange case,
 | 
					
						
							|  |  |  |                                                                    // we cannot invert this Remap)
 | 
					
						
							| 
									
										
										
										
											2019-08-05 19:36:47 +08:00
										 |  |  |       continue; | 
					
						
							| 
									
										
										
										
											2021-05-24 00:16:36 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-05 19:36:47 +08:00
										 |  |  |     inv.map(j, i); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-21 03:25:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 23:57:59 +08:00
										 |  |  |   return inv; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-07 03:15:54 +08:00
										 |  |  | 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-29 04:16:32 +08:00
										 |  |  | bool Remap::isInvertible(const PalettePicks& usedEntries) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   PalettePicks picks(size()); | 
					
						
							| 
									
										
										
										
											2021-05-12 03:31:59 +08:00
										 |  |  |   const int n = std::min(size(), usedEntries.size()); | 
					
						
							|  |  |  |   for (int i = 0; i < n; ++i) { | 
					
						
							| 
									
										
										
										
											2015-07-29 04:16:32 +08:00
										 |  |  |     if (!usedEntries[i]) | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int j = m_map[i]; | 
					
						
							| 
									
										
										
										
											2021-05-24 00:16:36 +08:00
										 |  |  |     if (j == kUnused || j == kNoTile) { | 
					
						
							| 
									
										
										
										
											2019-08-05 19:36:47 +08:00
										 |  |  |       continue; | 
					
						
							| 
									
										
										
										
											2021-05-24 00:16:36 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-05 19:36:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-29 04:16:32 +08:00
										 |  |  |     if (picks[j]) | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     picks[j] = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 19:36:47 +08:00
										 |  |  | bool Remap::isIdentity() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   for (int i = 0; i < size(); ++i) { | 
					
						
							| 
									
										
										
										
											2021-05-24 00:16:36 +08:00
										 |  |  |     int j = m_map[i]; | 
					
						
							|  |  |  |     if (j != i && j != kUnused) { | 
					
						
							| 
									
										
										
										
											2019-08-05 19:36:47 +08:00
										 |  |  |       return false; | 
					
						
							| 
									
										
										
										
											2021-05-24 00:16:36 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-05 19:36:47 +08:00
										 |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 23:25:32 +08:00
										 |  |  | } // namespace doc
 |