1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
21 #include "color_modifier.h"
22 #include "color_mask.h"
23 #include "hls_bank_texture_info.h"
24 #define HAS_INFO_GENERATION 0
25 #if HAS_INFO_GENERATION
26 #include "info_color_generation.h"
27 #include "info_mask_generation.h"
30 #include <nel/misc/types_nl.h>
31 #include <nel/misc/config_file.h>
32 #include <nel/misc/path.h>
33 #include <nel/misc/file.h>
34 #include <nel/misc/bitmap.h>
35 #include <nel/misc/debug.h>
39 using namespace NLMISC
;
43 string DivideBy2Dir
= "/d4/";
44 //string HlsInfoDir= "hlsInfo/";
47 // ========================================================================================================
48 // This tool is for creating various colored texture from a base texture.
49 // Parts of a base texture can have hue, contrast, luminosity shifting etc.
50 // Each part is defined by a mask. The red component of it is considered as an alpha value (not the alpha, because it is faster to create a grey texture with photoshop..)
51 // The result is serialized in png or tga files.
52 // ========================================================================================================
53 // why this tool ? : it is useful to create various colored cloth and skin textures
54 // Not all hardware allow it to manage that at runtime (lack for palettized textures or pixel shaders...)
55 //=========================================================================================================
58 /// describes the building infos
61 std::string InputPath
;
62 std::string OutputPath
;
63 std::string HlsInfoPath
;
64 std::string CachePath
;
65 std::vector
<std::string
> BitmapExtensions
; // the supported extension for bitmaps
66 std::string OutputFormat
; // png or tga
67 std::string DefaultSeparator
;
68 TColorMaskVect ColorMasks
;
69 // how to shift right the size of the src Bitmap for the .hlsinfo
71 uint OptimizeTextures
; // 0 = don't check, 1 = check
76 static void validateCgiInfo();
77 static void validateGtmInfo();
81 /** Build the infos we need from a config file
82 * It build a list of masks infos
84 static void BuildMasksFromConfigFile(NLMISC::CConfigFile
&cf
,
85 TColorMaskVect
&colorMasks
);
87 /// Build the colored versions
88 static void BuildColoredVersions(const CBuildInfo
&bi
);
91 static void BuildColoredVersionForOneBitmap(const CBuildInfo
&bi
, const std::string
&fileNameWithExtension
, bool mustDivideBy2
);
92 /** Check if building if reneeded by looking in the cache directory.
93 * If the texture is found in the cache it is just copied
95 static bool CheckIfNeedRebuildColoredVersionForOneBitmap(const CBuildInfo
&bi
, const std::string
&fileNameWithExtension
, bool mustDivideBy2
);
99 /// replace slashes by the matching os value in a file name
100 static std::string
replaceSlashes(const std::string
&src
)
102 std::string result
= src
;
103 for(uint k
= 0; k
< result
.size(); ++k
)
105 if (result
[k
] == '/') result
[k
] = '\\';
107 if (result
[k
] == '\\') result
[k
] = '/';
114 ///=====================================================
115 int main(int argc
, char* argv
[])
117 // Filter addSearchPath
118 NLMISC::createDebug();
120 //"panoply.cfg" "gtm" "fyros"
122 #if HAS_INFO_GENERATION
123 if(!strcmp(argv
[2], "gtm") || !strcmp(argv
[2], "cgi"))
125 NLMISC::CConfigFile cf
;
127 std::string _Path_Input_TexBases
;
128 std::string _Path_Input_Masks
;
129 std::string _Path_Output_MasksOptimized
;
130 std::string _Path_Output_Gtm
;
131 std::string _Path_Output_Cgi
;
135 /// load the config file
141 NLMISC::CConfigFile::CVar
&additionnal_paths
= cf
.getVar ("additionnal_paths");
142 for (uint k
= 0; k
< (uint
) additionnal_paths
.size(); ++k
)
144 NLMISC::CPath::addSearchPath(NLMISC::CPath::standardizePath(additionnal_paths
.asString(k
)),true, false);
147 catch (const NLMISC::EUnknownVar
&)
151 /// repertory of textures bases (no-colorized)
154 _Path_Input_TexBases
= NLMISC::CPath::standardizePath(cf
.getVar ("input_path_texbase").asString());
156 catch (const NLMISC::EUnknownVar
&)
160 /// repertory of masks (original)
163 _Path_Input_Masks
= NLMISC::CPath::standardizePath(cf
.getVar ("input_path_mask").asString());
165 catch (const NLMISC::EUnknownVar
&)
169 /// optimized masks output directory created
172 _Path_Output_MasksOptimized
= NLMISC::CPath::standardizePath(cf
.getVar ("output_path_mask_optimized").asString());
174 catch (const NLMISC::EUnknownVar
&)
178 /// file of infos about colorization average for the client
181 _Path_Output_Cgi
= NLMISC::CPath::standardizePath(cf
.getVar ("output_path_cgi").asString());
183 catch (const NLMISC::EUnknownVar
&)
187 /// file of infos about multiplexing texture for the client
190 _Path_Output_Gtm
= NLMISC::CPath::standardizePath(cf
.getVar ("output_path_gtm").asString());
192 catch (const NLMISC::EUnknownVar
&)
197 catch (const std::exception
&e
)
199 nlerror("Panoply building failed: %s", e
.what());
205 if( !strcmp(argv
[2], "gtm")) /// masks optimized
207 CInfoMaskGeneration
infoMaskGen(_Path_Input_TexBases
,
209 _Path_Output_MasksOptimized
,
214 infoMaskGen
.process();
216 else if( !strcmp(argv
[2], "cgi")) /// colorized information
218 CInfoColorGeneration
infoColor(_Path_Input_TexBases
,
230 NLMISC::InfoLog
->addNegativeFilter ("adding the path");
234 nlinfo("Usage : %s [config_file name]", argv
[0]);
240 /////////////////////////////////////////
241 // reads infos from the config files //
242 /////////////////////////////////////////
244 NLMISC::CConfigFile cf
;
247 /// load the config file
251 BuildMasksFromConfigFile(cf
, bi
.ColorMasks
);
256 NLMISC::CConfigFile::CVar
&additionnal_paths
= cf
.getVar ("additionnal_paths");
257 for (uint k
= 0; k
< (uint
) additionnal_paths
.size(); ++k
)
259 NLMISC::CPath::addSearchPath(NLMISC::CPath::standardizePath(additionnal_paths
.asString(k
)));
262 catch (const NLMISC::EUnknownVar
&)
269 bi
.InputPath
= NLMISC::CPath::standardizePath(cf
.getVar ("input_path").asString());
271 catch (const NLMISC::EUnknownVar
&)
278 bi
.OutputPath
= NLMISC::CPath::standardizePath(cf
.getVar ("output_path").asString());
280 catch (const NLMISC::EUnknownVar
&)
287 bi
.HlsInfoPath
= NLMISC::CPath::standardizePath(cf
.getVar("hls_info_path").asString());
289 catch (const NLMISC::EUnknownVar
&)
291 bi
.HlsInfoPath
= "hlsInfo/";
297 bi
.CachePath
= NLMISC::CPath::standardizePath(cf
.getVar ("cache_path").asString());
299 catch (const NLMISC::EUnknownVar
&)
306 bi
.OutputFormat
= "." + cf
.getVar ("output_format").asString();
308 catch (const NLMISC::EUnknownVar
&)
310 bi
.OutputFormat
= ".tga";
313 /// default ascii character for unused masks
316 bi
.DefaultSeparator
= cf
.getVar ("default_separator").asString();
318 catch (const NLMISC::EUnknownVar
&)
320 bi
.DefaultSeparator
= '_';
322 /// extension for bitmaps
325 NLMISC::CConfigFile::CVar
&bitmap_extensions
= cf
.getVar ("bitmap_extensions");
326 for (uint k
= 0; k
< (uint
) bitmap_extensions
.size(); ++k
)
328 std::string ext
= "." + NLMISC::toLowerAscii(bitmap_extensions
.asString(k
));
329 if (std::find(bi
.BitmapExtensions
.begin(), bi
.BitmapExtensions
.end(), ext
) == bi
.BitmapExtensions
.end())
331 bi
.BitmapExtensions
.push_back(ext
);
335 catch (const NLMISC::EUnknownVar
&)
337 bi
.BitmapExtensions
[0].resize(1);
338 bi
.BitmapExtensions
[0] = bi
.OutputFormat
;
343 bi
.LowDefShift
= cf
.getVar ("low_def_shift").asInt();
345 catch (const NLMISC::EUnknownVar
&)
347 // tranform 512*512 to 64*64 by default
353 bi
.OptimizeTextures
= cf
.getVar ("optimize_textures").asInt();
355 catch (const NLMISC::EUnknownVar
&)
357 // don't check files by default
358 bi
.OptimizeTextures
= 0;
361 catch (const std::exception
&e
)
363 nlerror("Panoply building failed: %s", e
.what());
367 ////////////////////////////////
368 // Build the colored versions //
369 ////////////////////////////////
372 BuildColoredVersions(bi
);
374 catch (const std::exception
&e
)
376 nlerror("Something went wrong while building bitmap: %s", e
.what());
380 #if HAS_INFO_GENERATION
385 ///======================================================
386 #if HAS_INFO_GENERATION
387 static void validateCgiInfo()
392 vector
<StrInfoTexColor
> temp
;
397 f
.open(CPath::lookup("info_color_texbase_fyros.cgi"));
402 catch(const std::exception
&e
)
404 nlerror("Panoply building failed: %s", e
.what());
407 uint16 a
= temp
.size();
412 ///======================================================
414 static void validateGtmInfo()
419 ///======================================================
420 static void BuildMasksFromConfigFile(NLMISC::CConfigFile
&cf
,
421 TColorMaskVect
&colorMasks
)
424 /// get a list of the alpha mask extensions
425 NLMISC::CConfigFile::CVar
&mask_extensions
= cf
.getVar ("mask_extensions");
426 colorMasks
.resize(mask_extensions
.size());
428 /// For each kind of mask, build a list of the color modifiers
429 for (uint k
= 0; k
< (uint
) mask_extensions
.size(); ++k
)
431 colorMasks
[k
].MaskExt
= mask_extensions
.asString(k
);
432 NLMISC::CConfigFile::CVar
&luminosities
= cf
.getVar (colorMasks
[k
].MaskExt
+ "_luminosities");
433 NLMISC::CConfigFile::CVar
&contrasts
= cf
.getVar (colorMasks
[k
].MaskExt
+ "_constrasts");
434 NLMISC::CConfigFile::CVar
&hues
= cf
.getVar (colorMasks
[k
].MaskExt
+ "_hues");
435 NLMISC::CConfigFile::CVar
&lightness
= cf
.getVar (colorMasks
[k
].MaskExt
+ "_lightness");
436 NLMISC::CConfigFile::CVar
&saturation
= cf
.getVar (colorMasks
[k
].MaskExt
+ "_saturations");
437 NLMISC::CConfigFile::CVar
&colorIDs
= cf
.getVar (colorMasks
[k
].MaskExt
+ "_color_id");
439 if (luminosities
.size() != contrasts
.size()
440 || luminosities
.size() != hues
.size()
441 || luminosities
.size() != lightness
.size()
442 || luminosities
.size() != saturation
.size()
443 || luminosities
.size() != colorIDs
.size()
446 throw NLMISC::Exception("All color descriptors must have the same number of arguments");
448 colorMasks
[k
].CMs
.resize(luminosities
.size());
449 for (uint l
= 0; l
< (uint
) luminosities
.size(); ++l
)
451 CColorModifier
&cm
= colorMasks
[k
].CMs
[l
];
452 cm
.Contrast
= contrasts
.asFloat(l
);
453 cm
.Luminosity
= luminosities
.asFloat(l
);
454 cm
.Hue
= hues
.asFloat(l
);
455 cm
.Lightness
= lightness
.asFloat(l
);
456 cm
.Saturation
= saturation
.asFloat(l
);
458 cm
.ColID
= colorIDs
.asString(l
);
463 ///======================================================
464 static void BuildColoredVersions(const CBuildInfo
&bi
)
466 if (!NLMISC::CFile::isExists(bi
.InputPath
))
468 nlerror("Path not found: %s", bi
.InputPath
.c_str());
471 for(uint sizeVersion
= 0; sizeVersion
<2; sizeVersion
++)
473 std::vector
<std::string
> files
;
475 // get the original (not to dvide) dir
476 NLMISC::CPath::getPathContent (bi
.InputPath
, false, false, true, files
);
478 // get the dir content with texture that must be divided by 2.
479 NLMISC::CPath::getPathContent (bi
.InputPath
+DivideBy2Dir
, false, false, true, files
);
481 // For all files found
482 for (uint k
= 0; k
< files
.size(); ++k
)
484 for (uint l
= 0; l
< bi
.BitmapExtensions
.size(); ++l
)
486 std::string fileExt
= "." + NLMISC::toLowerAscii(NLMISC::CFile::getExtension(files
[k
]));
487 if (fileExt
== bi
.BitmapExtensions
[l
])
489 //nlwarning("Processing : %s ", files[k].c_str());
492 if (CheckIfNeedRebuildColoredVersionForOneBitmap(bi
, NLMISC::CFile::getFilename(files
[k
]),
495 BuildColoredVersionForOneBitmap(bi
,
496 NLMISC::CFile::getFilename(files
[k
]),
501 //nlwarning(("No need to rebuild " + NLMISC::CFile::getFilename(files[k])).c_str());
504 catch (const std::exception
&e
)
506 nlerror("Processing of %s failed: %s", files
[k
].c_str(), e
.what());
515 /// used to loop throiugh the process, avoiding unused masks
518 NLMISC::CBitmap Mask
;
524 ///======================================================
525 static bool CheckIfNeedRebuildColoredVersionForOneBitmap(const CBuildInfo
&bi
, const std::string
&fileNameWithExtension
,
528 if (bi
.CachePath
.empty()) return true;
529 uint32 srcDate
= (uint32
) NLMISC::CFile::getFileModificationDate(replaceSlashes(bi
.InputPath
+ fileNameWithExtension
));
530 static std::vector
<CLoopInfo
> masks
;
531 /// check the needed masks
534 std::string fileName
= NLMISC::CFile::getFilenameWithoutExtension(fileNameWithExtension
);
535 std::string fileExt
= NLMISC::toLowerAscii(NLMISC::CFile::getExtension(fileNameWithExtension
));
537 for (uint k
= 0; k
< bi
.ColorMasks
.size(); ++k
)
539 std::string maskName
= fileName
+ "_" + bi
.ColorMasks
[k
].MaskExt
+ "." + fileExt
;
540 std::string maskFileName
= NLMISC::CPath::lookup(maskName
,
542 if (!maskFileName
.empty()) // found the mask ?
548 if (NLMISC::CFile::fileExists(maskFileName
))
550 srcDate
= std::max(srcDate
, (uint32
) NLMISC::CFile::getFileModificationDate(replaceSlashes(maskFileName
)));
556 // get hls info version that is in the cache. if not possible, must rebuild
557 std::string outputHLSInfo
= bi
.HlsInfoPath
+ fileName
+ ".hlsinfo";
558 std::string cacheHLSInfo
= bi
.CachePath
+ fileName
+ ".hlsinfo";
559 if (!NLMISC::CFile::fileExists(cacheHLSInfo
.c_str()) )
563 // Must now if was moved beetween normal dir and d4/ dir.
564 CHLSBankTextureInfo hlsInfo
;
565 // read .hlsInfo cache
567 if(!f
.open(cacheHLSInfo
))
571 // check if same DividedBy2 Flag.
572 if(hlsInfo
.DividedBy2
!=mustDivideBy2
)
575 // ok, can move the cache
576 if (!NLMISC::CFile::moveFile(outputHLSInfo
, cacheHLSInfo
))
578 nlerror("Couldn't move %s to %s", cacheHLSInfo
.c_str(), outputHLSInfo
.c_str());
584 /// check is each generated texture has the same date or is more recent
588 std::string outputFileName
= fileName
;
590 /// build current tex name
591 for (l
= 0; l
< masks
.size(); ++l
)
593 uint maskID
= masks
[l
].MaskID
;
594 uint colorID
= masks
[l
].Counter
;
595 /// complete the file name
596 outputFileName
+= bi
.DefaultSeparator
+ bi
.ColorMasks
[maskID
].CMs
[colorID
].ColID
;
600 std::string searchName
= replaceSlashes(bi
.CachePath
+ outputFileName
+ bi
.OutputFormat
);
601 if ((uint32
) NLMISC::CFile::getFileModificationDate(searchName
) < srcDate
)
603 return true; // not found or more old => need rebuild
606 // get version that is in the cache
607 std::string cacheDest
= bi
.OutputPath
+ outputFileName
+ bi
.OutputFormat
;
609 if (!NLMISC::CFile::moveFile(cacheDest
, searchName
))
611 nlerror("Couldn't move %s to %s", searchName
.c_str(), cacheDest
.c_str());
615 /// increment counters
616 for (l
= 0; l
< (uint
) masks
.size(); ++l
)
618 ++ (masks
[l
].Counter
);
620 /// check if we have done all colors for this mask
621 if (masks
[l
].Counter
== bi
.ColorMasks
[masks
[l
].MaskID
].CMs
.size())
623 masks
[l
].Counter
= 0;
630 if (l
== masks
.size()) break; // all cases dones
632 return false; // nothing to rebuild
637 ///======================================================
638 static void BuildColoredVersionForOneBitmap(const CBuildInfo
&bi
, const std::string
&fileNameWithExtension
,
642 NLMISC::CBitmap srcBitmap
;
643 NLMISC::CBitmap resultBitmap
;
645 /// **** load the src bitmap
648 string actualInputPath
;
650 actualInputPath
= bi
.InputPath
+ DivideBy2Dir
;
652 actualInputPath
= bi
.InputPath
;
655 std::string fullInputBitmapPath
= actualInputPath
+ fileNameWithExtension
;
660 if (is
.open(fullInputBitmapPath
))
662 // 8 bits textures are grayscale
663 srcBitmap
.loadGrayscaleAsAlpha(false);
665 depth
= srcBitmap
.load(is
);
668 if (depth
== 0 || srcBitmap
.getPixels().empty())
670 throw NLMISC::Exception("Failed to load bitmap");
673 // if bitmap is RGBA but has an alpha channel fully opaque (255),
674 // we can save it as RGB to optimize it
676 if (bi
.OptimizeTextures
> 0 && depth
== 32 && srcBitmap
.isAlphaUniform(&value
) && value
== 255)
678 nlwarning("Texture %s can be optimized, run textures_optimizer", fullInputBitmapPath
.c_str());
681 if (srcBitmap
.PixelFormat
!= NLMISC::CBitmap::RGBA
)
683 srcBitmap
.convertToType(NLMISC::CBitmap::RGBA
);
688 nlerror("Unable to open %s. Processing next", fullInputBitmapPath
.c_str());
692 catch (const NLMISC::Exception
&e
)
694 nlerror("File or format error with %s (%s). Processing next...", fullInputBitmapPath
.c_str(), e
.what());
699 /// **** Build and prepare build of the .hlsinfo to write.
700 CHLSBankTextureInfo hlsInfo
;
701 CBitmap hlsInfoSrcBitmap
;
702 hlsInfoSrcBitmap
= srcBitmap
;
703 // reduce size of the bitmap of LowDef shift
704 uint reduceShift
= bi
.LowDefShift
;
707 uint w
= hlsInfoSrcBitmap
.getWidth()>>reduceShift
;
708 uint h
= hlsInfoSrcBitmap
.getHeight()>>reduceShift
;
711 hlsInfoSrcBitmap
.resample(w
, h
);
713 // Compress DXTC5 src bitmap
714 hlsInfo
.SrcBitmap
.build(hlsInfoSrcBitmap
);
715 // Store info about if where in d4/ dir or not
716 hlsInfo
.DividedBy2
= mustDivideBy2
;
719 /// **** check the needed masks
720 static std::vector
<CLoopInfo
> masks
;
723 std::string fileName
= NLMISC::CFile::getFilenameWithoutExtension(fileNameWithExtension
);
724 std::string fileExt
= NLMISC::toLowerAscii(NLMISC::CFile::getExtension(fileNameWithExtension
));
727 for (k
= 0; k
< bi
.ColorMasks
.size(); ++k
)
729 std::string maskName
= fileName
+ "_" + bi
.ColorMasks
[k
].MaskExt
+ "." + fileExt
;
730 std::string maskFileName
= NLMISC::CPath::lookup(maskName
, false, false);
732 if (!maskFileName
.empty()) // found the mask ?
738 /// try to load the bitmap
743 if (is
.open(maskFileName
))
745 // masks are always opaque, if the mask is 8bits, it's in grayscale
746 li
.Mask
.loadGrayscaleAsAlpha(false);
748 uint8 maskDepth
= li
.Mask
.load(is
);
752 if (maskDepth
== 0 || li
.Mask
.getPixels().empty())
754 throw NLMISC::Exception("Failed to load mask");
757 // display a warning if checks enabled
758 if (li
.Mask
.getPixelFormat() == CBitmap::RGBA
&& bi
.OptimizeTextures
> 0 && !li
.Mask
.isGrayscale())
760 nlwarning("Mask %s is using colors, results may by incorrect! Run textures_optimizer to fix it.", maskFileName
.c_str());
763 // convert image to real grayscale
764 if (li
.Mask
.PixelFormat
!= NLMISC::CBitmap::Luminance
)
766 li
.Mask
.convertToType(NLMISC::CBitmap::Luminance
);
769 /// make sure the mask has the same size
770 if (li
.Mask
.getWidth() != srcBitmap
.getWidth()
771 || li
.Mask
.getHeight() != srcBitmap
.getHeight())
773 throw NLMISC::Exception("Bitmap and mask do not have the same size");
780 nlerror("Unable to open %s. Processing next", maskFileName
.c_str());
784 catch (const std::exception
&e
)
786 nlerror("Error with %s: %s. Aborting this bitmap processing", maskFileName
.c_str(), e
.what());
792 // **** Add the masks to the .hlsInfo
793 hlsInfo
.Masks
.resize(masks
.size());
794 for (k
= 0; k
< masks
.size(); ++k
)
796 CLoopInfo
&li
= masks
[k
];
797 CBitmap tmp
= li
.Mask
;
798 tmp
.resample(hlsInfoSrcBitmap
.getWidth(), hlsInfoSrcBitmap
.getHeight());
799 hlsInfo
.Masks
[k
].build(tmp
);
803 // **** generate each texture
804 // NB : if there are no masks the texture just will be copied
807 resultBitmap
= srcBitmap
;
809 std::string outputFileName
= fileName
;
811 // Add an instance entry to the hlsInfo
812 uint instId
= (uint
)hlsInfo
.Instances
.size();
813 hlsInfo
.Instances
.resize(instId
+1);
814 CHLSBankTextureInfo::CTextureInstance
&hlsTextInstance
= hlsInfo
.Instances
[instId
];
815 hlsTextInstance
.Mods
.resize(masks
.size());
817 /// build current tex
818 for (l
= 0; l
< masks
.size(); ++l
)
820 uint maskID
= masks
[l
].MaskID
;
821 uint colorID
= masks
[l
].Counter
;
823 /// get the color modifier
824 const CColorModifier
&cm
= bi
.ColorMasks
[maskID
].CMs
[colorID
];
827 float deltaHueApplied
;
828 cm
.convertBitmap(resultBitmap
, resultBitmap
, masks
[l
].Mask
, deltaHueApplied
);
830 /// save the setup in hlsInfo
831 hlsTextInstance
.Mods
[l
].DHue
= deltaHueApplied
;
832 hlsTextInstance
.Mods
[l
].DLum
= cm
.Lightness
;
833 hlsTextInstance
.Mods
[l
].DSat
= cm
.Saturation
;
835 /// complete the file name
836 outputFileName
+= bi
.DefaultSeparator
+ bi
.ColorMasks
[maskID
].CMs
[colorID
].ColID
;
839 // save good hlsInfo instance name
840 hlsTextInstance
.Name
= outputFileName
+ bi
.OutputFormat
;
842 nlinfo("Writing %s", outputFileName
.c_str());
843 /// Save the result. We let propagate exceptions (if there's no more space disk it useless to continue...)
845 std::string fullOutputPath
= bi
.OutputPath
+ outputFileName
+ bi
.OutputFormat
;
850 if (os
.open(fullOutputPath
))
852 // divide by 2 when needed.
854 resultBitmap
.resample( (resultBitmap
.getWidth()+1)/2, (resultBitmap
.getHeight()+1)/2 );
856 if (bi
.OutputFormat
== ".png")
858 resultBitmap
.writePNG(os
, depth
);
862 resultBitmap
.writeTGA(os
, depth
);
867 nlerror("Couldn't open %s for writing", fullOutputPath
.c_str());
870 catch(const NLMISC::EStream
&e
)
872 nlerror("Couldn't write %s: %s", fullOutputPath
.c_str(), e
.what());
877 /// increment counters
878 for (l
= 0; l
< (uint
) masks
.size(); ++l
)
880 ++ (masks
[l
].Counter
);
882 /// check if we have done all colors for this mask
883 if (masks
[l
].Counter
== bi
.ColorMasks
[masks
[l
].MaskID
].CMs
.size())
885 masks
[l
].Counter
= 0;
892 if (l
== masks
.size()) break; // all cases dones
895 // **** save the TMP hlsInfo
896 std::string fullHlsInfoPath
= bi
.HlsInfoPath
+ fileName
+ ".hlsinfo";
899 if (os
.open(fullHlsInfoPath
))
905 nlerror("Couldn't write %s", fullHlsInfoPath
.c_str());