Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / tools / 3d / textures_optimizer / main.cpp
blob3c3292e4584505117f3827c455b1b73b4e8d0177
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "nel/misc/file.h"
21 #include "nel/misc/bitmap.h"
22 #include "nel/misc/path.h"
23 #include "nel/misc/debug.h"
25 #include <iostream>
27 void writeInstructions()
29 std::cout << "Syntax: textures_optimizer [-a] [-g] <input>" << std::endl;
30 std::cout << std::endl;
31 std::cout << " Try to optimize TGA or PNG textures by removing useless alpha channel or converting a RGB with black and white values to grayscale" << std::endl;
32 std::cout << " By default, it only make checks and display if texture can optimized or not" << std::endl;
33 std::cout << std::endl;
34 std::cout << "with" << std::endl;
35 std::cout << "-a : Remove alpha channel if useless (255)" << std::endl;
36 std::cout << "-g : Convert to grayscale if all pixels are gray" << std::endl;
37 std::cout << "-t : Apply texture optimizations (same as -a -g)" << std::endl;
38 std::cout << "-m : Apply mask optimizations (convert to grayscale using red value and remove alpha)" << std::endl;
39 std::cout << std::endl;
40 std::cout << "-h or -? for this help" << std::endl;
41 std::cout << std::endl;
44 bool FixAlpha = false;
45 bool FixGrayscale = false;
46 bool TextureOptimizations = false;
47 bool MaskOptimizations = false;
49 std::vector<std::string> InputFilenames;
51 bool parseOptions(int argc, char **argv)
53 // process each argument
54 for(sint i = 1; i < argc; ++i)
56 std::string option = argv[i];
58 if (option.length() > 0)
60 bool isOption = option[0] == '-';
62 #ifdef NL_OS_WINDOWS
63 // authorize / for options only under Windows,
64 // because under Linux it could be a full path
65 if (!isOption) isOption = (option[0] == '/');
66 #endif
68 // Option
69 if (isOption)
71 // remove option prefix
72 option = option.substr(1);
74 // Fix alpha
75 if (option == "a")
77 FixAlpha = true;
79 // Fix grayscale
80 else if (option == "g")
82 FixGrayscale = true;
84 // Texture optimizations
85 else if (option == "t")
87 TextureOptimizations = true;
88 FixAlpha = true;
89 FixGrayscale = true;
91 // Mask optimizations
92 else if (option == "m")
94 MaskOptimizations = true;
96 else if (option == "h" || option == "?")
98 return false;
100 else
102 nlwarning("Unknown option -%s", option.c_str());
104 return false;
107 // Filename
108 else
110 std::string ext = NLMISC::toLowerAscii(NLMISC::CFile::getExtension(option));
112 if (ext == "png" || ext == "tga")
114 InputFilenames.push_back(option);
116 else
118 nlwarning("Only PNG and TGA files supported, %s won't be processed", option.c_str());
124 return !InputFilenames.empty();
127 #include "nel/misc/system_utils.h"
129 int main(int argc, char **argv)
131 NLMISC::CApplicationContext applicationContext;
133 if (!parseOptions(argc, argv))
135 writeInstructions();
136 return 0;
139 for(uint i = 0; i < InputFilenames.size(); ++i)
141 std::string ext = NLMISC::toLowerAscii(NLMISC::CFile::getExtension(InputFilenames[i]));
143 NLMISC::CIFile input;
145 if (!input.open(InputFilenames[i]))
147 std::cerr << "Unable to open " << InputFilenames[i] << std::endl;
148 return 1;
151 NLMISC::CBitmap bitmap;
153 // all 8 bits textures are grayscale and not alpha
154 bitmap.loadGrayscaleAsAlpha(false);
156 uint8 depth = bitmap.load(input);
158 // don't need file so close it
159 input.close();
161 if (depth == 0)
163 std::cerr << "Unable to decode " << InputFilenames[i] << std::endl;
164 return 1;
167 bool modified = false;
168 bool hasAlpha = false;
169 bool isGrayscale = false;
171 if (bitmap.getPixelFormat() == NLMISC::CBitmap::RGBA && depth == 32)
173 hasAlpha = true;
175 else if (bitmap.getPixelFormat() == NLMISC::CBitmap::AlphaLuminance)
177 hasAlpha = true;
178 isGrayscale = true;
180 else if (bitmap.getPixelFormat() == NLMISC::CBitmap::Luminance)
182 isGrayscale = true;
184 else if (bitmap.getPixelFormat() == NLMISC::CBitmap::Alpha)
186 hasAlpha = true;
187 isGrayscale = true;
190 if (MaskOptimizations && (!isGrayscale || hasAlpha))
192 std::cout << InputFilenames[i] << " (mask with wrong format)" << std::endl;
194 if (!isGrayscale)
196 // get a pointer on original RGBA data
197 uint32 size = bitmap.getPixels().size();
198 uint32 *data = (uint32*)bitmap.getPixels().getPtr();
199 uint32 *endData = (uint32*)((uint8*)data + size);
201 NLMISC::CRGBA *color = NULL;
203 // process all pixels
204 while(data < endData)
206 color = (NLMISC::CRGBA*)data;
208 // copy red value to green and blue,
209 // because only red is used for mask
210 color->B = color->G = color->R;
212 // make opaque
213 color->A = 255;
215 ++data;
219 // already in grayscale, just remove alpha
220 bitmap.convertToType(NLMISC::CBitmap::Luminance);
222 isGrayscale = true;
223 hasAlpha = false;
224 modified = true;
226 else
228 if (!isGrayscale && bitmap.isGrayscale())
230 std::cout << InputFilenames[i] << " (grayscale image with RGB colors)" << std::endl;
232 if (FixGrayscale)
234 if (!bitmap.convertToType(hasAlpha ? NLMISC::CBitmap::AlphaLuminance:NLMISC::CBitmap::Luminance))
236 std::cerr << "Unable to convert to Luminance" << std::endl;
237 return 1;
240 isGrayscale = true;
241 modified = true;
245 uint8 alpha = 0;
247 if (hasAlpha && bitmap.isAlphaUniform(&alpha))
249 std::cout << InputFilenames[i] << " (image with uniform alpha channel " << (sint)alpha << ")" << std::endl;
251 if (FixAlpha && alpha == 255)
253 bitmap.makeOpaque();
255 hasAlpha = false;
256 modified = true;
261 if (!modified) continue;
263 NLMISC::COFile output;
265 if (!output.open(InputFilenames[i]))
267 std::cerr << "Unable to open" << std::endl;
268 return 1;
271 uint32 newDepth = isGrayscale ? 8:24;
273 if (hasAlpha) newDepth += 8;
275 bool res = false;
277 if (ext == "png")
279 res = bitmap.writePNG(output, newDepth);
281 else if (ext == "tga")
283 res = bitmap.writePNG(output, newDepth);
286 if (!res)
288 std::cerr << "Unable to encode" << std::endl;
289 return 1;
293 return 0;