'''
PMDL Export Blender Addon
By Jack Andersen <jackoalan@gmail.com>

This file defines the main `pmdl` class used to generate PMDL file instances.
The class is initialised with a MESH or ARMATURE object (ARMATUREs generate `PAR1`).

The provided MESH or ARMATURE may hierarcically contain other MESH objects, 
resulting in an appropriately sub-divided PMDL. The MATERIAL name assigned to
MESH objects is hashed with SHA1 and used to reference a PSPLC implementing 
the appropriate shader.

Once the object is assigned, the appropriate draw-generator is initialised
(with optional indexing parameters set) and loaded into the PMDL instance. 

The actual PMDL generation may then happen with these objects gathered together.
'''

from . import pmdl_par2_octree
from . import pmdl_par1_rigging

import struct
import bpy
import hashlib
import posixpath

# Lookup PSPL material of MESH object
def lookup_pspl_material(mesh_obj):
    cur_mesh = mesh_obj

    while cur_mesh is not None:
        
        if cur_mesh.pspl_material:
            base_name = posixpath.splitext(os.path.basename(bpy.data.filepath))[0]
            mesh_name = string.replace(mesh_obj.name, "/", "_")
            mesh_name = string.replace(mesh_name, "\\", "_")
            material_name = string.replace(cur_mesh.pspl_material, "/", "_")
            material_name = string.replace(material_name, "\\", "_")
            shader_name = posixpath.normpath(os.path.dirname(bpy.data.filepath) + "/" + base_name + ".psplblend/" + mesh_name + "/" + material_name + ".pspl")
            return shader_name
        
        cur_mesh = cur_mesh.parent

    return None


def add_vec3(a,b):
    return (a[0]+b[0],a[1]+b[1],a[2]+b[2])

# Round up to nearest 32 multiple
def ROUND_UP_32(num):
    if num%32:
        return ((num>>5)<<5)+32
    else:
        return num
        

class pmdl:
    
    # Expand master bounding box to fit added mesh object
    def _accumulate_bound_box(self, obj):
    
        min_box = obj.bound_box[0]
        max_box = obj.bound_box[6]
        if not self.bound_box_accounted:
            self.bound_box_accounted = True
            for i in range(3):
                self.bound_box_min[i] = min_box[i]
                self.bound_box_max[i] = max_box[i]
        else:
            for i in range(3):
                if self.bound_box_min[i] > min_box[i]:
                    self.bound_box_min[i] = min_box[i]
                if self.bound_box_max[i] < max_box[i]:
                    self.bound_box_max[i] = max_box[i]

    
    # Recursive routine to add all MESH objects as individual PMDL collections
    def _recursive_add_mesh(self, draw_gen, object, root_rel_loc, rigger):
        
        # Start with root object (make sure it's a MESH)
        if object.type == 'MESH':
            
            # Only add if there is at least *one* polygon in mesh
            if len(object.data.polygons):
                
                # Copy mesh
                copy_name = object.name + "_pmdltri"
                copy_mesh = bpy.data.meshes.new(copy_name)
                copy_obj = bpy.data.objects.new(copy_name, copy_mesh)
                copy_obj.data = object.to_mesh(bpy.context.scene, True, 'RENDER')
                copy_obj.scale = object.scale
                copy_obj.location = root_rel_loc # This is set to be root-object-relative
                bpy.context.scene.objects.link(copy_obj)
                
                # If rigging, set original mesh's vertex groups as context
                if rigger:
                    rigger.mesh_vertex_groups = object.vertex_groups
                
                # Triangulate mesh
                bpy.context.scene.objects.active = copy_obj
                bpy.ops.object.mode_set(mode='EDIT')
                bpy.ops.mesh.select_all(action='SELECT')
                bpy.ops.mesh.quads_convert_to_tris()
                bpy.ops.object.mode_set(mode='OBJECT')
                
                # Set mesh's coordinates to be root-relative
                for vert in copy_mesh.vertices: