# Rendering script
# Run by calling the blender executable with -b -P <script_name>
# Disclaimer: I never did Python before so this is mostly hacks
#
# process:
# 1) Load model given as a parameter
# 2) Create emitting surfaces to act as lamps
# 3) Create camera
# 4) Rotate model and shoot image at each step
#
# Use `code.interact(local=dict(globals(), **locals()))` to pry into the script

import bpy
import os
import argparse
import datetime
import bmesh
import random
import code
import math
import mathutils
import random
import uuid

exec(open("lib/glitch3d/bpy/helpers.py").read())

# Arguments parsing
args = get_args()
file = args.file
mode = args.mode
shots_number = int(args.shots_number)

context = bpy.context

REFLECTOR_SCALE = 5
REFLECTOR_STRENGTH = 12
REFLECTOR_LOCATION_PADDING = 10
PROPS_NUMBER = 100
SHADERS = ['ShaderNodeBsdfGlossy', 'ShaderNodeBsdfDiffuse', 'ShaderNodeBsdfVelvet']

# Scene
new_scene = bpy.data.scenes.new("Automated Render Scene")
bpy.ops.scene.delete() # Delete old scene
context.screen.scene = new_scene # selects the new scene as the current one

# Render settings
context.scene.render.resolution_x = 1920
context.scene.render.resolution_y = 1080
context.scene.render.engine = 'CYCLES'
context.scene.render.resolution_percentage = 25
# bpy.context.scene.cycles.device = 'GPU'
context.scene.render.image_settings.compression = 0
context.scene.cycles.samples = 25
context.scene.render.image_settings.color_mode ='RGBA'
context.scene.render.image_settings.file_format='PNG'

if mode == 'high':
    context.scene.render.image_settings.compression = 90
    context.scene.cycles.samples = 500
    context.scene.render.resolution_percentage = 100

# Load model
model_path = os.path.join(file)
bpy.ops.import_scene.obj(filepath = model_path, use_edges=True)
model_object = bpy.data.objects['Glitch3D']

# Use center of mass to center object
model_object.select = True
bpy.ops.object.origin_set(type="ORIGIN_CENTER_OF_MASS")
model_object.location = (0, 0, 0)

# --------------
# Create camera
# --------------
camera_data = bpy.data.cameras.new('Render Camera')
bpy.data.objects.new('Render Camera', object_data=camera_data)
camera_object = bpy.data.objects['Render Camera']
new_scene.objects.link(camera_object)
camera_object.location = (8, 8, 0)

# Add reflectors
bpy.ops.mesh.primitive_plane_add(location=(0,8 + REFLECTOR_LOCATION_PADDING, 0))
bpy.ops.mesh.primitive_plane_add(location=(8 + REFLECTOR_LOCATION_PADDING,0,0))

plane1 = bpy.data.objects['Plane']
plane2 = bpy.data.objects['Plane.001']

# Adjust camera
context.scene.camera = camera_object
look_at(camera_object, model_object)
assign_material(model_object, create_cycles_material())

for index, plane in enumerate([plane1, plane2]):
    plane.scale = (REFLECTOR_SCALE, REFLECTOR_SCALE, REFLECTOR_SCALE)
    plane.rotation_euler.x += math.radians(90)
    emissive_material = bpy.data.materials.new('Emissive Material #' + str(index))
    emissive_material.use_nodes = True
    emission_node = emissive_material.node_tree.nodes.new('ShaderNodeEmission')
    # Set color
    emission_node.inputs[0].default_value = rand_color_vector()
    # Set strength
    emission_node.inputs[1].default_value = REFLECTOR_STRENGTH
    assign_node_to_output(emissive_material, emission_node)
    assign_material(plane, emissive_material)

# Tilt one of the reflectors
plane2.rotation_euler.z += math.radians(90)

# Add other elements
for index in range(0, int(PROPS_NUMBER)):
    bpy.ops.mesh.primitive_cube_add(location=rand_location(),radius=rand_scale(), rotation=rand_rotation())
    if index == 0:
        object_name = 'Cube'
    elif index > 9:
        object_name = 'Cube.0' + str(index)
    elif index > 99:
        object_name = 'Cube.' + str(index)
    else:
        object_name = 'Cube.00' + str(index)
    object = bpy.data.objects[object_name]
    new_material = create_cycles_material()
    assign_random_texture_to_material(new_material)
    assign_material(object, new_material)

for index in range(0, int(PROPS_NUMBER)):
    bpy.ops.mesh.primitive_circle_add(location=rand_location(),radius=rand_scale(), rotation=rand_rotation())
    if index == 0:
        object_name = 'Circle'
    elif index > 9:
        object_name = 'Circle.0' + str(index)
    elif index > 99:
        object_name = 'Circle.' + str(index)
    else:
        object_name = 'Circle.00' + str(index)
    object = bpy.data.objects[object_name]
    new_material = create_cycles_material()
    assign_random_texture_to_material(new_material)
    assign_material(object, new_material)

# Add background to world
world = bpy.data.worlds[0]
world.use_nodes = True
world_node_tree = world.node_tree
# code.interact(local=dict(globals(), **locals()))
gradient_node = world_node_tree.nodes.new(type="ShaderNodeTexGradient")
background_node = world_node_tree.nodes['Background']
world_node_tree.links.new(gradient_node.outputs['Color'], background_node.inputs['Color'])
gradient_node.gradient_type = 'EASING'

# ------
# Shoot
# ------
print('Rendering images with resolution: ' + str(context.scene.render.resolution_x) + ' x ' + str(context.scene.render.resolution_y))
for index in range(0, int(shots_number)):
    print("-------------------------- " + str(index) + " --------------------------")
    rotate(model_object, index)
    shoot(camera_object, model_object, output_name(index, model_path))

print('FINISHED ¯\_(ツ)_/¯')