1// Aseprite Document Library
2// Copyright (C) 2019-2021 Igara Studio S.A.
3// Copyright (C) 2001-2016 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "doc/remap.h"
13
14#include "base/base.h"
15#include "doc/palette.h"
16#include "doc/palette_picks.h"
17
18#include <algorithm>
19
20namespace doc {
21
22Remap create_remap_to_move_picks(const PalettePicks& picks, int beforeIndex)
23{
24 Remap map(picks.size());
25
26 int selectedTotal = 0;
27 int selectedBeforeIndex = 0;
28
29 for (int i=0; i<map.size(); ++i) {
30 if (picks[i]) {
31 ++selectedTotal;
32 if (i < beforeIndex)
33 ++selectedBeforeIndex;
34 }
35 }
36
37 for (int i=0, j=0, k=0; i<map.size(); ++i) {
38 if (k == beforeIndex - selectedBeforeIndex)
39 k += selectedTotal;
40
41 if (picks[i]) {
42 map.map(i, beforeIndex - selectedBeforeIndex + j);
43 ++j;
44 }
45 else {
46 map.map(i, k++);
47 }
48 }
49
50 return map;
51}
52
53Remap create_remap_to_expand_palette(int size, int count, int beforeIndex)
54{
55 Remap map(size);
56
57 int j, k = 0;
58 for (int i=0; i<size; ++i) {
59 if (i < beforeIndex)
60 j = i;
61 else if (i + count < size)
62 j = i + count;
63 else
64 j = beforeIndex + (k++);
65
66 map.map(i, j);
67 }
68 return map;
69}
70
71Remap create_remap_to_change_palette(
72 const Palette* oldPalette, const Palette* newPalette,
73 const int oldMaskIndex,
74 const bool remapMaskIndex)
75{
76 Remap remap(std::max(oldPalette->size(), newPalette->size()));
77 int maskIndex = oldMaskIndex;
78
79 if (maskIndex >= 0) {
80 if (remapMaskIndex &&
81 oldPalette->getEntry(maskIndex) !=
82 newPalette->getEntry(maskIndex)) {
83 color_t maskColor = oldPalette->getEntry(maskIndex);
84 int r = rgba_getr(maskColor);
85 int g = rgba_getg(maskColor);
86 int b = rgba_getb(maskColor);
87 int a = rgba_geta(maskColor);
88
89 // Find the new mask color
90 maskIndex = newPalette->findExactMatch(r, g, b, a, -1);
91 if (maskIndex >= 0)
92 remap.map(oldMaskIndex, maskIndex);
93 }
94 else {
95 remap.map(maskIndex, maskIndex);
96 }
97 }
98
99 for (int i=0; i<oldPalette->size(); ++i) {
100 if (i == oldMaskIndex)
101 continue;
102
103 const color_t color = oldPalette->getEntry(i);
104
105 // If in both palettes, it's the same color, we don't need to
106 // remap this entry.
107 if (color == newPalette->getEntry(i)) {
108 remap.map(i, i);
109 continue;
110 }
111
112 int j = newPalette->findExactMatch(
113 rgba_getr(color),
114 rgba_getg(color),
115 rgba_getb(color),
116 rgba_geta(color), maskIndex);
117
118 if (j < 0)
119 j = newPalette->findBestfit(
120 rgba_getr(color),
121 rgba_getg(color),
122 rgba_getb(color),
123 rgba_geta(color), maskIndex);
124
125 remap.map(i, j);
126 }
127 return remap;
128}
129
130void Remap::merge(const Remap& other)
131{
132 for (int i=0; i<size(); ++i) {
133 m_map[i] = other[m_map[i]];
134 }
135}
136
137Remap Remap::invert() const
138{
139 Remap inv(size());
140
141 for (int i=0; i<size(); ++i)
142 inv.unused(i);
143
144 for (int i=0; i<size(); ++i) {
145 int j = m_map[i];
146 if (j == kUnused ||
147 j == kNoTile ||
148 inv.m_map[j] != kUnused) { // Already mapped (strange case, we
149 // cannot invert this Remap)
150 continue;
151 }
152 inv.map(j, i);
153 }
154
155 return inv;
156}
157
158bool Remap::isFor8bit() const
159{
160 for (int i=0; i<size(); ++i) {
161 // Moving entries between [0,255] range to or from [256,+inf)
162 // range are invalid for 8-bit images.
163 if ((i < 256 && m_map[i] >= 256) ||
164 (i >= 256 && m_map[i] < 256))
165 return false;
166 }
167 return true;
168}
169
170bool Remap::isInvertible(const PalettePicks& usedEntries) const
171{
172 PalettePicks picks(size());
173 const int n = std::min(size(), usedEntries.size());
174 for (int i=0; i<n; ++i) {
175 if (!usedEntries[i])
176 continue;
177
178 int j = m_map[i];
179 if (j == kUnused ||
180 j == kNoTile) {
181 continue;
182 }
183
184 if (picks[j])
185 return false;
186
187 picks[j] = true;
188 }
189 return true;
190}
191
192bool Remap::isIdentity() const
193{
194 for (int i=0; i<size(); ++i) {
195 int j = m_map[i];
196 if (j != i &&
197 j != kUnused) {
198 return false;
199 }
200 }
201 return true;
202}
203
204} // namespace doc
205