summaryrefslogtreecommitdiff
path: root/scripts/embed_assets.py
blob: 52309ef2c04a584fa55c1f931349461690155b17 (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
#!/usr/bin/env python3
"""
Embed asset files (images, sounds, fonts, etc.) into a C header file.
Usage: python embed_assets.py <output.h> <file1.png> [file2.wav] [file3.ttf] ...

Embeds all specified asset files into a C header for inclusion in the executable.
"""
import sys
import os

def sanitize_name(filename):
    """Convert filename to valid C identifier"""
    name = os.path.basename(filename)
    # Remove or replace all non-alphanumeric characters (except underscore)
    valid_chars = []
    for char in name:
        if char.isalnum() or char == '_':
            valid_chars.append(char)
        else:
            valid_chars.append('_')
    name = ''.join(valid_chars)
    # Ensure it doesn't start with a digit
    if name and name[0].isdigit():
        name = '_' + name
    return name

def get_file_extension(filename):
    """Get the file extension"""
    return os.path.splitext(filename)[1].lower()

def embed_files(output_file, input_files):
    with open(output_file, 'w') as f:
        f.write('#ifndef EMBEDDED_ASSETS_H\n')
        f.write('#define EMBEDDED_ASSETS_H\n\n')
        f.write('/* Auto-generated file - do not edit manually */\n\n')
        
        # Embed each file as a separate array
        for idx, input_file in enumerate(input_files):
            with open(input_file, 'rb') as inf:
                data = inf.read()
            
            var_name = sanitize_name(input_file)
            # Extract relative path from 'assets/' onwards if present
            if 'assets' in input_file.replace('\\', '/'):
                parts = input_file.replace('\\', '/').split('assets/')
                if len(parts) > 1:
                    relative_name = 'assets/' + parts[-1]
                else:
                    relative_name = os.path.basename(input_file)
            else:
                relative_name = os.path.basename(input_file)
            
            f.write(f'/* Embedded asset: {input_file} ({len(data)} bytes) */\n')
            f.write(f'static const unsigned char embedded_asset_{idx}_{var_name}[] = {{\n')
            
            for i, byte in enumerate(data):
                if i % 12 == 0:
                    f.write('    ')
                f.write(f'0x{byte:02x}')
                if i < len(data) - 1:
                    f.write(',')
                    if (i + 1) % 12 == 0:
                        f.write('\n')
                    else:
                        f.write(' ')
            
            f.write('\n};\n')
            f.write(f'static const unsigned int embedded_asset_{idx}_{var_name}_len = {len(data)};\n\n')
        
        # Create the asset table
        f.write('/* Asset table for virtual filesystem */\n')
        f.write('typedef struct {\n')
        f.write('    const char* name;\n')
        f.write('    const unsigned char* data;\n')
        f.write('    unsigned int size;\n')
        f.write('} EmbeddedAsset;\n\n')
        
        f.write('static const EmbeddedAsset embedded_assets[] = {\n')
        for idx, input_file in enumerate(input_files):
            var_name = sanitize_name(input_file)
            # Extract relative path from 'assets/' onwards if present
            if 'assets' in input_file.replace('\\', '/'):
                parts = input_file.replace('\\', '/').split('assets/')
                if len(parts) > 1:
                    relative_name = 'assets/' + parts[-1]
                else:
                    relative_name = os.path.basename(input_file)
            else:
                relative_name = os.path.basename(input_file)
            f.write(f'    {{ "{relative_name}", embedded_asset_{idx}_{var_name}, embedded_asset_{idx}_{var_name}_len }},\n')
        f.write('};\n\n')
        
        f.write(f'static const int embedded_asset_count = {len(input_files)};\n\n')
        f.write('#endif /* EMBEDDED_ASSETS_H */\n')

if __name__ == '__main__':
    if len(sys.argv) < 3:
        print('Usage: python embed_assets.py <output.h> <asset1> [asset2] ...')
        print('  Embeds images, sounds, fonts, and other asset files into a C header.')
        print('  Supported: .png, .jpg, .wav, .ogg, .mp3, .ttf, .otf, etc.')
        sys.exit(1)
    
    output_file = sys.argv[1]
    input_files = sys.argv[2:]
    
    # Check all input files exist
    for f in input_files:
        if not os.path.exists(f):
            print(f'Error: File not found: {f}')
            sys.exit(1)
    
    embed_files(output_file, input_files)
    print(f'Embedded {len(input_files)} asset file(s) into {output_file}')
    for f in input_files:
        size = os.path.getsize(f)
        print(f'  - {f} ({size} bytes)')