#!BPY
import bpy
import mathutils
import json
import bmesh
import os

bundlesDirectory = r"H:\MEC\bundles";

skelJson = r"ebx\characters\skeletons\skeleton_faith.json"

importTables = [
    {
        "jsonMeshFile": r"res\characters\faith\armgear\magrope\magrope_skin_mesh\magrope_skin-lod1.json",
        "diffuseMap":   r"res\characters\faith\armgear\magrope\t_magrope_d ec6cb90b09fef721 0b000000010000000000000000000000.PNG"
    },
    {
        "jsonMeshFile": r"res\characters\faith\arms\faith_arms_mesh\faith_arms-lod1.json"
    },
    {
        "jsonMeshFile": r"res\characters\faith\gridlink\faith_gridlink_mesh\faith_gridlink-lod1.json"
    },
    {
        "jsonMeshFile": r"res\characters\faith\hair\faith_hair_3pcloth_ingame_mesh ba25d653909762f1 3005000070a404006800000090003001-lod1.json",
        "diffuseMap":   r"res\characters\faith\hair\t_alphahair_a 98be69afce0ddd0b 0b000000010000000000000000000000.PNG"
    },
    {
        "jsonMeshFile": r"res\characters\faith\head\faith_head_mesh 9bd03e0f689c56d9 002c190020050800f800000090003001-lod1.json",
        "diffuseMap":   r"res\characters\faith\head\t_faithhead_dao b99b387e03207ab7 0b000000010000000000000000000000.PNG"
    },
    {
        "jsonMeshFile": r"res\characters\faith\headparts\faith_headparts_mesh\faith_headparts-lod1.json"
    },
    {
        "jsonMeshFile": r"res\characters\faith\lowerbody\faith_lowerbody_mesh\faith_lowerbody-lod1.json",
        "diffuseMap":   r"res\characters\faith\lowerbody\t_lowerbody_dao fc8450880b45f12b 0b000000010000000000000000000000.PNG"
    },
    {
        "jsonMeshFile": r"res\characters\faith\toolbag\faith_toolbag_mesh\faith_toolbag-lod1.json",
        "diffuseMap":   r"res\characters\faith\toolbag\faith_pickupbag_dao 6206caa6286b3edb 0b000000010000000000000000000000.PNG"
    },
    {
        "jsonMeshFile": r"res\characters\faith\upperbody\faith_upperbody_mesh\faith_upperbody-lod1.json",
        "diffuseMap":   r"res\characters\faith\upperbody\t_arms_dao a97c9a442565aba7 0b000000010000000000000000000000.PNG"
    }
]

def importSkelton(json):
  # Create Armature and Object
  bpy.ops.object.add(type='ARMATURE', enter_editmode=True, location=(0,0,0))
  object = bpy.context.object
  object.name = json["name"]
  armature = object.data
  armature.name = 'Skeleton'

  bones = {}
  absMatrices = {}

  jsonBones = json["bones"]

  for jsonBone in jsonBones:
      index = jsonBone["index"]
      parentIndex = jsonBone["parentIndex"]
      
      if parentIndex != -1:
          tail = mathutils.Vector(jsonBone["vector2"])
          head = bones[parentIndex].tail

          delta = tail - head
          deltaNorm = delta.copy()
          deltaNorm.normalize()
          
          tail = tail
          head = tail - deltaNorm * 0.05
          
          bone = armature.edit_bones.new(jsonBone["name"])
          bone.tail = tail
          bone.head = head
          bone.parent = bones[parentIndex]
          
          bones[index] = bone
      else:
          bone = armature.edit_bones.new(jsonBone["name"])
          bones[index] = bone

  bpy.ops.object.mode_set(mode='OBJECT')
  
  return {
    "object": object,
    "armature": armature,
    "bones": bones,
    "jsonBones": jsonBones
    }

def importMesh(json, skeleton, diffuseMap):
  # http://wiki.xentax.com/index.php/Blender_Import_Guide#Creating_vertices.2C_edges.2C_faces

  for subMesh in json["subMeshes"]:
    verts = subMesh["vertexes"]
    edges = []
    faces = subMesh["indices"]

    name = "%s+%s" % (json["name"], subMesh["shader"])
    mesh = bpy.data.meshes.new(name)
    mesh.from_pydata(verts, edges, faces)
    
    BiNormals = subMesh["BiNormals"]
    if BiNormals:
      # assign vertex normals
      vindex = 0
      for vertex in mesh.vertices:
        vertex.normal = BiNormals[vindex] # where "normals" is a list of normals
        vindex += 1
    
    Diffuse_UV = None
    Normals_UV = None
    
    if subMesh["Normals_UV"]:
      if subMesh["Diffuse_UV"]:
        Diffuse_UV = subMesh["Diffuse_UV"]
        Normals_UV = subMesh["Normals_UV"]
      else:
        Diffuse_UV = subMesh["Normals_UV"]
        Normals_UV = subMesh["Normals_UV"]

    material = bpy.data.materials.new(name)
    
    # assign material to the Mesh
    mesh.materials.append(material)
    
    if diffuseMap:
      image = bpy.data.images.load(diffuseMap)
      
      # save in blend
      image.pack(as_png = True)

      # create Texture which will use that image
      texture = bpy.data.textures.new(name, type = 'IMAGE')
      texture.image = image
      texture.use_alpha = True
      
      # assign textures to materials
      mtex = material.texture_slots.add()
      mtex.texture = texture
      mtex.texture_coords = 'UV'
      
    if Diffuse_UV:
      # http://blender.stackexchange.com/a/10444
      uvtex = mesh.uv_textures.new('Diffuse')
      uvlay = mesh.uv_layers[0]
      # https://blenderartists.org/forum/showthread.php?254004-Accessing-UV-data-in-Python-script&p=2115831&viewfull=1#post2115831
      for f in mesh.polygons:
        # f.index, f.loop_start, f.loop_total, f.loop_indices
        for i in f.loop_indices:
          loop = mesh.loops[i]
          uv = uvlay.data[loop.index].uv
          uvSrc = Diffuse_UV[loop.vertex_index]
          uv.x = uvSrc[0]
          uv.y = uvSrc[1]

    object = bpy.data.objects.new(name, mesh)
    bpy.context.scene.objects.link(object) # link object to scene
    
    # useful for development when the mesh may be invalid.
    # mesh.validate(verbose=True)

    modifier = object.modifiers.new(name, 'ARMATURE')
    modifier.object = skeleton["object"]
    object.parent = skeleton["object"]
  
    for boneIndex, bone in enumerate(skeleton["jsonBones"]):
      vertgroup = None

      for refIndex in range(0, len(verts)):
        bIndices = subMesh["Bone_Indices"][refIndex]
        bWeights = subMesh["Blend_Weights"][refIndex]
        for x in (0, 1, 2, 3):
          if bIndices[x] == boneIndex and bWeights[x] != 0.0:
            if vertgroup == None:
              vertgroup = object.vertex_groups.new(bone["name"])
            vertgroup.add([refIndex], bWeights[x], 'REPLACE')
  
  return {
    "object": object
  }

file = open(bundlesDirectory + skelJson, "r")
jsonData = json.load(file)
file.close
skeleton = importSkelton(jsonData)

importedObjects = []

for importTable in importTables:
  jsonMeshFile = os.path.join(bundlesDirectory, importTable["jsonMeshFile"])
  print("Importing %s" % (jsonMeshFile, ))
  file = open(jsonMeshFile, "r")
  jsonMesh = json.load(file)
  file.close
  
  diffuseMap = None
  if "diffuseMap" in importTable:
      diffuseMap = os.path.join(bundlesDirectory, importTable["diffuseMap"])
  
  importedMesh = importMesh(jsonMesh, skeleton, diffuseMap)
  importedObjects.append(importedMesh["object"])

for importedObject in importedObjects:
  importedObject.select = True

bpy.ops.group.create(name="Faith")
