#!BPY
""" Registration info for Blender menus:
Name: 'Poser (.cr2)...'
Blender: 243
Group: 'Import'
ToolTip: 'Import Poser CR2 files'
"""
__author__ = "Damir Prebeg"
__url__ = ["http://blendfactory.phpnet.us/"]
__email__ = ["blend"+chr(46)+"factory"+chr(64)+"gmail"+chr(46)+"com","damir_prebeg"+chr(64)+"yahoo.com"]
__version__ = "0.1"
__bpydoc__ = """\

CR2 Importer by Damir Prebeg\n
Copyright (c) Damir Prebeg, blendfactory.phpnet.us\n
This script will import armature and referenced obj model from Poser CR2 file.\n
Usage:\n
Launch this script and navigate to Posers Runtime folders. Under Libraries\Character sub folders find and select your CR2. If obj model is correctly referenced, it will be imported as well. Otherwise, script will import only armature from selected cr2. If that happens, launch this script again, find and import a proper obj file. After that, manually add Armature modifier to imported mesh\n
TODO:\n
For Armature: Constraints, Stride Root... For Obj: Materials(currently skipped due of Blender limitations of 16 mats/obj), Vertex Weights, Shape Keys and IPO drivers calculated from CR2 matSpheres, Joints, Twists...

"""

# ***** BEGIN GPL LICENSE BLOCK *****
#
# Script copyright (C) Damir Prebeg 
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****

import Blender, time, BPyMesh

def browse_cr2():
	Blender.Window.FileSelector(launch_import, 'Import', '*.cr2|*.obj')

def launch_import(filepath):
	if Blender.sys.exists(filepath):
		ext = filepath.split('.')[-1].upper()
		print ext
		if ext == "CR2":
			t1 = time.clock()
			Blender.Window.WaitCursor(1)
			imported = do_import_bones(filepath)
			Blender.Window.Redraw()
			Blender.Window.WaitCursor(0)
			if imported:
				print 'CR2 Imported in ' + str(time.clock()-t1) + ' seconds'
			else:
				Blender.Draw.PupMenu('Nothing to import%t|OK')
		elif ext == "OBJ":
			t1 = time.clock()
			Blender.Window.WaitCursor(1)
			imported = do_import_obj(filepath)
			Blender.Window.Redraw()
			Blender.Window.WaitCursor(0)
			if imported:
				print 'OBJ Imported in ' + str(time.clock()-t1) + ' seconds'
			else:
				Blender.Draw.PupMenu('Nothing to import%t|OK')
		else:
			Blender.Draw.PupMenu('Wrong file extension%t|OK')

def figureResToPath(filepath, figureResFile):

	path = figureResFile.strip('"')

	if Blender.sys.exists(path): #if figureResFile string is absolute path
		return path
	else: #figureResFile string is in poser format :dir:dir:dir:name.obj
		path = []
		cr2Tree = filepath.split('\\')
		figResTree = figureResFile.lstrip(':').split(':')
		for element in cr2Tree:
			if element in figResTree:
				for element in figResTree:
					path.append(element)
				path = "\\".join(path)
				if Blender.sys.exists(path):
					return path
			path.append(element)

		return False

def do_import_bones(filepath):

	Vector = Blender.Mathutils.Vector
	Editbone = Blender.Armature.Editbone
	strjoin = str.join

	actor_list = {}
	active_actor = ''
	block_level = 0
	objImported = False	
	objName = ''
	
	cr2_name = filepath.split('\\')[-1].split('/')[-1].split('.')[0]	
	
	cr2file = open(filepath, 'r')

	for line in cr2file:

		words = line.split()

		if len(words) == 0 or words[0].startswith('#'):
			continue

		elif words[0] == '{':
			block_level +=1 #for future use
			continue

		elif words[0] == '}':
			block_level -=1 #for future use
			continue

		elif words[0] == 'figureResFile' and len(words)>1:
			if not objImported:
				figurePath = figureResToPath(filepath, " ".join(words[1:]))
				if figurePath:
					objName = do_import_obj(figurePath)
					if objName:
						objImported = True
					else:
						objImported = False
				else:
					objImported = False

		elif words[0] == 'actor' and len(words) > 1:
			active_actor = strjoin(' ', words[1:]).split(':')[0]
			actor_list[active_actor]={}
			continue

		elif words[0] == 'on': #include only visible bones
			if actor_list.has_key(active_actor):
				if not actor_list[active_actor].has_key('visible'):
					actor_list[active_actor]['visible'] = True
			continue

		elif words[0] == 'off': #skip invisible bones
			if actor_list.has_key(active_actor):
				if not actor_list[active_actor].has_key('visible'):
					actor_list[active_actor]['visible'] = False
			continue

		elif words[0] == 'parent' and active_actor:
			if actor_list.has_key(active_actor):
				if not actor_list[active_actor].has_key('parent'):
					actor_list[active_actor]['parent'] = strjoin(' ', words[1:]).split(':')[0]
			continue
		
		elif words[0] == 'nonInkyParent' and active_actor: #For now use this only to fix parenting
			if actor_list.has_key(active_actor):
				if not actor_list[active_actor].has_key('parent'):
					actor_list[active_actor]['parent'] = strjoin(' ', words[1:]).split(':')[0]
				else:
					nonInkyParent = strjoin(' ', words[1:]).split(':')[0]
					if actor_list[active_actor]['parent'] != nonInkyParent:
						actor_list[active_actor]['parent'] = nonInkyParent
			continue

		elif words[0] == 'endPoint' and active_actor:
			if actor_list.has_key(active_actor):
				#ZFlipped
				if not actor_list[active_actor].has_key('endPoint'):
					actor_list[active_actor]['endPoint'] = (float(words[1])*10,float(words[3])*-10,float(words[2])*10)
			continue

		elif words[0] == 'origin' and active_actor:
			if actor_list.has_key(active_actor):
				#ZFlipped
				if not actor_list[active_actor].has_key('origin'):
					actor_list[active_actor]['origin'] = (float(words[1])*10,float(words[3])*-10,float(words[2])*10)
			continue

	cr2file.close()

	for actor_name, actor_data in actor_list.iteritems():
		if not actor_data.has_key('endPoint') or not actor_data.has_key('origin'):
			actor_list.pop(actor_name)

	if not actor_list:
		return False

	arm = Blender.Armature.New(cr2_name)

	arm.makeEditable()

	for actor_name, actor_data in actor_list.iteritems():
		if actor_data['visible']:
			new_bone = Editbone()
			new_bone.tail = Vector(actor_data['endPoint'])
			new_bone.head = Vector(actor_data['origin'])
			new_bone.name = actor_name
			arm.bones[actor_name] = new_bone
	
	arm.envelopes = False #set envelopes to false
	
	objArmature = Blender.Object.New('Armature', cr2_name)
	objArmature.link(arm)
	
	objArmature.xRay = 1 #set x-ray to true

	for actor_name, actor_data in actor_list.iteritems():
		if actor_name in arm.bones.keys():
			if actor_data.has_key('parent'):
				if actor_data['parent'] in arm.bones.keys():
					arm.bones[actor_name].parent = arm.bones[actor_data['parent']]

	arm.update()

	scn = Blender.Scene.GetCurrent()

	for ob in scn.objects:
		ob.sel = 0
	
	objArmature.layers = scn.layers
	
	scn.objects.link(objArmature)
	
	if objName:
		ob = Blender.Object.Get(objName)
		obMods = ob.modifiers
		armMod=obMods.append(Blender.Modifier.Types.ARMATURE)
		armMod[Blender.Modifier.Settings.OBJECT] = objArmature
		armMod[Blender.Modifier.Settings.ENVELOPES] = 0
		armMod[Blender.Modifier.Settings.RENDER] = 1
		armMod[Blender.Modifier.Settings.REALTIME] = 1
		armMod[Blender.Modifier.Settings.EDITMODE] = 1	
		ob.makeDisplayList()
	
	scn.update()
	
	objArmature.sel = 1
	
	return True

def prep_import_obj(filepath): #Prepare for import (for some future use)
	if do_import_obj(filepath):
		return True
	else:
		return False

def do_import_obj(filepath): #Obj Importer

	Vector = Blender.Mathutils.Vector

	vertList = [] #List to store vertices
	vertappend = vertList.append
	faceList = [] #List to store faces
	faceappend = faceList.append
	uvList = [] #List to store UVs
	uvListAppend = uvList.append
	faceUvList = [] #List
	faceUvListAppend = faceUvList.append

	vertGroupDict = {} #Dict to store vert groups
	activGrp = ''

	name = filepath.split('\\')[-1].split('/')[-1].split('.')[0] #Name of a mesh

	objFile = open(filepath)

	for line in objFile:

		words = line.split()

		if len(words) is 0 or words[0].startswith('#'): #Skip comments and blank lines
			continue

		elif words[0] == 'g' and len(words)>1: #Collect groups
			activGrp = words[1]
			if not activGrp in vertGroupDict.iterkeys():
				vertGroupDict[activGrp] = []
			continue

		elif words[0] == 'v' and len(words)>1: #Collect vertices
			vertappend((float(words[1])*10,float(words[3])*-10,float(words[2])*10))
			continue

		elif words[0] == 'vt' and len(words)>1: #Collect vertices
			uvListAppend((float(words[1]),float(words[2])))
			continue

		elif words[0] == 'f' and len(words)>1: #Collect faces
			face = []
			uv = []
			for faceVert in words[1:len(words)]:
				IDS = faceVert.split('/')
				vertID = int(IDS[0])-1
				if len(IDS) > 1:
					uvID = int(IDS[1])-1
				face.append(vertID)

				if uvList:
					uv.append(uvList[uvID])

				if activGrp:
					vertGroupDict[activGrp].append(vertID)

			if len(face) < 5:
				faceappend(face)
				if uv:
					faceUvListAppend(uv)
			else:
				triList = BPyMesh.ngon(vertList, face)
				for tri in triList:
					faceappend([face[n] for n in tri])
					if uv:
						faceUvListAppend([uv[n] for n in tri])

	objFile.close()

	if not vertList: #Exit if there is no verts
		return False

	if Blender.Window.EditMode():
		Blender.Window.EditMode(0)

	importedMesh = Blender.Mesh.New(name) #Create a new mesh

	importedMesh.verts.extend(vertList) #Append imported vertices to the mesh

	if faceList:
		importedMesh.faces.extend(faceList) #Append imported faces to the mesh
		if faceUvList:
			for faceCount in range(len(importedMesh.faces)):
				importedMesh.faces[faceCount].uv = map(Vector,faceUvList[faceCount])

	objMesh = Blender.Object.New('Mesh', name) #Create new object

	objMesh.link(importedMesh)

	if vertGroupDict:
		for grupName in vertGroupDict.iterkeys():
			importedMesh.addVertGroup(grupName)
			importedMesh.assignVertsToGroup(grupName,vertGroupDict[grupName],1.00,Blender.Mesh.AssignModes.REPLACE)

	scn = Blender.Scene.GetCurrent() # Get current scene

	for ob in scn.objects:
		ob.sel = 0 #Deselect all objects in scene

	scn.objects.link(objMesh) #Put object in to scene

	for face in importedMesh.faces:
		face.smooth = True

	importedMesh.calcNormals()

	objMesh.layers = scn.layers #Show object in active layers
	
	return name

browse_cr2()