433 lines
18 KiB
C#
433 lines
18 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using System.Xml.Linq;
|
|
|
|
namespace McBitFont {
|
|
public partial class Export : Form {
|
|
|
|
private MainForm mainForm;
|
|
|
|
//private List<string> comments = new List<string>();
|
|
private Dictionary<string, string> comments = new Dictionary<string, string>();
|
|
|
|
public Export(object sender) {
|
|
InitializeComponent();
|
|
|
|
mainForm = (MainForm)sender;
|
|
}
|
|
|
|
private void Export_Load(object sender, EventArgs e) {
|
|
var groupBoxes = Controls.OfType<GroupBox>();
|
|
foreach (var gb in groupBoxes) {
|
|
var comboBoxes = gb.Controls.OfType<ComboBox>();
|
|
foreach (var cb in comboBoxes) {
|
|
cb.SelectedIndex = 0;
|
|
}
|
|
}
|
|
comments.Add("header",
|
|
"// File generated by McBitFont v" + MainForm.version + "\n" +
|
|
"// made by Anton Mukhin (mcfly@mcflyer.ru)\n" +
|
|
"//\n" +
|
|
"//\n"
|
|
);
|
|
comments.Add("scan_order", "// Scan order: ");
|
|
comments.Add("scan_hdir", "// Horizontal direction: ");
|
|
comments.Add("scan_vdir", "// Vertical direction: ");
|
|
|
|
comments.Add("num_bit_order", "// Bit order: ");
|
|
comments.Add("num_base", "// Numbers base: ");
|
|
comments.Add("num_size", "// Numbers size: ");
|
|
|
|
comments.Add("text_format", "// Text format: ");
|
|
comments.Add("text_lines", "// Numbers per line: ");
|
|
|
|
comments.Add("font_header_map",
|
|
"// Font header map:\n" +
|
|
"// packed; // Flag for packed font\n" +
|
|
"// width; // Font width in pixels (0 - variable width)\n" +
|
|
"// height; // Font height in pixels\n" +
|
|
"// space; // Font space in pixels\n" +
|
|
"// first; // First character code\n" +
|
|
"// last; // Last character code\n"
|
|
);
|
|
}
|
|
|
|
private void cbOrder_SelectedIndexChanged(object sender, EventArgs e) {
|
|
switch (cbOrder.SelectedIndex) {
|
|
case 0: // Columns
|
|
cbBitOrder.Items[0] = "LSB Top";
|
|
cbBitOrder.Items[1] = "MSB Top";
|
|
cbLines.Items[0] = "1 Column per line";
|
|
break;
|
|
case 1: // Rows
|
|
cbBitOrder.Items[0] = "LSB Left";
|
|
cbBitOrder.Items[1] = "MSB Left";
|
|
cbLines.Items[0] = "1 Row per line";
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void btnGenerate_Click(object sender, EventArgs e) {
|
|
string output = "";
|
|
int bTotal = 0;
|
|
txtOutput.Clear();
|
|
bool com = cbComments.Checked;
|
|
bool hdr = cbHeader.Checked;
|
|
bool packed = cbPacked.Checked;
|
|
int lines = cbLines.SelectedIndex;
|
|
int format = cbFormat.SelectedIndex;
|
|
bool mono = mainForm.monospaced;
|
|
int lineslim = (int)nudXLines.Value;
|
|
int fcount = mainForm.frames.Count;
|
|
|
|
int imin, jmin, imax, jmax, idir, jdir;
|
|
|
|
if (com) {
|
|
// Header comments
|
|
//output += comments["header"];
|
|
output += comments["scan_order"] + cbOrder.Text + "\n";
|
|
output += comments["scan_hdir"] + cbHDir.Text + "\n";
|
|
output += comments["scan_vdir"] + cbVDir.Text + "\n\n";
|
|
|
|
output += comments["num_bit_order"] + cbBitOrder.Text + "\n";
|
|
output += comments["num_base"] + cbNumBase.Text + "\n";
|
|
output += comments["num_size"] + cbNumSize.Text + "\n\n";
|
|
|
|
output += comments["text_format"] + cbFormat.Text + "\n";
|
|
output += comments["text_lines"] + cbLines.Text + "\n\n";
|
|
|
|
if (hdr) {
|
|
// comment about meta header map
|
|
output += comments["font_header_map"] + "\n\n";
|
|
}
|
|
}
|
|
|
|
// Figure out mins and maxes
|
|
if (cbOrder.SelectedIndex == 0) {
|
|
if (cbHDir.SelectedIndex == 0) {
|
|
// Columns; Left to right
|
|
imin = 0;
|
|
imax = mainForm.dotWidth;
|
|
idir = 1;
|
|
} else {
|
|
// Columns; Right to left
|
|
imin = mainForm.dotWidth - 1;
|
|
imax = -1;
|
|
idir = -1;
|
|
}
|
|
if (cbVDir.SelectedIndex == 0) {
|
|
// Columns; Top to bottom
|
|
jmin = 0;
|
|
jmax = mainForm.dotHeight;
|
|
jdir = 1;
|
|
} else {
|
|
// Columns; Bottom to top
|
|
jmin = mainForm.dotHeight - 1;
|
|
jmax = -1;
|
|
jdir = -1;
|
|
}
|
|
} else {
|
|
if (cbVDir.SelectedIndex == 0) {
|
|
// Rows; Left to right
|
|
imin = 0;
|
|
imax = mainForm.dotHeight;
|
|
idir = 1;
|
|
} else {
|
|
// Rows; Right to left
|
|
imin = mainForm.dotHeight - 1;
|
|
imax = -1;
|
|
idir = -1;
|
|
}
|
|
if (cbHDir.SelectedIndex == 0) {
|
|
// Rows; Top to bottom
|
|
jmin = 0;
|
|
jmax = mainForm.dotWidth;
|
|
jdir = 1;
|
|
} else {
|
|
// Rows; Bottom to top
|
|
jmin = mainForm.dotWidth - 1;
|
|
jmax = -1;
|
|
jdir = -1;
|
|
}
|
|
}
|
|
|
|
// C data type selection
|
|
ushort bits = 8;
|
|
string dataType = "uint8_t";
|
|
switch (cbNumSize.SelectedIndex) {
|
|
case 0:
|
|
bits = 8;
|
|
dataType = "uint8_t";
|
|
break;
|
|
case 1:
|
|
bits = 16;
|
|
dataType = "uint16_t";
|
|
break;
|
|
case 2:
|
|
bits = 32;
|
|
dataType = "uint32_t";
|
|
break;
|
|
}
|
|
|
|
int nbase = 16;
|
|
string prefix = "0x";
|
|
string pref = "";
|
|
int pad = 2;
|
|
switch (cbNumBase.SelectedIndex) {
|
|
case 0:
|
|
nbase = 16;
|
|
prefix = "0x";
|
|
pad = cbZeroes.Checked ? bits / 4 : 0;
|
|
break;
|
|
case 1:
|
|
nbase = 2;
|
|
prefix = "0b";
|
|
pad = cbZeroes.Checked ? bits : 0;
|
|
break;
|
|
case 2:
|
|
nbase = 10;
|
|
prefix = "";
|
|
pad = 0;
|
|
break;
|
|
}
|
|
|
|
// Array definition
|
|
if (format == 0 || format == 1) output += "const " + dataType + " " + mainForm.prjName + "[]" + (format == 1 ? "[]" : "") + " = {\n";
|
|
|
|
// Should we add the meta header?
|
|
if (hdr) {
|
|
output +=
|
|
" // Meta header\n" +
|
|
" " + (packed ? "1" : "0") + ", // Is it a packed font?\n" +
|
|
" " + (mono || mainForm.frames.Count == 1 ? mainForm.frames.First().width.ToString() : "0") + ", // Font width in pixels; 0 - variable width\n" +
|
|
" " + mainForm.frames.First().height.ToString() + ", // Font height in pixels\n" +
|
|
" 0, // Font space (between symbols) in pixels\n" +
|
|
" " + mainForm.frames.First().code.ToString() + ", // First character code\n" +
|
|
" " + mainForm.frames.Last().code.ToString() + ", // Last character code\n"
|
|
;
|
|
bTotal += 6*bits / 8; // Count bytes total
|
|
}
|
|
|
|
// Brackets for 2D array definition
|
|
string obracket = format == 1 ? "{ " : "";
|
|
string cbracket = format == 1 ? " }" : "";
|
|
|
|
// Number output counter
|
|
int numcount = 0;
|
|
|
|
if (com) output += " // Data:\n";
|
|
MainForm.FrameMiniature flast = mainForm.frames.Last();
|
|
foreach (MainForm.FrameMiniature f in mainForm.frames) {
|
|
// For each frame
|
|
uint b = 0; // current number bits
|
|
int t, x, y; // t - calculated bit number; x - actual x; y - actual y
|
|
|
|
if (com && lines != 1 && fcount > 1) {
|
|
// Comments enabled and other than "1 symbol per line" selected
|
|
// Print a symbol comment before its data
|
|
output += " // " + f.code.ToString() + " --> " + mainForm.DecodeSymbol(f.code) + "\n";
|
|
}
|
|
if (lines == 1) {
|
|
// "1 symbol per line" - new line offset
|
|
output += " ";
|
|
numcount = 0;
|
|
}
|
|
if (!mono && fcount > 1) {
|
|
// Not a single image; Variable width font - lets post the width as a 1st number
|
|
|
|
// Should we post a prefix to the number?
|
|
pref = (!cbZeroes.Checked && ((f.width < 10 && nbase == 16) || (f.width < 2 && nbase == 2))) ? "" : prefix;
|
|
output += (lines != 1 ? " " : "") + pref + Convert.ToString(f.width, nbase).PadLeft(pad, '0') + (lines != 0 ? (lines == 1 ? ", " : "") : ",\n");
|
|
bTotal += bits / 8; // Count bytes total
|
|
// Count posted numbers
|
|
numcount++;
|
|
if (lines != 2) numcount = 0;
|
|
if (lines == 2 && numcount >= lineslim) {
|
|
numcount = 0;
|
|
output += "\n ";
|
|
}
|
|
}
|
|
if (lines == 2 && numcount == 0) {
|
|
// "X numbers per line" - first line of a symbol offset
|
|
output += " ";
|
|
}
|
|
|
|
//Figure out mins and maxes for variable width fonts
|
|
if (!mono && fcount > 1) {
|
|
if (cbOrder.SelectedIndex == 0) {
|
|
if (cbHDir.SelectedIndex == 0) {
|
|
// Columns; Left to right
|
|
imax = f.width;
|
|
} else {
|
|
// Columns; Right to left
|
|
imin = f.width - 1;
|
|
}
|
|
if (cbVDir.SelectedIndex == 0) {
|
|
// Columns; Top to bottom
|
|
jmax = f.height;
|
|
} else {
|
|
// Columns; Bottom to top
|
|
jmin = f.height - 1;
|
|
}
|
|
} else {
|
|
if (cbVDir.SelectedIndex == 0) {
|
|
// Rows; Left to right
|
|
imax = f.height;
|
|
} else {
|
|
// Rows; Right to left
|
|
imin = f.height - 1;
|
|
}
|
|
if (cbHDir.SelectedIndex == 0) {
|
|
// Rows; Top to bottom
|
|
jmax = f.width;
|
|
} else {
|
|
// Rows; Bottom to top
|
|
jmin = f.width - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
t = jdir < 0 ? bits+1 : -1;
|
|
for (int i = imin; i != imax; i += idir) {
|
|
if (lines == 0) {
|
|
// "Column/Row per line" - new line offset
|
|
output += " " + obracket;
|
|
numcount = 0;
|
|
}
|
|
for (int j = jmin; j != jmax; j += jdir) {
|
|
if (packed) {
|
|
t += jdir;
|
|
if (t < 0 || t % bits == 0) t = jdir < 0 ? bits : 0;
|
|
} else {
|
|
if (jdir < 0) t = jmin - j;
|
|
else t = j;
|
|
}
|
|
if (t % bits == 0) b = 0;
|
|
|
|
if (cbOrder.SelectedIndex == 0) { // Columns
|
|
x = i; y = j;
|
|
} else { // Rows
|
|
x = j; y = i;
|
|
}
|
|
|
|
if (f.data[x, y]) {
|
|
if ((cbBitOrder.SelectedIndex == 0 && jdir > 0) || (cbBitOrder.SelectedIndex == 1 && jdir < 0)) {
|
|
// LSB on top/Left
|
|
b |= (uint)(1 << (t % bits));
|
|
} else {
|
|
// MSB on top/Left
|
|
b |= (uint)(1 << (bits - (t % bits) - 1));
|
|
}
|
|
|
|
}
|
|
if (((t + 1) % bits == 0) || (j + jdir == jmax && !packed)) {
|
|
// we have filled a number with bits - let's post it
|
|
|
|
// should we post a comma before the number?
|
|
output += numcount == 0 ? "" : ", ";
|
|
|
|
// should we post a prefix to the number?
|
|
pref = (!cbZeroes.Checked && ((b < 10 && nbase == 16) || (b < 2 && nbase == 2))) ? "" : prefix;
|
|
output += pref + Convert.ToString(b, nbase).PadLeft(pad, '0');
|
|
bTotal += bits / 8; // Count bytes total
|
|
|
|
// count posted numbers
|
|
numcount++;
|
|
if (lines == 2 && numcount >= lineslim && !(j + jdir == jmax && i + idir == imax)) {
|
|
// "X numbers per line" - line break
|
|
numcount = 0;
|
|
output += ",\n ";
|
|
}
|
|
}
|
|
}
|
|
if (lines == 0) {
|
|
// "Column/Row per line" - closing line
|
|
output += cbracket + ((i + idir == imax) && f.Equals(flast) ? "" : ",") + "\n";
|
|
}
|
|
}
|
|
if (packed && (f.width * f.height) % bits > 0) {
|
|
// post leftovers in last number
|
|
|
|
// should we post a prefix to the number?
|
|
pref = (!cbZeroes.Checked && ((b < 10 && nbase == 16) || (b < 2 && nbase == 2))) ? "" : prefix;
|
|
output += (numcount > 0? ", " : "") + pref + Convert.ToString(b, nbase).PadLeft(pad, '0');
|
|
bTotal += bits / 8; // Count bytes total
|
|
|
|
// count posted numbers
|
|
numcount++;
|
|
}
|
|
if (lines == 1) {
|
|
// "1 symbol per line" - closing line
|
|
if (!f.Equals(flast) && f.width > 0) output += ",";
|
|
if (com && fcount > 1) {
|
|
//...with a comment
|
|
output += " // " + f.code.ToString() + " --> " + mainForm.DecodeSymbol(f.code);
|
|
}
|
|
output += "\n";
|
|
}
|
|
if (lines == 2) {
|
|
// "X numbers per line" - closing line
|
|
if (!f.Equals(flast)) output += ",";
|
|
output += "\n";
|
|
numcount = 0;
|
|
}
|
|
}
|
|
// Close array definition
|
|
output += "};\n";
|
|
|
|
// Add header and bytes total counter
|
|
if (com) {
|
|
output = "// Bytes total: " + bTotal.ToString() + "\n" + output;
|
|
output = comments["header"] + output;
|
|
}
|
|
|
|
txtOutput.Text = output;
|
|
txtOutput.SelectionStart = 0;
|
|
txtOutput.ScrollToCaret();
|
|
}
|
|
|
|
private void cbFormat_SelectedIndexChanged(object sender, EventArgs e) {
|
|
if (cbFormat.SelectedIndex == 1 && cbHeader.Checked) {
|
|
MessageBox.Show("Cannot pack the font meta header into 2D array!\nChoose 1D array or disable the meta header.\n(Setting array format to 1D array)", "No header in 2D array!", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
cbFormat.SelectedIndex = 0;
|
|
}
|
|
if (!mainForm.monospaced && cbFormat.SelectedIndex == 1 && mainForm.frames.Count > 1) {
|
|
MessageBox.Show("Cannot pack the variable width font into 2D array!\n(Setting array format to 1D array)", "2D arrays are for monospaced fonts only!", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
cbFormat.SelectedIndex = 0;
|
|
}
|
|
if (cbFormat.SelectedIndex == 1) {
|
|
cbLines.SelectedIndex = 0;
|
|
cbLines.Enabled = false;
|
|
} else {
|
|
cbLines.Enabled = true;
|
|
}
|
|
}
|
|
|
|
private void cbLines_SelectedIndexChanged(object sender, EventArgs e) {
|
|
if (cbLines.SelectedIndex == 0 && cbPacked.Checked) {
|
|
MessageBox.Show("Cannot make one line per column/row in packed font as there are bytes used in several columns/rows!\n(Setting text format to 1 Symbol per line)", "No 1 Symbol per line for packed fonts!", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
cbLines.SelectedIndex = 1;
|
|
}
|
|
if (cbLines.SelectedIndex == 2) {
|
|
nudXLines.Enabled = true;
|
|
lblXLines.Enabled = true;
|
|
} else {
|
|
nudXLines.Enabled = false;
|
|
lblXLines.Enabled = false;
|
|
}
|
|
}
|
|
|
|
private void cbPacked_CheckedChanged(object sender, EventArgs e) {
|
|
if (cbPacked.Checked && cbLines.SelectedIndex == 0) cbLines.SelectedIndex = 1;
|
|
}
|
|
}
|
|
}
|