|  | @@ -0,0 +1,230 @@
 | 
	
		
			
				|  |  | +import bpy
 | 
	
		
			
				|  |  | +import mathutils
 | 
	
		
			
				|  |  | +import math
 | 
	
		
			
				|  |  | +import random
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# load outfittemplate-nocube.blend, then run this
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# add an ominous red lamp
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bpy.ops.object.add(type='LIGHT', location=(3,-3,0))
 | 
	
		
			
				|  |  | +lamp = bpy.context.object
 | 
	
		
			
				|  |  | +lamp.data.type = 'POINT'
 | 
	
		
			
				|  |  | +lamp.data.energy = 55
 | 
	
		
			
				|  |  | +lamp.data.color = [1.0,0.2,0.1]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# we need five materials
 | 
	
		
			
				|  |  | +#   - the monitor (image texture)
 | 
	
		
			
				|  |  | +#   - the metal for the case
 | 
	
		
			
				|  |  | +#   - three colors for the buttons
 | 
	
		
			
				|  |  | +#     - green (pressed down)
 | 
	
		
			
				|  |  | +#     - grey/clear (most unpressed)
 | 
	
		
			
				|  |  | +#     - red (unpressed but alert)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +monitor_mat = bpy.data.materials.new("ComputerMonitor")
 | 
	
		
			
				|  |  | +monitor_mat.diffuse_color = [0, 0.02, 0, 1]
 | 
	
		
			
				|  |  | +monitor_mat.specular_color = [0.9, 1, 0.9]
 | 
	
		
			
				|  |  | +monitor_mat.roughness = 0.05
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +monitor_mat.use_nodes = True
 | 
	
		
			
				|  |  | +mon_nodes = monitor_mat.node_tree.nodes
 | 
	
		
			
				|  |  | +mon_links = monitor_mat.node_tree.links
 | 
	
		
			
				|  |  | +mon_mat_output = mon_nodes.get('Material Output')
 | 
	
		
			
				|  |  | +mon_bsdf = mon_nodes.get('Principled BSDF')
 | 
	
		
			
				|  |  | +mon_bsdf.inputs['Roughness'].default_value = 0.1
 | 
	
		
			
				|  |  | +mon_bsdf.inputs['Emission Strength'].default_value = 30
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +mon_img = bpy.data.images.load(filepath = '/home/jmelesky/code/endless-sky-artificial-crew-models/images/oscilloscreen red.png')
 | 
	
		
			
				|  |  | +mon_imgtx = mon_nodes.new('ShaderNodeTexImage')
 | 
	
		
			
				|  |  | +mon_imgtx.image = mon_img
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +mon_links.new(mon_imgtx.outputs['Color'], mon_bsdf.inputs['Base Color'])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +mon_ramp = mon_nodes.new('ShaderNodeValToRGB')
 | 
	
		
			
				|  |  | +mon_ramp.color_ramp.interpolation = 'B_SPLINE'
 | 
	
		
			
				|  |  | +mon_ramp.color_ramp.elements[0].position = 0.1
 | 
	
		
			
				|  |  | +mon_ramp.color_ramp.elements[1].color = [1.0, 0.2, 0.1, 1.0]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +mon_links.new(mon_imgtx.outputs['Color'], mon_ramp.inputs['Fac'])
 | 
	
		
			
				|  |  | +mon_links.new(mon_ramp.outputs['Color'], mon_bsdf.inputs['Emission Color'])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +metal_mat = bpy.data.materials.new("ComputerMetal")
 | 
	
		
			
				|  |  | +metal_mat.use_nodes = True
 | 
	
		
			
				|  |  | +metal_nodes = metal_mat.node_tree.nodes
 | 
	
		
			
				|  |  | +metal_links = metal_mat.node_tree.links
 | 
	
		
			
				|  |  | +metal_mat_output = metal_nodes.get('Material Output')
 | 
	
		
			
				|  |  | +metal_bsdf = metal_nodes.get('Principled BSDF')
 | 
	
		
			
				|  |  | +metal_bsdf.inputs['Metallic'].default_value = 1.0
 | 
	
		
			
				|  |  | +metal_bsdf.inputs['Base Color'].default_value = [0.16, 0.12, 0.08, 1.0]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# metal_noise = metal_nodes.new('ShaderNodeTexNoise')
 | 
	
		
			
				|  |  | +# metal_noise.inputs['Scale'].default_value = 70.0
 | 
	
		
			
				|  |  | +# metal_noise.inputs['Detail'].default_value = 15.0
 | 
	
		
			
				|  |  | +# metal_noise.inputs['Roughness'].default_value = 0.6
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# metal_ramp = metal_nodes.new('ShaderNodeValToRGB')
 | 
	
		
			
				|  |  | +# metal_ramp.color_ramp.elements[0].color = [0.08, 0.07, 0.03, 1.0]
 | 
	
		
			
				|  |  | +# metal_ramp.color_ramp.elements[1].color = [0.16, 0.155, 0.08, 1.0]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# metal_links.new(metal_noise.outputs['Fac'], metal_ramp.inputs['Fac'])
 | 
	
		
			
				|  |  | +# metal_links.new(metal_ramp.outputs['Color'], metal_bsdf.inputs['Base Color'])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +metal_bump = metal_nodes.new('ShaderNodeBump')
 | 
	
		
			
				|  |  | +metal_bump.invert = True
 | 
	
		
			
				|  |  | +metal_bump.inputs['Strength'].default_value = 0.3
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +metal_noise2 = metal_nodes.new('ShaderNodeTexNoise')
 | 
	
		
			
				|  |  | +metal_noise2.inputs['Scale'].default_value = 70.0
 | 
	
		
			
				|  |  | +metal_noise2.inputs['Detail'].default_value = 15.0
 | 
	
		
			
				|  |  | +metal_noise2.inputs['Roughness'].default_value = 0.6
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +metal_links.new(metal_noise2.outputs['Fac'], metal_bump.inputs['Height'])
 | 
	
		
			
				|  |  | +metal_links.new(metal_bump.outputs['Normal'], metal_bsdf.inputs['Normal'])
 | 
	
		
			
				|  |  | +metal_links.new(metal_bump.outputs['Normal'], metal_bsdf.inputs['Roughness'])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +down_button_mat = bpy.data.materials.new("DownButton")
 | 
	
		
			
				|  |  | +down_button_mat.use_nodes = True
 | 
	
		
			
				|  |  | +down_button_mat.blend_method = 'BLEND'
 | 
	
		
			
				|  |  | +down_bsdf = down_button_mat.node_tree.nodes.get('Principled BSDF')
 | 
	
		
			
				|  |  | +down_bsdf.inputs['Base Color'].default_value = [0.5, 0.5, 0.5, 0.95]
 | 
	
		
			
				|  |  | +down_bsdf.inputs['Roughness'].default_value = 0.4
 | 
	
		
			
				|  |  | +down_bsdf.inputs['Emission Color'].default_value = [0.2, 0.85, 0.2, 0.3]
 | 
	
		
			
				|  |  | +down_bsdf.inputs['Emission Strength'].default_value = 0.8
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +up_button_mat = bpy.data.materials.new("UpButton")
 | 
	
		
			
				|  |  | +up_button_mat.diffuse_color = [0.5, 0.5, 0.5, 0.4]
 | 
	
		
			
				|  |  | +up_button_mat.roughness = 0.8
 | 
	
		
			
				|  |  | +up_button_mat.blend_method = 'BLEND'
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +attn_button_mat = bpy.data.materials.new("AttnButton")
 | 
	
		
			
				|  |  | +attn_button_mat.use_nodes = True
 | 
	
		
			
				|  |  | +attn_button_mat.blend_method = 'BLEND'
 | 
	
		
			
				|  |  | +attn_bsdf = attn_button_mat.node_tree.nodes.get('Principled BSDF')
 | 
	
		
			
				|  |  | +attn_bsdf.inputs['Base Color'].default_value = [0.5, 0.5, 0.5, 0.95]
 | 
	
		
			
				|  |  | +attn_bsdf.inputs['Roughness'].default_value = 0.4
 | 
	
		
			
				|  |  | +attn_bsdf.inputs['Emission Color'].default_value = [0.7, 0.1, 0.1, 0.3]
 | 
	
		
			
				|  |  | +attn_bsdf.inputs['Emission Strength'].default_value = 0.7
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# now the big box
 | 
	
		
			
				|  |  | +back_bottom_left   = (0,0,0)
 | 
	
		
			
				|  |  | +back_top_left      = (0,0,8)
 | 
	
		
			
				|  |  | +front_top_left     = (2,0,8)
 | 
	
		
			
				|  |  | +front_mid_left     = (4,0,3)
 | 
	
		
			
				|  |  | +front_bottom_left  = (4,0,0)
 | 
	
		
			
				|  |  | +back_bottom_right  = (0,10,0)
 | 
	
		
			
				|  |  | +back_top_right     = (0,10,8)
 | 
	
		
			
				|  |  | +front_top_right    = (2,10,8)
 | 
	
		
			
				|  |  | +front_mid_right    = (4,10,3)
 | 
	
		
			
				|  |  | +front_bottom_right = (4,10,0)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +box_vertices = [back_bottom_left, back_top_left, back_bottom_right, back_top_right,
 | 
	
		
			
				|  |  | +    front_top_left, front_top_right, front_mid_left, front_mid_right,
 | 
	
		
			
				|  |  | +    front_bottom_left, front_bottom_right]
 | 
	
		
			
				|  |  | +box_faces = [
 | 
	
		
			
				|  |  | +    (0,1,3,2), # the back of the box: back_bottom_left, back_top_left, back_top_right, back_bottom_right
 | 
	
		
			
				|  |  | +    (0,2,9,8), # the bottom: back_bottom_left, back_bottom_right, front_bottom_right, front_bottom_left
 | 
	
		
			
				|  |  | +    (8,9,7,6), # lower front plate: front_bottom_left, front_bottom_right, front_mid_right, front_mid_left
 | 
	
		
			
				|  |  | +    (9,2,3,5,7), # right side panel (5 edges): front_bottom_right, back_bottom_right, back_top_right, front_top_right, front_mid_right
 | 
	
		
			
				|  |  | +    (0,8,6,4,1), # left side panel: back_bottom_left, front_bottom_left, front_mid_left, front_top_left, back_top_left
 | 
	
		
			
				|  |  | +    (6,7,5,4), # upper front plate: front_mid_left, front_mid_right, front_top_right, front_top_left
 | 
	
		
			
				|  |  | +    (4,5,3,1), # top: front_top_left, front_top_right, back_top_right, back_top_left
 | 
	
		
			
				|  |  | +]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# box_mat = bpy.data.materials.new('MyBoxMaterial')
 | 
	
		
			
				|  |  | +# box_mat.use_nodes = True
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# if box_mat.node_tree:
 | 
	
		
			
				|  |  | +#     box_mat.node_tree.links.clear()
 | 
	
		
			
				|  |  | +#     box_mat.node_tree.nodes.clear()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# box_output = box_mat.node_tree.nodes.new(type='ShaderNodeOutputMaterial')
 | 
	
		
			
				|  |  | +# box_shader = box_mat.node_tree.nodes.new(type='ShaderNodeBsdfDiffuse')
 | 
	
		
			
				|  |  | +# box_mat.node_tree.nodes['Diffuse BSDF'].inputs[0].default_value = (.125, .179, .263, 1)
 | 
	
		
			
				|  |  | +# box_mat.node_tree.links.new(box_shader.outputs[0], box_output.inputs[0])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +box_mesh = bpy.data.meshes.new('MyComputerBoxMesh')
 | 
	
		
			
				|  |  | +box_mesh.from_pydata(box_vertices, [], box_faces)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +box_obj = bpy.data.objects.new('MyComputerBox', box_mesh)
 | 
	
		
			
				|  |  | +box_obj.data.materials.append(metal_mat)
 | 
	
		
			
				|  |  | +bpy.context.scene.collection.objects.link(box_obj)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# the oscilloscope-style monitor
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +monitor_location = mathutils.Vector((3, 2.5, 5.5))
 | 
	
		
			
				|  |  | +monitor_scale = mathutils.Vector((.4, 1, 1))
 | 
	
		
			
				|  |  | +monitor_rotation = mathutils.Euler((0, math.radians(203), math.radians(180)))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bpy.ops.mesh.primitive_uv_sphere_add(
 | 
	
		
			
				|  |  | +    segments=32,
 | 
	
		
			
				|  |  | +    ring_count=16,
 | 
	
		
			
				|  |  | +    radius=2,
 | 
	
		
			
				|  |  | +    location=monitor_location,
 | 
	
		
			
				|  |  | +    scale=monitor_scale, # this is relative to the size
 | 
	
		
			
				|  |  | +    rotation=monitor_rotation)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# smooth the monitor, add a texture
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +monitor_obj = bpy.context.active_object
 | 
	
		
			
				|  |  | +for f in monitor_obj.data.polygons:
 | 
	
		
			
				|  |  | +    f.use_smooth = True
 | 
	
		
			
				|  |  | +monitor_obj.data.update()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +monitor_obj.data.materials.append(monitor_mat)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# three rows of buttons, randomly depressed
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +# a better way to do this would be to set the buttons in a group,
 | 
	
		
			
				|  |  | +# then rotate that entire group. i'm not there yet, so we're
 | 
	
		
			
				|  |  | +# using some magic numbers for positional offsets.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +buttons = []
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +for i in [7, 5.5, 4]:
 | 
	
		
			
				|  |  | +    for j in [6.8, 7.2, 7.6, 8, 8.4, 8.8, 9.2]:
 | 
	
		
			
				|  |  | +        if random.random() > .9:
 | 
	
		
			
				|  |  | +            button_location = mathutils.Vector((5.0 - (i/2.5), j, i-.1))
 | 
	
		
			
				|  |  | +            button_material = down_button_mat
 | 
	
		
			
				|  |  | +        else:
 | 
	
		
			
				|  |  | +            button_location = mathutils.Vector((5.2 - (i/2.5), j, i))
 | 
	
		
			
				|  |  | +            if random.random() > .2:
 | 
	
		
			
				|  |  | +                button_material = attn_button_mat
 | 
	
		
			
				|  |  | +            else:
 | 
	
		
			
				|  |  | +                button_material = up_button_mat
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        bpy.ops.mesh.primitive_cube_add(
 | 
	
		
			
				|  |  | +            size=1,
 | 
	
		
			
				|  |  | +            location=button_location,
 | 
	
		
			
				|  |  | +            rotation=monitor_rotation,
 | 
	
		
			
				|  |  | +            scale=mathutils.Vector((.8, .2, .6)))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        button = bpy.context.active_object
 | 
	
		
			
				|  |  | +        buttons.append(button)
 | 
	
		
			
				|  |  | +        button.data.materials.append(button_material)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +box_obj.select_set(True)
 | 
	
		
			
				|  |  | +monitor_obj.select_set(True)
 | 
	
		
			
				|  |  | +for b in buttons:
 | 
	
		
			
				|  |  | +    b.select_set(True)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bpy.ops.transform.resize(
 | 
	
		
			
				|  |  | +    value=(0.5, 0.5, 0.5)
 | 
	
		
			
				|  |  | +)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bpy.ops.transform.rotate(
 | 
	
		
			
				|  |  | +    value=math.radians(90)
 | 
	
		
			
				|  |  | +)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bpy.ops.transform.translate(
 | 
	
		
			
				|  |  | +    value=(-2.5,-5,-3.3)
 | 
	
		
			
				|  |  | +)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 |