# exports blender meshs to .antmesh files

import bpy
import bmesh
import struct
import mathutils
import os
import random
import datetime

f = None
buf_vertices = []
materials_dict = {}
out_materials = []

MatIdentity = mathutils.Matrix(([ 1, 0, 0, 0],
                                [ 0, 1, 0, 0],
                                [ 0, 0, 1, 0],
                                [ 0, 0, 0, 1]))
MatGL = mathutils.Matrix(([-1, 0, 0, 0],
                          [ 0, 0, 1, 0],
                          [ 0, 1, 0, 0],
                          [ 0, 0, 0, 1]))
InvMatGL = MatGL.inverted()

def log(*args, **kwargs):
    # Prints to python console, not the system console
    for a in bpy.context.screen.areas:
        if a.type == 'CONSOLE':
            c = {}
            c['area'] = a
            c['space_data'] = a.spaces.active
            c['region'] = a.regions[-1]
            c['window'] = bpy.context.window
            c['screen'] = bpy.context.screen
            s = " ".join([str(arg) for arg in args])
            for line in s.split("\n"):
                bpy.ops.console.scrollback_append(c, text=line)
                
def remember_pos(): return f.tell()
def save_uint8(val): f.write(struct.pack('<B', val))
def save_uint16(val): f.write(struct.pack('<H', val))
def save_uint32(val): f.write(struct.pack('<I', val))
def save_float(val): f.write(struct.pack('f', val))
def save_double(val): f.write(struct.pack('d', val))
def fix_uint32(pos, newval):
    whence_end = 2
    f.seek(pos)
    save_uint32(newval)
    f.seek(0, whence_end)

def save_string_raw(text):
    encoded_text = text.encode('utf-8')
    f.write(encoded_text)

def save_string(text):
    encoded_text = text.encode('utf-8')
    save_uint32(len(encoded_text))
    f.write(encoded_text)
    
def on_mesh(mesh):
    log('MESH ', mesh)
    buf_dict = {}
    buf_indices = []

    bm = bmesh.new()
    bm.from_mesh(mesh.data)
    bmesh.ops.triangulate(bm, faces=bm.faces[:])
    #log('Faces: ', len(bm.faces))
    for face in bm.faces:
        material_index = face.material_index
        #log("FACE with ", len(face.verts), " vertices")
        for vert in face.verts:
            pos = vert.co
            normal = vert.normal
            #log(material_index, pos.x, pos.y, pos.z, normal.x, normal.y, normal.z)
    triMesh = bpy.data.meshes.new(name = '~temp~')
    bm.to_mesh(triMesh)
    triMesh.calc_loop_triangles()
    bm.free()
    
    # uvs = triMesh.tessface_uv_textures
    try:
        uv_layer_0 = triMesh.uv_layers.values()[0]
        uv_layer_0_name = triMesh.uv_layers.keys()[0]
    except IndexError:
        uv_layer_0 = None
        uv_layer_0_name = ""
    for f in triMesh.loop_triangles:
        for index in range(3):
            vertex = triMesh.vertices[f.vertices[index]]
            i = f.loops[index]
            vc = vertex.co
            vn = vertex.normal
            if uv_layer_0:
                t0 = uv_layer_0.data[i].uv
            else:
                t0 = [0, 1.0]
            
            vp = ( vc.x, vc.y, vc.z,
                    vn.x, vn.y, vn.z,
                    t0[0], 1.0 - t0[1],
                    )
            index = buf_dict.setdefault(vp, len(buf_dict))
            buf_indices.append(index)
            
    bpy.data.meshes.remove(triMesh)

    save_uint32(len(buf_indices))
    save_uint32(len(buf_vertices))
    for index in buf_indices:
        save_uint16(index)
    for vertex in buf_vertices: # vertex coordinates
        save_float(vertex[0])
        save_float(vertex[1])
        save_float(vertex[2])
    for vertex in buf_vertices: # normals
        save_float(vertex[3])
        save_float(vertex[4])
        save_float(vertex[5])
    for vertex in buf_vertices: # texture coordinates
        save_float(vertex[6])
        save_float(vertex[7])
    
    #for key, value in mesh.items():
    #    if isinstance(value, str):
    #        log(key, ' = ', value)
    #    elif isinstance(value, int):
    #        log(key, ' = ', value)
    #        
    #for slot in mesh.material_slots:
    #    if slot.material:
    #        log(mesh.name, " HAS MATERIAL ", slot.material.name)
    
def on_light(light):
    log('Ignored LIGHT ', light)
    
def on_camera(camera):
    log('Ignore CAMERA ', obj)
    
def on_unknown_object(obj):
    log('Ignored ', obj.type, ' ', obj)

log('')
log('Exporting...')

pre, ext = os.path.splitext(bpy.data.filepath)

for obj in bpy.data.objects:
    if obj.type == 'MESH':
        filename = pre + '_' + obj.name + '.antmesh'
        f = open(filename, 'wb')
        save_string_raw('.antmesh')
        save_uint32(0)
        on_mesh(obj)
        f.close()      
        log('EXPOERTED ', filename)
    elif obj.type == 'LIGHT':
        on_light(obj)
    elif obj.type == 'CAMERA':
        on_camera(obj)
    else:
        on_unknown_object(obj)

log('DONE blender_ant')
