"""Small facade fixture: generated straight frame/infill, wall cuts and repeated atoms.
Not an additional exported master; renders the real kit in its assembly context.
"""
import bpy,sys,math,json
from pathlib import Path
from mathutils import Vector,Matrix
ROOT=Path(__file__).resolve().parent;sys.path.insert(0,str(ROOT))
exec(compile((ROOT/'render_kit.py').read_text().split("(ROOT/'renders').mkdir")[0],str(ROOT/'render_kit.py'),'exec'))
import geometry as G
names=['Rubble_stone','Rubble_stone_dark','Oak_frame','Oak_frame_grey','Plaster_ochre','Plaster_white','Plaster_pink','Clay_tile','Clay_tile_dark','Dressed_limestone','Wrought_iron','Leaded_glass','Door_paint','Sign_paint']
# Unused shelf slots still need renderable materials for generated infill/walls.
for name in names:
 if name in bpy.data.materials:continue
 m=bpy.data.materials.new(name);m.use_nodes=True;bs=m.node_tree.nodes.get('Principled BSDF')
 for kind,path in SHELF[name]['maps'].items():
  tex=m.node_tree.nodes.new('ShaderNodeTexImage');tex.image=bpy.data.images.load(str(ROOT/path),check_existing=True);tex.image.colorspace_settings.name='sRGB' if kind=='BaseColor' else 'Non-Color'
  if kind=='BaseColor':m.node_tree.links.new(tex.outputs['Color'],bs.inputs['Base Color'])
  elif kind=='Normal':
   normal=m.node_tree.nodes.new('ShaderNodeNormalMap');m.node_tree.links.new(tex.outputs['Color'],normal.inputs[0]);m.node_tree.links.new(normal.outputs[0],bs.inputs['Normal'])
  else:
   sep=m.node_tree.nodes.new('ShaderNodeSeparateColor');m.node_tree.links.new(tex.outputs['Color'],sep.inputs[0]);m.node_tree.links.new(sep.outputs['Green'],bs.inputs['Roughness']);m.node_tree.links.new(sep.outputs['Blue'],bs.inputs['Metallic'])
G.MATS=[bpy.data.materials[n] for n in names];G.TILES=[SHELF[n]['tile_size_metres'] for n in names]
fixture=[]
def instance(name,x,y,z,rx=0,ry=0):
 source=masters[name];root=source.copy();root.data=source.data.copy() if source.type=='MESH' else None;bpy.context.collection.objects.link(root);root.name='FIXTURE_'+name;root.location=(x,-z,y);root.rotation_euler.rotate_axis('X',rx);root.rotation_euler.rotate_axis('Z',ry);root.hide_render=False
 def children(src,dst):
  for child in src.children:
   o=child.copy();o.data=child.data;o.parent=dst;bpy.context.collection.objects.link(o);o.hide_render=False;children(child,o)
 children(source,root);fixture.append(root);return root
frame=G.Mesh('FIXTURE_generated_frame_infill')
def box(x0,x1,y0,y1,z0,z1,mat,bevel=0,grain=(1,0,0)):
 frame.grain=Vector(grain);G.box(frame,((x0+x1)/2,(y0+y1)/2,(z0+z1)/2),(x1-x0,y1-y0,z1-z0),mat,bevel)
# Stone wall 0.5m thick, cut out for door and window, upper floor jetties 0.30m.
for lo,hi in [(-2,-1.45),(-.45,.65),(1.35,2)]:box(lo,hi,0,2.4,-.8,-.3,0,.006)
box(-1.45,-.45,2,2.4,-.8,-.3,0);box(.65,1.35,0,.85,-.8,-.3,0);box(.65,1.35,1.85,2.4,-.8,-.3,0)
instance('door_plank',-.95,0,-.3);instance('window_leaded_stone',1,.85,-.3)
# Infills are set back exactly 25mm from timber face. Central opening is .7 x 1.
for lo,hi in [(-1.94,-.44),(.44,1.94)]:box(lo,hi,2.46,4.74,-.19,-.025,4,.002)
for lo,hi in [(-.35,.35)]:box(lo,hi,2.46,3.0,-.19,-.025,5,.002);box(lo,hi,4.09,4.74,-.19,-.025,5,.002)
for x in [-1.94,1.94]:box(x-.06,x+.06,2.4,4.8,-.2,0,2,.007,(0,1,0))
for x in [-.395,.395]:
 for lo,hi in [(2.4,3.045),(4.045,4.8)]:box(x-.045,x+.045,lo,hi,-.2,0,2,.006,(0,1,0))
for y in [2.4,4.74]:box(-2,2,y,y+.06,-.2,0,2,.007)
instance('window_leaded',0,3.045,0)
instance('brace_storey',-1.24,2.4,0);o=instance('brace_storey',1.24,2.4,0);o.scale.x=-1
for x in [-1.5,-.5,.5,1.5]:instance('bressummer_1m',x,2.4,.02)
for x in [-1.75,-1.25,-.75,-.25,.25,.75,1.25,1.75]:instance('joist_end',x,2.18,-.3)
for x in [-1.88,1.88]:instance('jetty_bracket',x,2.18,-.3)
# Separate steep roof above the facade, repeated tiles in actual dimensions.
p=math.radians(55);length=1.82;ridgeY=4.82+length*math.sin(p);ridgeZ=-.5
rot=Matrix.Rotation(p,3,'X');G.box(frame,(0,ridgeY-length/2*math.sin(p)-.025,ridgeZ+length/2*math.cos(p)),(4.12,.035,length),8,0,rot)
for row in range(17):
 for x in [-1.32,0,1.32]:instance('tile_strip_'+('a' if row%2==0 else 'b'),x,ridgeY-row*.1*math.sin(p),ridgeZ+row*.1*math.cos(p),p)
for j in range(16):instance('ridge_tile_round',-1.91+j*.255,ridgeY+.025,ridgeZ)
for x in [-1.75,-1.25,-.75,-.25,.25,.75,1.25,1.75]:instance('rafter_end',x,4.84,.29)
instance('tavern_sign',1.79,3.4,.03);instance('barrel',-2.38,0,.35);instance('bench_wood',1.3,0,.58)
ob=frame.finish();ob.rotation_euler.x=math.pi/2;fixture.append(ob)
render('assembly_check.png',fixture,(.32,-1,.32),(1700,1500))
render('assembly_clay.png',fixture,(.32,-1,.32),(1700,1500),True)
print('ASSEMBLY_FIXTURE_COMPLETE')
