-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* font overhaul * misc changes * compressed fonts & changed back to consola
- Loading branch information
Showing
83 changed files
with
789 additions
and
2,823 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
from PIL import Image, ImageFont, ImageDraw | ||
from textures import Formats, write_tex | ||
import struct | ||
import argparse | ||
import re | ||
|
||
def size_type(string): | ||
pattern = re.compile("([0-9]+)[xX]([0-9]+)") | ||
matching = re.fullmatch(pattern, string) | ||
if matching is None: | ||
msg = "%r is not a valid size" % string | ||
raise argparse.ArgumentTypeError(msg) | ||
size = tuple(int(g) for g in matching.groups()) | ||
if size[0] % 4 != 0 or size[1] % 4 != 0: | ||
msg = "The new size \"%dx%d\" must be a multiple of 4" % size | ||
raise argparse.ArgumentTypeError(msg) | ||
return size | ||
|
||
def write_header(out_buf, font): | ||
out_buf.write(struct.pack(">4s", "FNT0".encode("ascii"))) # channel count | ||
out_buf.write(struct.pack(">f", font['base_size'])) # base_size | ||
out_buf.write(struct.pack(">ff", font['metrics'][0], font['metrics'][1])) # (ascend, descend) | ||
|
||
def write_glyphs(out_buf, font): | ||
out_buf.write(len(font['glyphs']).to_bytes(4, 'big', signed=False)) # glyphs count | ||
for i in range(len(font['glyphs'])): | ||
out_buf.write(struct.pack(">ff", font['glyphs'][i]['offset'], font['glyphs'][i]['width'])) | ||
out_buf.write(struct.pack(">ffff", *font['glyphs'][i]['tex_coords'])) | ||
|
||
if __name__ == '__main__': | ||
parser = argparse.ArgumentParser(description='Converts a font into a .fnt file.') | ||
parser.add_argument('-V', '--version', action='version', version='%(prog)s 0.2') | ||
parser.add_argument('font_file', type=argparse.FileType('rb'), | ||
help='Path to the font file') | ||
parser.add_argument('out_fnt', type=argparse.FileType('wb'), nargs='?', default="out.fnt", | ||
help='Name of the output file') | ||
parser.add_argument('-s', '--size', type=size_type, metavar='WxH', default="256x256", | ||
help='Set the resolution of the font to a width/height of W/H') | ||
parser.add_argument('-F', '--font-size', type=int, default=18, | ||
help='Font size (in points)') | ||
parser.add_argument('-f', '--format', type=str, choices=[name for name, _ in Formats.__members__.items()], | ||
default='I8', help='Format to save the font in') | ||
params = parser.parse_args() | ||
|
||
if params.format in ["RGBA8"] and (params.size[0] % 4 != 0 or params.size[1] % 4 != 0): | ||
raise RuntimeError("Size has to be a multiple of 4 when using RGBA8") | ||
if params.format in ["CMPR", "I8"] and (params.size[0] % 8 != 0 and params.size[1] % 8 != 0): | ||
raise RuntimeError("Size has to be a multiple of 8 when using CMPR or I8 formats") | ||
|
||
image = Image.new('RGBA', params.size, (0,0,0,0)) | ||
draw = ImageDraw.Draw(image) | ||
|
||
ftf = ImageFont.FreeTypeFont(params.font_file, params.font_size) | ||
asc, dsc = ftf.getmetrics() | ||
pos = (0, asc) | ||
default_glyph = { | ||
'offset': 0, | ||
'width': 0, | ||
'tex_coords' : (0, 0, 0, 0), | ||
} | ||
glyphs = [{**default_glyph} for i in range(256)] | ||
for i in range(256): | ||
bbox = ftf.getbbox(chr(i), anchor="ls") | ||
glyph_width = bbox[2] - bbox[0] | ||
glyph_offset = (bbox[0], bbox[1]) | ||
if pos[0] + glyph_width > params.size[0]: | ||
pos = (0, pos[1] + asc + dsc + 1) | ||
if pos[1] + asc + dsc > params.size[1]: | ||
raise RuntimeError("The resolution is too small to fit all the glyphs! Try to reduce the font size") | ||
|
||
draw.text((pos[0] - bbox[0], pos[1]), chr(i), font=ftf, anchor="ls") | ||
glyphs[i]['offset'] = bbox[0] | ||
glyphs[i]['width'] = glyph_width | ||
glyphs[i]['tex_coords'] = ((pos[0]) / params.size[0], (pos[1] - asc) / params.size[1], (pos[0] + glyph_width) / params.size[0], (pos[1] + dsc) / params.size[1]) | ||
|
||
pos = (pos[0] + glyph_width, pos[1]) | ||
font = { | ||
'metrics': (asc, dsc), | ||
'base_size': params.font_size, | ||
'glyphs': [*glyphs], | ||
} | ||
|
||
write_header(params.out_fnt, font) | ||
write_glyphs(params.out_fnt, font) | ||
write_tex(params.out_fnt, image, Formats.RGBA8) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .textures import Formats, write_tex |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
from enum import Enum, unique | ||
from PIL import Image | ||
import struct | ||
import re | ||
import functools | ||
import io | ||
#import syaz0 | ||
|
||
|
||
@unique | ||
class Formats(Enum): | ||
RGBA8 = 0 | ||
CMPR = 1 | ||
I8 = 2 | ||
|
||
|
||
def write_header(out_file, image: Image, format: Formats): | ||
out_file.write(struct.pack(">4s", "TEX0".encode("ascii"))) # channel count | ||
out_file.write(format.value.to_bytes(4, 'big', signed=False)) | ||
out_file.write(image.width.to_bytes(4, 'big', signed=False)) | ||
out_file.write(image.height.to_bytes(4, 'big', signed=False)) | ||
|
||
def write_tile(out_file, chn): | ||
for j in range(8): | ||
for i in range(8): | ||
pos = (i, j) | ||
val = chn.getpixel(pos) | ||
out_file.write(struct.pack(">B", val)) | ||
|
||
def write_tile2(out_file, chn1, chn2): | ||
for j in range(4): | ||
for i in range(4): | ||
pos = (i, j) | ||
val1 = chn1.getpixel(pos) | ||
val2 = chn2.getpixel(pos) | ||
out_file.write(struct.pack(">BB", val1, val2)) | ||
|
||
def write_raw(out_file, image): | ||
image = image.convert('RGBA') | ||
# We save each 4x4 tile one at a time. | ||
for j in range(image.height // 4): | ||
for i in range(image.width // 4): | ||
tile = image.crop((i * 4, j * 4, (i + 1) * 4, (j + 1) * 4)) | ||
chnR, chnG, chnB, chnA = tile.split() | ||
write_tile2(out_file, chnA, chnR) | ||
write_tile2(out_file, chnG, chnB) | ||
|
||
def write_i8(out_file, image): | ||
image = image.convert(mode="L", dither=None) | ||
# We save each 4x4 tile one at a time. | ||
for j in range(image.height // 8): | ||
for i in range(image.width // 8): | ||
tile = image.crop((i * 8, j * 8, (i + 1) * 8, (j + 1) * 8)) | ||
write_tile(out_file, tile) | ||
|
||
def toRGB565(r, g, b): | ||
return (int(r * 31 / 255) << 11) | (int(g * 63 / 255) << 5) | (int(b * 31 / 255)) | ||
|
||
def quantize_tile(out_file, img): | ||
img = img.convert('RGBA') | ||
has_transparency = any(pixel[3] == 0 for pixel in (img.getdata())) | ||
lst = img.quantize(2).getpalette()[:2*3] | ||
palette = [tuple(lst[i:i + 3]) for i in range(0, len(lst), 3)] | ||
if not ((has_transparency and toRGB565(*palette[0]) <= toRGB565(*palette[1])) or ((not has_transparency) and toRGB565(*palette[0]) > toRGB565(*palette[1]))): | ||
tmp = palette[0] | ||
palette[0] = palette[1] | ||
palette[1] = tmp | ||
out_file.write(toRGB565(*palette[0]).to_bytes(2, 'big', signed=False)) | ||
out_file.write(toRGB565(*palette[1]).to_bytes(2, 'big', signed=False)) | ||
if (has_transparency): | ||
palette.append(tuple((palette[0][i] + palette[1][i]) // 2 for i in range(3))) | ||
else: | ||
palette.append(tuple((palette[0][i] * 2 + palette[1][i]) // 3 for i in range(3))) | ||
palette.append(tuple((palette[1][i] * 2 + palette[0][i]) // 3 for i in range(3))) | ||
for j in range(4): | ||
row = list() | ||
for i in range(4): | ||
pixel = img.getpixel((i, j)) | ||
distances = [sum(abs(pixel[a] - palette[k][a]) for a in range(len(palette[k]))) for k in range(len(palette))] | ||
chnA = pixel[3] | ||
min_palette = distances.index(min(distances)) | ||
if chnA == 0: | ||
min_palette = 3 | ||
row.append(min_palette) | ||
out_file.write(functools.reduce(lambda x, y: x | y, ((int(row[i]) & 0x3) << ((4 - (i + 1)) * 2) for i in range(4))).to_bytes(1, 'big', signed=False)) | ||
|
||
def write_cmpr(out_file, image): | ||
for v in range(image.height // 8): | ||
for u in range(image.width // 8): | ||
for j in range(2): | ||
for i in range(2): | ||
tile = image.crop((u * 8 + i * 4, v * 8 + j * 4, u * 8 + (i + 1) * 4, v * 8 + (j + 1) * 4)) | ||
quantize_tile(out_file, tile) | ||
|
||
def write_tex(out_buf, img: Image, fmt: Formats): | ||
buffer = io.BytesIO() | ||
|
||
write_header(out_buf, img, fmt) | ||
|
||
if fmt == Formats.RGBA8: | ||
write_raw(buffer, img) | ||
elif fmt == Formats.CMPR: | ||
write_cmpr(buffer, img) | ||
elif fmt == Formats.I8: | ||
write_i8(buffer, img) | ||
#out_buf.write(syaz0.compress(buffer.getvalue())) | ||
out_buf.write(buffer.getvalue()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.