summaryrefslogtreecommitdiffstats
path: root/Third_Party/gen_atlas
blob: 7cc6c41849a32faed28a9b91a76045b7fdc8c238 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/env python3

import argparse
import subprocess
import os
import json
from PIL import Image

def calculate_cell_dimensions(total_size, num_cells):
    """
    Distribute pixels evenly across cells, handling remainder.
    Returns a list of cell sizes that add up to total_size.
    """
    base_size = total_size // num_cells
    remainder = total_size % num_cells
    
    # Create array of cell sizes
    cell_sizes = []
    for i in range(num_cells):
        # Add an extra pixel to cells until remainder is used up
        # This distributes remainder pixels evenly across cells
        extra = 1 if i < remainder else 0
        cell_sizes.append(base_size + extra)
    
    return cell_sizes

def generate_atlas(font_path, resolution):
    # Calculate cell dimensions for 12x12 grid
    cell_widths = calculate_cell_dimensions(resolution, 12)
    cell_heights = calculate_cell_dimensions(resolution, 12)
    
    # Use the most common cell size
    cell_width = max(cell_widths)
    cell_height = max(cell_heights)

    # Construct the command with explicit glyph range for printable ASCII
    cmd = [
        "msdf-atlas-gen/build/bin/Debug/msdf-atlas-gen.exe",
        "-font", font_path,
        "-type", "msdf",
        "-format", "png",
        "-imageout", "atlas.png",
        "-json", "atlas.json",
        "-size", "32",
        "-pxrange", "2",
        "-dimensions", str(resolution), str(resolution),
        "-chars", "[32, 126]",
        "-uniformgrid",
        "-uniformcols", "12",
        "-uniformcell", str(cell_width), str(cell_height),
        "-uniformorigin", "on"
    ]

    try:
        result = subprocess.run(cmd, check=True, capture_output=True, text=True)
        
        # Rearrange the atlas to include gaps for non-printable characters
        rearrange_atlas(resolution, cell_width, cell_height)
        return True
    except subprocess.CalledProcessError as e:
        print(f"Error generating atlas: {e}")
        print(f"Error output: {e.stderr}")
        return False

def rearrange_atlas(resolution, cell_width, cell_height):
    """Rearrange the atlas to include gaps for non-printable characters"""
    # Load the original atlas and JSON data
    original = Image.open("atlas.png")
    with open("atlas.json", 'r') as f:
        data = json.load(f)
    
    # Create the new atlas image
    new_atlas = Image.new('RGB', (resolution, resolution), (0, 0, 0))
    
    # Calculate exact cell dimensions
    exact_cell_width = resolution / 12
    exact_cell_height = resolution / 12
    
    for glyph in data['glyphs']:
        if 'unicode' not in glyph or 'atlasBounds' not in glyph:
            continue
            
        char_code = glyph['unicode']
        
        # Calculate grid position using floor division to avoid rounding errors
        grid_x = (char_code % 12) * resolution // 12
        grid_y = (char_code // 12) * resolution // 12
        
        # Extract original bounds
        bounds = glyph['atlasBounds']
        orig_x = round(float(bounds['left']))  # Use round instead of int
        orig_y = resolution - round(float(bounds['top']))  # Use round instead of int
        width = round(float(bounds['right']) - float(bounds['left']))
        height = round(float(bounds['top']) - float(bounds['bottom']))
        
        # Extract the glyph from the original atlas
        glyph_region = original.crop((
            orig_x,
            orig_y,
            orig_x + width,
            orig_y + height
        ))
        
        # Paste the glyph directly at the grid position
        new_atlas.paste(glyph_region, (grid_x, grid_y))
    
    # Draw grid lines
    from PIL import ImageDraw
    draw = ImageDraw.Draw(new_atlas)
    
    # Draw vertical lines
    for x in range(12):
        line_x = x * resolution // 12  # Use integer division
        draw.line([(line_x, 0), (line_x, resolution-1)], fill=(255, 0, 0), width=1)
    
    # Draw horizontal lines
    for y in range(12):
        line_y = y * resolution // 12  # Use integer division
        draw.line([(0, line_y), (resolution-1, line_y)], fill=(255, 0, 0), width=1)
    
    # Draw the final borders
    draw.line([(resolution-1, 0), (resolution-1, resolution-1)], fill=(255, 0, 0), width=1)
    draw.line([(0, resolution-1), (resolution-1, resolution-1)], fill=(255, 0, 0), width=1)
    
    # Save the rearranged atlas
    new_atlas.save("atlas_rearranged.png")
    print("Atlas rearranged successfully!")

def main():
    parser = argparse.ArgumentParser(description='Generate a font atlas using msdf-atlas-gen')
    parser.add_argument('font_path', help='Path to the font file (.ttf/.otf)')
    parser.add_argument('resolution', type=int, help='Total atlas resolution (width=height)')
    
    args = parser.parse_args()

    # Verify font file exists
    if not os.path.isfile(args.font_path):
        print(f"Error: Font file not found at {args.font_path}")
        return

    generate_atlas(args.font_path, args.resolution)

if __name__ == "__main__":
    main()