1 // Aseprite
2 // Copyright (C) 2001-2018 David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include "app/modules/palettes.h"
12
13 #include "app/app.h"
14 #include "app/extensions.h"
15 #include "app/file/palette_file.h"
16 #include "app/resource_finder.h"
17 #include "base/fs.h"
18 #include "doc/image.h"
19 #include "doc/palette.h"
20 #include "doc/sprite.h"
21
22 #include <cstring>
23
24 namespace app {
25
26 // The default color palette.
27 static Palette* ase_default_palette = NULL;
28
29 // Palette in current sprite frame.
30 static Palette* ase_current_palette = NULL;
31
init_module_palette()32 int init_module_palette()
33 {
34 ase_default_palette = new Palette(frame_t(0), 256);
35 ase_current_palette = new Palette(frame_t(0), 256);
36 return 0;
37 }
38
exit_module_palette()39 void exit_module_palette()
40 {
41 delete ase_default_palette;
42 delete ase_current_palette;
43 }
44
load_default_palette()45 void load_default_palette()
46 {
47 base::UniquePtr<Palette> pal;
48 std::string defaultPalName = get_preset_palette_filename(
49 get_default_palette_preset_name(), ".ase");
50
51 // If there is no palette in command line, we use the default one.
52 std::string palFile = defaultPalName;
53 if (base::is_file(palFile)) {
54 pal.reset(load_palette(palFile.c_str()));
55 }
56 else {
57 // Migrate old default.gpl to default.ase format
58 palFile = get_preset_palette_filename(
59 get_default_palette_preset_name(), ".gpl");
60
61 if (base::is_file(palFile)) {
62 pal.reset(load_palette(palFile.c_str()));
63
64 // Remove duplicate black entries at the end (as old palettes
65 // contains 256 colors)
66 if (pal && pal->size() == 256) {
67 doc::color_t black = rgba(0, 0, 0, 255);
68
69 // Get the last non-black entry
70 int i = 0;
71 for (i=pal->size()-1; i>0; --i) {
72 if (pal->getEntry(i) != black)
73 break;
74 }
75
76 if (i < pal->size()-1) {
77 // Check if there is a black entry in the first entries.
78 bool hasBlack = false;
79 for (int j=0; j<i; ++j) {
80 if (pal->getEntry(j) == black) {
81 hasBlack = true;
82 break;
83 }
84 }
85 if (!hasBlack)
86 ++i; // Leave one black entry
87
88 // Resize the palette
89 if (i < pal->size()-1)
90 pal->resize(i+1);
91 }
92 }
93
94 // We could remove the old .gpl file (palFile), but as the
95 // user could be using multiple versions of Aseprite, it's a
96 // good idea to keep both formats (.gpl for Aseprite <=
97 // v1.1-beta5, and .ase for future versions).
98 }
99 // If the default palette file doesn't exist, we copy db32.gpl
100 // as the default one (default.ase).
101 else {
102 std::string path = App::instance()->extensions().palettePath("DB32");
103 if (path.empty())
104 path = App::instance()->extensions().palettePath("VGA 13h");
105 if (!path.empty())
106 pal.reset(load_palette(path.c_str()));
107 }
108
109 // Save default.ase file
110 if (pal) {
111 palFile = defaultPalName;
112 save_palette(palFile.c_str(), pal.get(), 0);
113 }
114 }
115
116 if (pal)
117 set_default_palette(pal.get());
118
119 set_current_palette(nullptr, true);
120 }
121
get_current_palette()122 Palette* get_current_palette()
123 {
124 return ase_current_palette;
125 }
126
get_default_palette()127 Palette* get_default_palette()
128 {
129 return ase_default_palette;
130 }
131
set_default_palette(const Palette * palette)132 void set_default_palette(const Palette* palette)
133 {
134 palette->copyColorsTo(ase_default_palette);
135 }
136
137 // Changes the current system palette and triggers the
138 // App::PaletteChange signal.
139 //
140 // If "_palette" is nullptr the default palette is set.
set_current_palette(const Palette * _palette,bool forced)141 bool set_current_palette(const Palette *_palette, bool forced)
142 {
143 const Palette* palette = (_palette ? _palette: ase_default_palette);
144 bool ret = false;
145
146 // Have changes
147 if (forced ||
148 palette->countDiff(ase_current_palette, NULL, NULL) > 0) {
149 // Copy current palette
150 palette->copyColorsTo(ase_current_palette);
151
152 // Call slots in signals
153 App::instance()->PaletteChange();
154
155 ret = true;
156 }
157
158 return ret;
159 }
160
get_preset_palette_filename(const std::string & preset,const std::string & dot_extension)161 std::string get_preset_palette_filename(const std::string& preset,
162 const std::string& dot_extension)
163 {
164 ResourceFinder rf;
165 rf.includeUserDir(base::join_path("palettes", ".").c_str());
166 std::string palettesDir = rf.getFirstOrCreateDefault();
167
168 if (!base::is_directory(palettesDir))
169 base::make_directory(palettesDir);
170
171 return base::join_path(palettesDir, preset + dot_extension);
172 }
173
get_default_palette_preset_name()174 std::string get_default_palette_preset_name()
175 {
176 return "default";
177 }
178
179 } // namespace app
180