diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e0fc7e9..793445e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,6 +6,7 @@ "command": "C:\\msys64\\mingw64\\bin\\g++.exe", "args": [ "-fdiagnostics-color=always", + "-static", "--std", "c++20", "-g", diff --git a/Makefile b/Makefile index 612a2cb..8de8c4b 100644 --- a/Makefile +++ b/Makefile @@ -4,11 +4,11 @@ # Compiler settings - Can be customized. CC = g++ -CXXFLAGS = -std=c++20 -Wall +CXXFLAGS = -std=c++20 -Wall -static LDFLAGS = # Makefile settings - Can be customized. -APPNAME = avatar-font-tool +APPNAME = hdosd-font-tool EXT = .cpp SRCDIR = $(CURDIR) OBJDIR = obj diff --git a/README.md b/README.md index bc23ae4..17bd52b 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,20 @@ # HD OSD Font Tool -A tool for compiling fonts for HD OSD systems. The Avatar (Walksnail/Caddx) HD system is currently supported. +A tool for compiling fonts for HD system OSDs. Currently, only the Avatar (Walksnail/Caddx) and HDZero HD systems are supported. ## Introduction This work was initially done as part of preparing the [INAV](https://github.com/iNavFlight) font for the Avatar HD system. In INAV, the characters each have their own image file. This makes editing and customising the fonts much simpler. My plan was to take the same approach with the Avatar font; and have a tool to compile the image used in their firmware. Inspiration coming from the [max67456tool](https://github.com/fiam/max7456tool) by fiam. ## The Tool -The HD OSD Font Tool will take the individual character images and convert them in to the image used by Avatar. It will also convert alternate fonts found in the same main directory that the program is run from or pointed to. An optional name can also be given for the output files. This is all done without the need for configuration files. However, there are a couple of caveats for using the tool. +The HD OSD Font Tool will take the individual character images and convert them in to the image used by OSDs. It will also convert alternate fonts found in the same main directory that the program is run from or pointed to. An optional name can also be given for the output files. This is all done without the need for configuration files. However, there are a couple of caveats for using the tool. ### The Avatar font image file -The Avatar firmware uses a PNG file for it's fonts. It does use alpha transparency, so you can create some really cool symbols. The current Avatar firmware uses a font file which is one character wide by 256 characters x the number of pages high. At this point in time, INAV uses 2 pages (so 512 characters high). Whereas, BetaFlight and ArduPilot use 1 page (256 characters high). BetaFlight will start using 4 pages in version 4.4. This would have meant a 1024 character high image. Not only would this be unwieldy. It also may be to tall to open in some image editing tools. So, the format of the Avatar font file will change to multiple columns of 256 characters. ArduPilot would not change. That would still be 1 character by 256 characters. BetaFlight will be 4 characters by 256 characters. Finally, INAV will be 2 characters by 256 characters. - -This tool has been updated in preparation for this change. Currently, it will create the one character by 256 (BF/Ardu) or 512 (INAV) characters high font. To generate the multiple column font. Use the `-xcols` argument in the command line. +The Avatar firmware uses a PNG file for it's fonts. It does use alpha transparency, so you can create some really cool symbols. The current Avatar firmware uses a font file which is one character wide by 256 characters x the number of pages high. At this point in time, INAV uses 2 pages (so 512 characters high). Whereas, BetaFlight and ArduPilot use 1 page (256 characters high). BetaFlight now also use 4 pages, from version 4.4. ### The image files -Image files must be stored as PNG files with transparency. The Avatar system uses the transparent pixels, rather than having a mid grey background which is removed. This means that alpha transparency and full colour can be used in your fonts. There are three sizes of fonts: +Image files must be stored as PNG files with transparency. The Avatar and WTF OS systems use transparent pixels, rather than having a mid grey background which is removed. This means that alpha transparency and full colour can be used in your fonts. HDZero uses a grey background for transparency. This will be added by the tool for HDZero. There are three sizes of fonts: - **12 x 18 pixels** This is the small font, the same size as analogue -- **24 x 36 pixels** This is a mid size font -- **36 x 54 pixels** This is the large font +- **24 x 36 pixels** This is a mid size font for Avatar, and the font size for HDZero +- **36 x 54 pixels** This is the large font for Avatar, and the font size for WTF OS The fonts should be places in directories named `12x18`, `24x36`, and `36x54` respectively. @@ -37,7 +35,7 @@ The tool uses the directory structre to find and create fonts. Here is an exampl The main directory is the one highlighted in blue called `fonts`. I will call that the **font root**. You don't have to name it fonts, but the structure after that needs some rigidity. This is just the starting point, and where the compiled font files are stored. You can see the three INAV font files in the image. -The first subdirectory you see is named `default`. This level of directory I will call **fontset** directories. The `default `directory must exist. For INAV, the default font directory can be found in the [INAV Configurator repository](https://github.com/iNavFlight/inav-configurator/tree/master/resources/osd/avatar). Maybe BetaFlight and ArduPilot will do the same at some point? If these appear, let me know and I will link here for convenience. This contains the default font for the firmware. Inside the `default` directory are the three font size directories, which must be named `12x18`, `24x36`, and `36x54`. The default font specifies if the fontset in question uses 256 or 512 characters. It is also used to fill in any missing characters. +The first subdirectory you see is named `default`. This level of directory I will call **fontset** directories. The `default `directory must exist. For INAV, the default font directory can be found in the [INAV Configurator repository](https://github.com/iNavFlight/inav-configurator/tree/master/resources/osd/digital). Maybe BetaFlight and ArduPilot will do the same at some point? If these appear, let me know and I will link here for convenience. This contains the default font for the firmware. Inside the `default` directory are the three font size directories, which must be named `12x18`, `24x36`, and `36x54`. The default font specifies if the fontset in question uses 256 or 512 characters. It is also used to fill in any missing characters. Underneath the `default` directory, you can see it's sibling **fontset** called `supercoolfont`. This is where I will put my customised character images. Notice that I only have a `36x54` sub directory. I took the lasy option, and decided to only change the largest font. The tool will see that the characters are missing from the smaller sizes, and will find the best alternatives for them. @@ -51,14 +49,15 @@ Currently, multiple character images are not found when searching for missing fo ### Using the tool The tool is a simple command line executable. You can put the tool in to the **font root** directory and just run it. Or, you can specify a path where the **font root** is located. There are only three argument options: - **?** Help -- **-v** Use verbose mode. This will output more detailed messages during the program execution. -- **-xcols** Generate a multi-column font file. +- **-system** _AVATAR_ or _HDZERO_. If no option is provided, AVATAR is generated - **-p path** Specify the location of the font root. - **-n prefix_name** Which is added to the beginning of the compiled font filename. +- **-xcols** Generate a multi-column font file. Note, this is not currently used by any HD system. +- **-v** Use verbose mode. This will output more detailed messages during the program execution. If the tool is in the **font root**, you can just run ``` -avatar-font-tool +hdosd-font-tool ``` If you are in a different directory, or have added the tool to the OS path. You can use the first argument to specify the **font root** ``` @@ -74,9 +73,9 @@ Note that directories with spaces should be wrapped in quotess. The above option If you want, you can add a prefix to the filenames. To do this, you add a second argument to the command line. For example, adding the prefix **INAV**. These two examples show how to add the prefix. The first example for when the tool is in the **font root**. The second example when the tool is in the path. ``` -avatar-font-tool .\ INAV +hdosd-font-tool .\ INAV -avatar-font-tool -p "C:\my stuff\fonts" -n INAV +hdosd-font-tool -p "C:\my stuff\fonts" -n INAV ``` The above options will result in the generation of six Avatar font files: - INAV_default_12.png diff --git a/avatar-font.d b/avatar-font.d deleted file mode 100644 index 7ef1276..0000000 --- a/avatar-font.d +++ /dev/null @@ -1,3 +0,0 @@ -obj/avatar-font.o: c:/github/MrD/avatar-font-tool/avatar-font.cpp \ - c:/github/MrD/avatar-font-tool/avatar-font.h \ - c:/github/MrD/avatar-font-tool/image-character.h diff --git a/avatar-font.cpp b/hdosd-font.cpp similarity index 68% rename from avatar-font.cpp rename to hdosd-font.cpp index 283f776..e935a4c 100644 --- a/avatar-font.cpp +++ b/hdosd-font.cpp @@ -1,24 +1,25 @@ /** - * This file is part of Avatar Font Tool. + * This file is part of HD OSD Font Tool. * Written by Darren Lines (Mr. D RC) * - * Avatar Font Tool is free software: you can redistribute it and/or modify + * HD OSD Font Tool is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. Please keep this header in the files. * - * Avatar Font Tool is distributed in the hope that it will be useful, + * HD OSD Font Tool is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Avatar Font Tool. If not, see . + * along with HD OSD Font Tool. If not, see . */ -#include "avatar-font.h" +#include "hdosd-font.h" #include "image-character.h" #include +#include #include #include #include @@ -29,14 +30,14 @@ namespace fs = std::filesystem; fs::path fontPath; -AvatarFont::AvatarFont() { +HDOSDFont::HDOSDFont() { // Blank constructor for null object. } -AvatarFont::~AvatarFont() { +HDOSDFont::~HDOSDFont() { } -AvatarFont::AvatarFont(fs::path fp, bool isVerbose = false) { +HDOSDFont::HDOSDFont(fs::path fp, bool isVerbose = false) { verbose = isVerbose; bool dirExists = false; isObjNull = false; @@ -77,7 +78,7 @@ AvatarFont::AvatarFont(fs::path fp, bool isVerbose = false) { } } -void AvatarFont::seedMaps() { +void HDOSDFont::seedMaps() { // Generate remaining empty characters for (int i = 0; i <= 512; i++) { ImageCharacter newIC = ImageCharacter(); @@ -109,7 +110,7 @@ void AvatarFont::seedMaps() { * @return true if character retrieval successful * @return false if there was a problem */ -bool AvatarFont::generateCharacters(AvatarFont& defaultFont) { +bool HDOSDFont::generateCharacters(HDOSDFont& defaultFont) { if (verbose) { cout << "Generating characters for font " << showDirectory() << ". Default Font is " << flush; if (defaultFont.isNull()) { @@ -131,31 +132,38 @@ bool AvatarFont::generateCharacters(AvatarFont& defaultFont) { return true; } -bool AvatarFont::generateAvatarPNGFiles(fs::path exportPath, string fontBaseName, bool renderColsx256FontImage) { +bool HDOSDFont::generateFontImageFiles(fs::path exportPath, string fontBaseName, uint8_t exportFontSystem, bool renderColsx256FontImage) { bool aOK = true; - if (aOK && !generatePNGFile(exportPath, characters12X18, 12, 18, fontBaseName, renderColsx256FontImage)) { - cout << "There was an issue generating the 12x18 " << showDirectory() << " file." << endl; - aOK = false; - } + if (exportFontSystem == OUTPUT_FONT_AVATAR) { + if (aOK && !generateAvatarPNGFile(exportPath, characters12X18, 12, 18, fontBaseName, renderColsx256FontImage)) { + cout << "There was an issue generating the Avatar 12x18 " << showDirectory() << " file." << endl; + aOK = false; + } - if (aOK && !generatePNGFile(exportPath, characters24X36, 24, 36, fontBaseName, renderColsx256FontImage)) { - cout << "There was an issue generating the 24x36 " << showDirectory() << " file." << endl; - aOK = false; - } + if (aOK && !generateAvatarPNGFile(exportPath, characters24X36, 24, 36, fontBaseName, renderColsx256FontImage)) { + cout << "There was an issue generating the Avatar 24x36 " << showDirectory() << " file." << endl; + aOK = false; + } - if (aOK && !generatePNGFile(exportPath, characters36X54, 36, 54, fontBaseName, renderColsx256FontImage)) { - cout << "There was an issue generating the 36x54 " << showDirectory() << " file." << endl; - aOK = false; + if (aOK && !generateAvatarPNGFile(exportPath, characters36X54, 36, 54, fontBaseName, renderColsx256FontImage)) { + cout << "There was an issue generating the Avatar 36x54 " << showDirectory() << " file." << endl; + aOK = false; + } + } else if (exportFontSystem == OUTPUT_FONT_HDZERO) { + if (aOK && !generateHDZeroBMPFile(exportPath, characters24X36, 24, 36, fontBaseName, renderColsx256FontImage)) { + cout << "There was an issue generating the HDZero 24x36 " << showDirectory() << " file." << endl; + aOK = false; + } } return aOK; } -bool AvatarFont::generatePNGFile(fs::path &path, ImageMap& characters, uint8_t charWidth, uint8_t charHeight, string &fontBaseName, bool renderColsx256FontImage) { - // create the object for the Avatar image +bool HDOSDFont::generateAvatarPNGFile(fs::path &path, ImageMap& characters, uint8_t charWidth, uint8_t charHeight, string &fontBaseName, bool renderColsx256FontImage) { + // create the object for the Avatar OSD image uint8_t charCols = 1; - uint16_t charRows = 512; + uint16_t charRows = maxCharacters; if (renderColsx256FontImage) { charCols = (int) maxCharacters / 256; @@ -163,53 +171,115 @@ bool AvatarFont::generatePNGFile(fs::path &path, ImageMap& characters, uint8_t c } if (verbose) { - cout << "Generating font with " << to_string(charCols) << " columns and " << to_string(charRows) << " rows." << endl; + cout << "Generating a " << to_string(charWidth) << "x" << to_string(charHeight) << " Avatar font with " << to_string(charCols) << " columns and " << to_string(charRows) << " rows." << endl; } ImageCharacter avatarOutput = ImageCharacter((charWidth * charCols), (charHeight * charRows)); // Transfer all the individual images to the Avatar image - uint32_t avImgPtr = 0; + uint32_t outImgPtr = 0; uint8_t curCol = 0; uint32_t charStart = 0; uint8_t charInd = 0; for (auto const&[key, character] : characters) { - if (key <= maxCharacters) { + if (key < maxCharacters) { charStart = 0; - if ((charCols > 1) && ((key % charRows) == 0)) { + if ((outImgPtr > 0) && (charCols > 1) && ((key % charRows) == 0)) { curCol++; - avImgPtr = (charWidth * curCol) * 4; + outImgPtr = (charWidth * curCol) * 4; } for (charInd = 0; charInd < charHeight; charInd++) { - memcpy(&avatarOutput.data[avImgPtr], character.data + charStart, (charWidth * 4)); + memcpy(&avatarOutput.data[outImgPtr], character.data + charStart, (charWidth * 4)); charStart+= (charWidth * 4); - avImgPtr+= (charWidth * 4) * charCols; + outImgPtr+= (charWidth * 4) * charCols; } } } // Save the file - avatarOutput.writeImage(path.string() + path.root_directory().string() + fontBaseName + showDirectory() + "_" + to_string(charWidth) + ".png"); + return avatarOutput.writeAvatarImage(path.string() + path.root_directory().string() + fontBaseName + showDirectory() + "_" + to_string(charWidth) + ".png"); +} - return true; +bool HDOSDFont::generateHDZeroBMPFile(fs::path &path, ImageMap& characters, uint8_t charWidth, uint8_t charHeight, string &fontBaseName, bool renderColsx256FontImage) { + // create the object for the HS OSD image + bool verticalFontSet = false; + uint8_t charCols = 16; + uint16_t charRows = maxCharacters / 16; + + if (renderColsx256FontImage) { + charCols = (int) maxCharacters / 256; + charRows = (int) maxCharacters / charCols; + verticalFontSet = true; + } + + if (verbose) { + cout << "Generating a " << to_string(charWidth) << "x" << to_string(charHeight) << " HDZero font with " << to_string(charCols) << " columns and " << to_string(charRows) << " rows." << endl; + } + + ImageCharacter hdzeroOutput = ImageCharacter((charWidth * charCols), (charHeight * charRows)); + hdzeroOutput.fillImage(127, 127, 127, 255); + + // Transfer all the individual images to the Avatar image + uint32_t outImgPtr = 0; + uint8_t curCol = 0; + uint8_t curRow = 0; + uint32_t charStart = 0; + uint8_t charInd = 0; + + for (auto const&[key, character] : characters) { + if (key < maxCharacters) { + charStart = 0; + + if (verticalFontSet) { + if (outImgPtr > 0 && (key % charRows) == 0) { + curCol++; + outImgPtr = (charWidth * curCol) * 4; + } + } else { + if (outImgPtr > 0) { + curCol++; + } + + if (curCol == charCols) { + curRow++; + curCol = 0; + } + + outImgPtr = ((charWidth * 4) * curCol) + (((charWidth * 4) * charCols) * (charHeight * curRow)); + } + + for (charInd = 0; charInd < charHeight; charInd++) { + for (uint8_t pixel = 0; pixel < charWidth; pixel++) { + if ((character.data[(charStart + (pixel * 4) + 3)] > 10)) { + memcpy(&hdzeroOutput.data[outImgPtr+(pixel * 4)], character.data + (charStart + (pixel*4)), 4); + } + } + charStart+= (charWidth * 4); + outImgPtr+= (charWidth * 4) * charCols; + } + } + } + + // Save the file + return hdzeroOutput.writeHDZeroImage(path.string() + path.root_directory().string() + fontBaseName + showDirectory() + "_" + to_string(charWidth) + ".bmp"); } -bool AvatarFont::isFontDefaultFont() { +bool HDOSDFont::isFontDefaultFont() { return isDefaultFont; } -string AvatarFont::showDirectory() { +string HDOSDFont::showDirectory() { return fontPath.filename().string(); } -int AvatarFont::getMaxCharacters() { +int HDOSDFont::getMaxCharacters() { return maxCharacters; } -ImageMap &AvatarFont::getFontMap(string fontSize) { +ImageMap &HDOSDFont::getFontMap(string fontSize) { if (fontSize == "36x54") { return characters36X54; } else if (fontSize == "24x36") { @@ -220,13 +290,14 @@ ImageMap &AvatarFont::getFontMap(string fontSize) { return characters12X18; } -int AvatarFont::calculateLastCharacter(AvatarFont& defaultFont) { +int HDOSDFont::calculateLastCharacter(HDOSDFont& defaultFont) { return (isDefaultFont) ? maxCharacters : defaultFont.getMaxCharacters(); } -void AvatarFont::capturePNGCharacters(AvatarFont& defaultFont, ImageMap& characterMap, fs::path charactersPath, fs::path alt1, fs::path alt2, uint8_t thisWidth, uint8_t thisHeight, uint8_t alt1Width, uint8_t alt1Height, uint8_t alt2Width, uint8_t alt2Height) { - int characterIndex = 1; +void HDOSDFont::capturePNGCharacters(HDOSDFont& defaultFont, ImageMap& characterMap, fs::path charactersPath, fs::path alt1, fs::path alt2, uint8_t thisWidth, uint8_t thisHeight, uint8_t alt1Width, uint8_t alt1Height, uint8_t alt2Width, uint8_t alt2Height) { + int characterIndex = 0; int lastCharacter = calculateLastCharacter(defaultFont); + int capturedCharacters = 0; if (verbose) { cout << "Capturing characters for " << quoted(charactersPath.string()) << flush; @@ -304,10 +375,11 @@ void AvatarFont::capturePNGCharacters(AvatarFont& defaultFont, ImageMap& charact } } - if (workingCharacter > 255 && maxCharacters < 512) { - maxCharacters = 512; - lastCharacter = calculateLastCharacter(defaultFont); - } + // Update max and last characters + maxCharacters = (floor((float)workingCharacter / 256) + 1) * 256; + lastCharacter = calculateLastCharacter(defaultFont); + + capturedCharacters++; } else if (filename.find('_') != string::npos) { // This is multiple characters in one PNG // The characters must be sequential. The first character and last character indexes are separated by an '_' @@ -369,10 +441,11 @@ void AvatarFont::capturePNGCharacters(AvatarFont& defaultFont, ImageMap& charact characterIndex++; } - if (workingCharacter > 255 && maxCharacters < 512) { - maxCharacters = 512; - lastCharacter = calculateLastCharacter(defaultFont); - } + // Update max and last characters + maxCharacters = (floor((float)workingCharacter / 256) + 1) * 256; + lastCharacter = calculateLastCharacter(defaultFont); + + capturedCharacters++; } else { int workingCharacter = stoi(filename); @@ -386,16 +459,19 @@ void AvatarFont::capturePNGCharacters(AvatarFont& defaultFont, ImageMap& charact characterIndex++; - if (workingCharacter > 255 && maxCharacters < 512) { - maxCharacters = 512; - lastCharacter = calculateLastCharacter(defaultFont); - } + // Update max and last characters + maxCharacters = (floor((float)workingCharacter / 256) + 1) * 256; + lastCharacter = calculateLastCharacter(defaultFont); + + capturedCharacters++; } } } + maxCharacters = lastCharacter; + if (verbose) { - cout << " with a total of " << lastCharacter << " characters. " << endl; + cout << " with a total of " << lastCharacter << " characters. " << to_string(capturedCharacters) << " characters loaded from directory." << endl; } if (characterIndex < (lastCharacter + 1)) { @@ -405,7 +481,7 @@ void AvatarFont::capturePNGCharacters(AvatarFont& defaultFont, ImageMap& charact return; } -int AvatarFont::findMissingCharacters(AvatarFont& defaultFont, ImageMap& characterMap, int characterIndex, int workingCharacter, fs::path alt1, fs::path alt2, uint8_t thisWidth, uint8_t thisHeight, uint8_t alt1Width, uint8_t alt1Height, uint8_t alt2Width, uint8_t alt2Height) { +int HDOSDFont::findMissingCharacters(HDOSDFont& defaultFont, ImageMap& characterMap, int characterIndex, int workingCharacter, fs::path alt1, fs::path alt2, uint8_t thisWidth, uint8_t thisHeight, uint8_t alt1Width, uint8_t alt1Height, uint8_t alt2Width, uint8_t alt2Height) { // If we have missing characters, fill the gaps while (characterIndex < workingCharacter) { diff --git a/hdosd-font.d b/hdosd-font.d new file mode 100644 index 0000000..ed1cd0f --- /dev/null +++ b/hdosd-font.d @@ -0,0 +1,3 @@ +obj/hdosd-font.o: C:/github/MrD/avatar-font-tool/hdosd-font.cpp \ + C:/github/MrD/avatar-font-tool/hdosd-font.h \ + C:/github/MrD/avatar-font-tool/image-character.h diff --git a/avatar-font.h b/hdosd-font.h similarity index 55% rename from avatar-font.h rename to hdosd-font.h index 01e20e3..5bfd035 100644 --- a/avatar-font.h +++ b/hdosd-font.h @@ -24,19 +24,23 @@ using namespace std; namespace fs = std::filesystem; +#define OUTPUT_FONT_AVATAR 0 +#define OUTPUT_FONT_HDZERO 1 +#define OUTPUT_FONT_WTFOS 2 + typedef map ImageMap; -class AvatarFont { +class HDOSDFont { public: - AvatarFont(); - ~AvatarFont(); - AvatarFont(fs::path, bool); + HDOSDFont(); + ~HDOSDFont(); + HDOSDFont(fs::path, bool); string showDirectory(); int getMaxCharacters(); bool isFontDefaultFont(); bool isNull() {return isObjNull;} - bool generateCharacters(AvatarFont& defaultFont); - bool generateAvatarPNGFiles(fs::path exportPath, string fontBaseName, bool renderColsx256FontImage); + bool generateCharacters(HDOSDFont& defaultFont); + bool generateFontImageFiles(fs::path exportPath, string fontBaseName, uint8_t exportFontSystem, bool renderColsx256FontImage); ImageMap &getFontMap(string fontSize); private: ImageMap characters12X18; @@ -51,9 +55,10 @@ class AvatarFont { fs::path fontPath24x36; fs::path fontPath12x18; - int calculateLastCharacter(AvatarFont& defaultFont); - void capturePNGCharacters(AvatarFont& defaultFont, map& characterMap, fs::path charactersPath, fs::path alt1, fs::path alt2, uint8_t thisWidth, uint8_t thisHeight, uint8_t alt1Width, uint8_t alt1Height, uint8_t alt2Width, uint8_t alt2Height); - int findMissingCharacters(AvatarFont& defaultFont, map& characterMap, int characterIndex, int workingCharacter, fs::path alt1, fs::path alt2, uint8_t thisWidth, uint8_t thisHeight, uint8_t alt1Width, uint8_t alt1Height, uint8_t alt2Width, uint8_t alt2Height); - bool generatePNGFile(fs::path &path, map& characterMap, uint8_t charWidth, uint8_t charHeight, string &fontBaseName, bool renderColsx256FontImage); + int calculateLastCharacter(HDOSDFont& defaultFont); + void capturePNGCharacters(HDOSDFont& defaultFont, map& characterMap, fs::path charactersPath, fs::path alt1, fs::path alt2, uint8_t thisWidth, uint8_t thisHeight, uint8_t alt1Width, uint8_t alt1Height, uint8_t alt2Width, uint8_t alt2Height); + int findMissingCharacters(HDOSDFont& defaultFont, map& characterMap, int characterIndex, int workingCharacter, fs::path alt1, fs::path alt2, uint8_t thisWidth, uint8_t thisHeight, uint8_t alt1Width, uint8_t alt1Height, uint8_t alt2Width, uint8_t alt2Height); + bool generateAvatarPNGFile(fs::path &path, map& characterMap, uint8_t charWidth, uint8_t charHeight, string &fontBaseName, bool renderColsx256FontImage); + bool generateHDZeroBMPFile(fs::path &path, map& characterMap, uint8_t charWidth, uint8_t charHeight, string &fontBaseName, bool renderColsx256FontImage); void seedMaps(); }; \ No newline at end of file diff --git a/image-character.cpp b/image-character.cpp index e632a14..5c710b9 100644 --- a/image-character.cpp +++ b/image-character.cpp @@ -1,19 +1,19 @@ /** - * This file is part of Avatar Font Tool. + * This file is part of HD OSD Font Tool. * Written by Darren Lines (Mr. D RC) * - * Avatar Font Tool is free software: you can redistribute it and/or modify + * HD OSD Font Tool is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. Please keep this header in the files. * - * Avatar Font Tool is distributed in the hope that it will be useful, + * HD OSD Font Tool is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Avatar Font Tool. If not, see . + * along with HD OSD Font Tool. If not, see . */ #define STB_IMAGE_IMPLEMENTATION @@ -76,6 +76,14 @@ bool ImageCharacter::readImage(const string imageFile) { return data != NULL; } +void ImageCharacter::fillImage(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + for (int i = 0; i < (w * h * channels); i++) { + data[i++] = r; + data[i++] = g; + data[i++] = b; + data[i] = a; + } +} void ImageCharacter::resizeImage(const string imageFile, int newW, int newH) { if (!readImage(imageFile)) { @@ -107,7 +115,24 @@ void ImageCharacter::setWH(int newW, int newH) { } } -bool ImageCharacter::writeImage(const string fileName) { +void ImageCharacter::convertRGBAtoRGB() { + if (channels == 4) { + uint8_t* noAlphaData = new uint8_t[(w * h * 3)](0); + int toPointer = 0; + + for (int i = 0; i < (w * h * channels); i++) { + if (i % 4 != 3) { + memcpy(&noAlphaData[toPointer++], &data[i], 1); + } + } + + channels = 3; + size = w * h * channels; + data = noAlphaData; + } +} + +bool ImageCharacter::writeAvatarImage(const string fileName) { stbi_write_png_compression_level = 10; char filename[fileName.length() + 1]; @@ -115,5 +140,16 @@ bool ImageCharacter::writeImage(const string fileName) { int success = stbi_write_png(filename, w, h, channels, data, (w * channels)); - return success != 0; + return (success != 0); +} + +bool ImageCharacter::writeHDZeroImage(const string fileName) { + char filename[fileName.length() + 1]; + strcpy(filename, fileName.c_str()); + + convertRGBAtoRGB(); + + int success = stbi_write_bmp(filename, w, h, channels, data); + + return (success != 0); } \ No newline at end of file diff --git a/image-character.h b/image-character.h index b51388c..7534d0d 100644 --- a/image-character.h +++ b/image-character.h @@ -32,9 +32,12 @@ class ImageCharacter { void copyImage(const ImageCharacter &fromCharacter); bool readImage(const string imageFile); + void fillImage(uint8_t r, uint8_t g, uint8_t b, uint8_t a); void resizeImage(const string imageFile, int newW, int newH); void setWH(int newW, int newH); - bool writeImage(const string fileName); + void convertRGBAtoRGB(); + bool writeAvatarImage(const string fileName); + bool writeHDZeroImage(const string fileName); int w; int h; diff --git a/libgcc_s_seh-1.dll b/libgcc_s_seh-1.dll new file mode 100644 index 0000000..2a8dcb2 Binary files /dev/null and b/libgcc_s_seh-1.dll differ diff --git a/libstdc++-6.dll b/libstdc++-6.dll new file mode 100644 index 0000000..0fa56db Binary files /dev/null and b/libstdc++-6.dll differ diff --git a/libwinpthread-1.dll b/libwinpthread-1.dll new file mode 100644 index 0000000..31a4639 Binary files /dev/null and b/libwinpthread-1.dll differ diff --git a/main.cpp b/main.cpp index bc1f152..adbca1a 100644 --- a/main.cpp +++ b/main.cpp @@ -2,12 +2,12 @@ * This file is part of Avatar Font Tool. * Written by Darren Lines (Mr. D RC) * - * Avatar Font Tool is free software: you can redistribute it and/or modify + * HD OSD Font Tool is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. Please keep this header in the files. * - * Avatar Font Tool is distributed in the hope that it will be useful, + * HD OSD Font Tool is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. @@ -17,9 +17,10 @@ */ #include +#include #include #include -#include "avatar-font.h" +#include "hdosd-font.h" #include "image-character.h" // REMOVE AFTER TEST @@ -37,7 +38,8 @@ namespace fs = std::filesystem; */ int main(int argsCount, char *args[]) { int exitCode = 0; - vector fonts; + uint8_t fontExportSystem = OUTPUT_FONT_AVATAR; + vector fonts; bool haveDefaultFont = false; string tmpPath = ""; fs::path path; @@ -50,15 +52,16 @@ int main(int argsCount, char *args[]) { if (argsCount > 1) { string arg = args[1]; if (arg == "?") { - cout << "Avatar Font Tool by Mr. D (www.mrd-rc.com)" << newl + cout << "HD OSD Font Tool by Mr. D (www.mrd-rc.com)" << newl << "Command line usage:" << newl << "no arguments - default use: font root in current directory and no filename prefix" << newl << "-- Options --" << newl - << "? | This help screen" << newl - << "-p %p | Path to the font root" << newl - << "-n %n | Filename prefix" << newl - << "-xcols | Output a multi-column x 256 high character font image" << newl - << "-v | Verbose mode (show more detailed messages)" << endl; + << "? | This help screen" << newl + << "-p %p | Path to the font root" << newl + << "-n %n | Filename prefix" << newl + << "-system | AVATAR or HDZERO (defaults to AVATAR)" << newl + << "-xcols | Output a multi-column x 256 high character font image. For Avatar" << newl + << "-v | Verbose mode (show more detailed messages)" << endl; exit(exitCode); } else if (arg == "-v") { @@ -77,7 +80,7 @@ int main(int argsCount, char *args[]) { renderColsx256FontImage = true; } else if (argsCount > curArg) { if (option == "-p") { - string value = args[curArg++]; + string value = args[curArg++]; tmpPath = value; if (tmpPath[tmpPath.length() - 1] != '/') { @@ -88,13 +91,26 @@ int main(int argsCount, char *args[]) { } if (option == "-n") { - string value = args[curArg++]; + string value = args[curArg++]; fontBaseName = value; if (fontBaseName.length() > 0) { fontBaseName+= "_"; } } + + if (option == "-system") { + string value = args[curArg++]; + + for (long long unsigned int sc = 0; sc < value.length(); sc++) { + value[sc] = tolower(value[sc]); + } + if (value == "hdzero") { + fontExportSystem = OUTPUT_FONT_HDZERO; + } else if (value == "wtfos") { + fontExportSystem = OUTPUT_FONT_WTFOS; + } + } } } } @@ -121,19 +137,19 @@ int main(int argsCount, char *args[]) { } // Create the font objects based on the subdirectories of the current directory. These should all be fonts - // First loop through the subdirectories and create the AvatarFont objects + // First loop through the subdirectories and create the HDOSDFont objects for (auto &dirPath : fontDirectories) { // Create objects for fonts - AvatarFont af(dirPath, verbose); + HDOSDFont osdFont(dirPath, verbose); - if (af.isFontDefaultFont()) { + if (osdFont.isFontDefaultFont()) { // Add default font object to start of vector - fonts.insert(fonts.begin(), af); + fonts.insert(fonts.begin(), osdFont); // State that we have a default font haveDefaultFont = true; } else { // Add font object to vector - fonts.push_back(af); + fonts.push_back(osdFont); } } @@ -152,7 +168,7 @@ int main(int argsCount, char *args[]) { // Generate the image data from the PNG character files. if (fontSet.isFontDefaultFont()) { - AvatarFont null = AvatarFont(); + HDOSDFont null = HDOSDFont(); fontSet.generateCharacters(null); } else { fontSet.generateCharacters(fonts[0]); @@ -161,7 +177,7 @@ int main(int argsCount, char *args[]) { // Output the font files. The file name format is fontBaseName_font folder_font width. // For example with arg fontBaseName set to INAV. INAV_default_24.png // ... or with no fontBaseName set. default_24.png - fontSet.generateAvatarPNGFiles(path, fontBaseName, renderColsx256FontImage); + fontSet.generateFontImageFiles(path, fontBaseName, fontExportSystem, renderColsx256FontImage); cout << "Font generation successful." << endl; } diff --git a/main.d b/main.d index 30c15ba..7770c4d 100644 --- a/main.d +++ b/main.d @@ -1,3 +1,3 @@ -obj/main.o: c:/github/MrD/avatar-font-tool/main.cpp \ - c:/github/MrD/avatar-font-tool/avatar-font.h \ - c:/github/MrD/avatar-font-tool/image-character.h +obj/main.o: C:/github/MrD/avatar-font-tool/main.cpp \ + C:/github/MrD/avatar-font-tool/hdosd-font.h \ + C:/github/MrD/avatar-font-tool/image-character.h diff --git a/obj/hdosd-font.o b/obj/hdosd-font.o new file mode 100644 index 0000000..b0e43a7 Binary files /dev/null and b/obj/hdosd-font.o differ diff --git a/obj/image-character.o b/obj/image-character.o index 188af6b..a91e051 100644 Binary files a/obj/image-character.o and b/obj/image-character.o differ diff --git a/obj/main.o b/obj/main.o index 1e8b7f0..e310581 100644 Binary files a/obj/main.o and b/obj/main.o differ