"""Placeholder atom kit (boxes with the agreed sizes and origins) to test the house assembler before the real kit.
usage: python3 tools/placeholder_kit.py browse/kits/placeholder"""
import json, struct, sys, os
out = sys.argv[1]
# atom: list of boxes (cx, cy, cz, sx, sy, sz, material)
G, D, S, T, F, Z, GL, TC = 'Granite_lime_moss', 'Dressed_granite', 'Blue_grey_slate', 'Breton_blue_timber', 'Aged_ivory_frames', 'Weathered_zinc_iron', 'Old_window_glass', 'Terracotta'
def win(w, h, shutters=False):
    b = [(0, h + .1, .03, w + .5, .2, .14, D), (0, -.06, .05, w + .3, .1, .18, D), (-(w / 2 + .12), h / 2, .02, .24, h, .1, D), ((w / 2 + .12), h / 2, .02, .24, h, .1, D),
         (0, h / 2, -.1, w, h, .06, F), (0, h / 2, -.12, w - .1, h - .1, .02, GL), (0, h / 2, -.19, w, .02, .38, D)]
    if shutters: b += [(-(w * .75 + .3), h / 2, .05, w / 2, h, .04, T), ((w * .75 + .3), h / 2, .05, w / 2, h, .04, T)]
    return b
A = {
 'slate_a': [(0, .006, .21, .34, .012, .42, S)], 'slate_b': [(0, .006, .21, .34, .012, .42, S)], 'slate_c': [(0, .006, .21, .34, .012, .42, S)],
 'ridge_tile': [(0, .05, 0, .42, .1, .3, TC)], 'quoin_long': [(0, 0, 0, .6, .386, .35, D)], 'quoin_short': [(0, 0, 0, .35, .386, .65, D)],
 'window_ground': win(.95, 1.3), 'window_ground_shutters': win(.95, 1.3, True), 'window_upper': win(.85, 1.1), 'window_upper_shutters': win(.85, 1.1, True),
 'window_small': win(.5, .7), 'door': [(0, 1.05, -.1, 1.0, 2.1, .08, T), (0, -.05, .25, 1.3, .1, .5, D), (-.62, 1.05, .02, .24, 2.1, .1, D), (.62, 1.05, .02, .24, 2.1, .1, D), (0, 2.2, .02, 1.5, .2, .12, D)],
 'dormer': [(0, .9, -.2, 1.3, 1.8, .4, D), (0, 1.9, -.6, 1.5, .1, 1.2, S)], 'chimney_stack': [(0, 1.0, 0, 1.0, 2.0, .7, D), (-.2, 2.2, 0, .18, .4, .18, TC), (.2, 2.2, 0, .18, .4, .18, TC)],
 'gutter_1m': [(0, -.05, .07, 1.0, .1, .14, Z)], 'downpipe_1m': [(0, .5, .06, .08, 1.0, .08, Z)], 'eaves_board_1m': [(0, -.1, .02, 1.0, .2, .03, F)],
 'verge_board_1m': [(0, -.1, .02, 1.0, .2, .03, F)], 'lantern': [(0, 0, .12, .2, .35, .2, Z)],
}
mats = [G, D, S, T, F, Z, GL, TC]
def box(cx, cy, cz, sx, sy, sz):
    P, N, U, I = [], [], [], []
    for ax, sg in [(0, 1), (0, -1), (1, 1), (1, -1), (2, 1), (2, -1)]:
        n = [0, 0, 0]; n[ax] = sg; a, b = [k for k in range(3) if k != ax]
        base = len(P)
        for du, dv in [(-1, -1), (1, -1), (1, 1), (-1, 1)]:
            p = [cx, cy, cz]; s = [sx, sy, sz]; p[ax] += sg * s[ax] / 2; p[a] += du * s[a] / 2; p[b] += dv * s[b] / 2
            P.append(p); N.append(n); U.append([p[a] / 1.0, p[b] / 1.0])
        I += [base, base + 1, base + 2, base, base + 2, base + 3] if sg > 0 else [base, base + 2, base + 1, base, base + 3, base + 2]
    return P, N, U, I
bin_, views, accs, meshes, nodes = bytearray(), [], [], [], []
def push(data, fmt, comps, target, minmax=False):
    off = len(bin_); raw = b''.join(struct.pack('<' + fmt * comps, *v) if comps > 1 else struct.pack('<' + fmt, v) for v in data)
    bin_.extend(raw); bin_.extend(b'\0' * ((4 - len(raw) % 4) % 4))
    views.append({'buffer': 0, 'byteOffset': off, 'byteLength': len(raw), 'target': target})
    acc = {'bufferView': len(views) - 1, 'componentType': 5126 if fmt == 'f' else 5125, 'count': len(data), 'type': {1: 'SCALAR', 2: 'VEC2', 3: 'VEC3'}[comps]}
    if minmax: acc['min'] = [min(v[k] for v in data) for k in range(3)]; acc['max'] = [max(v[k] for v in data) for k in range(3)]
    accs.append(acc); return len(accs) - 1
for name, boxes in A.items():
    prims = []
    for m in mats:
        bs = [b for b in boxes if b[6] == m]
        if not bs: continue
        P, N, U, I = [], [], [], []
        for b in bs:
            p, n, u, i = box(*b[:6]); I += [x + len(P) for x in i]; P += p; N += n; U += u
        prims.append({'attributes': {'POSITION': push(P, 'f', 3, 34962, True), 'NORMAL': push(N, 'f', 3, 34962), 'TEXCOORD_0': push(U, 'f', 2, 34962)},
                      'indices': push(I, 'I', 1, 34963), 'material': mats.index(m)})
    meshes.append({'name': name, 'primitives': prims}); nodes.append({'name': name, 'mesh': len(meshes) - 1})
doc = {'asset': {'version': '2.0'}, 'scene': 0, 'scenes': [{'nodes': list(range(len(nodes)))}], 'nodes': nodes, 'meshes': meshes,
       'materials': [{'name': m} for m in mats], 'accessors': accs, 'bufferViews': views, 'buffers': [{'byteLength': len(bin_)}]}
js = json.dumps(doc).encode(); js += b' ' * ((4 - len(js) % 4) % 4)
glb = struct.pack('<4sII', b'glTF', 2, 12 + 8 + len(js) + 8 + len(bin_)) + struct.pack('<I4s', len(js), b'JSON') + js + struct.pack('<I4s', len(bin_), b'BIN\0') + bytes(bin_)
open(os.path.join(out, 'kit.glb'), 'wb').write(glb)
json.dump({'file': 'kit.glb', 'atoms': [{'name': n} for n in A]}, open(os.path.join(out, 'kit.json'), 'w'))
tiles = {G: 2.25, D: 1.0, S: 1.0, T: 1.0, F: 1.0, Z: 1.0, GL: 1.0, TC: 1.0}
M = {}
for m in mats:
    f = lambda k: f'materials/{m}_{k}.jpg'
    if not os.path.exists(os.path.join(out, f('BaseColor'))): continue
    M[m] = {'base': f('BaseColor'), 'normal': f('Normal') if os.path.exists(os.path.join(out, f('Normal'))) else f('BaseColor'),
            'orm': f('ORM') if os.path.exists(os.path.join(out, f('ORM'))) else f('BaseColor'), 'tile': tiles[m], 'metal': m == Z}
if os.path.exists(os.path.join(out, 'materials/rock_wall_09_disp_1k.jpg')): M[G]['height'] = 'materials/rock_wall_09_disp_1k.jpg'
M[GL]['transparent'] = True
json.dump({'materials': M}, open(os.path.join(out, 'materials.json'), 'w'), indent=1)
print('placeholder kit', len(A), 'atoms', len(glb), 'bytes')
