# -*- coding: utf-8 -*-

###########################################################################
# Glest Model / Texture / UV / Animation Importer and Exporter
# for the Game Glest that u can find http://www.glest.org
# copyright 2005 By Andreas Becker (seltsamuel@yahoo.de)
#
# 2011/05/25: v0.1 alpha1
# modified by William Zheng for Blender 2.57(loveheaven_zhengwei@hotmail.com)
#
# Started Date: 07 June 2005  Put Public 20 June 2005   
#  Distributed under the GNU PUBLIC LICENSE
#"""
#Here an explanation of the V4 Format found at www.glest.org
#================================
#1. DATA TYPES
#================================
#G3D files use the following data types:
#uint8: 8 bit unsigned integer
#uint16: 16 bit unsigned integer
#uint32: 32 bit unsigned integer
#float32: 32 bit floating point
#================================
#2. OVERALL STRUCTURE
#================================
#- File header
#- Model header
#- Mesh header
#- Texture names
#- Mesh data
#================================
#2. FILE HEADER
#================================
#Code:
#struct FileHeader{
#   uint8 id[3];
#   uint8 version;
#};
#This header is shared among all the versions of G3D, it identifies this file as a G3D model and provides information of the version.
#id: must be "G3D"
#version: must be 4, in binary (not '4')
#================================
#3. MODEL HEADER
#================================
#Code:
#struct ModelHeader{
#   uint16 meshCount;
#   uint8 type;
#};		   
#meshCount: number of meshes in this model
#type: must be 0
#================================
#4. MESH HEADER
#================================
#There is a mesh header for each mesh, there must be "meshCount" headers in a file but they are not consecutive, texture names and mesh data are stored in between.
#Code:
#struct MeshHeader{
#   uint8 name[64];
#   uint32 frameCount;
#   uint32 vertexCount;
#   uint32 indexCount;
#   float32 diffuseColor[3];
#   float32 specularColor[3];
#   float32 specularPower;
#   float32 opacity;
#   uint32 properties;
#   uint32 textures;
#};
#name: name of the mesh
#frameCount: number of keyframes in this mesh
#vertexCount: number of vertices in each frame
#indexCount: number of indices in this mesh (the number of triangles is indexCount/3)
#diffuseColor: RGB diffuse color
#specularColor: RGB specular color (currently unused)
#specularPower: specular power (currently unused)
##properties: property flags
#Code:
#enum MeshPropertyFlag{
#   mpfTwoSided= 1,
#		mpfCustomColor= 2,
#};
#mpfTwoSided: meshes in this mesh are rendered by both sides, if this flag is not present only "counter clockwise" faces are rendered
#mpfCustomColor: alpha in this model is replaced by a custom color, usually the player color
#textures: texture flags, only 0x1 is currently used, indicating that there is a diffuse texture in this mesh.
#================================
#4. TEXTURE NAMES
#================================
#A list of uint8[64] texture name values. One for each texture in the mesh. If there are no textures in the mesh no texture names are present. In practice since Glest only uses 1 texture for each mesh the number of texture names should be 0 or 1.
#================================
#5. MESH DATA
#================================
#After each mesh header and texture names the mesh data is placed.
#vertices: frameCount * vertexCount * 3, float32 values representing the x, y, z vertex coords for all frames
#normals: frameCount * vertexCount * 3, float32 values representing the x, y, z normal coords for all frames
#texture coords: vertexCount * 2, float32 values representing the s, t tex coords for all frames (only present if the mesh has 1 texture at least)
#indices: indexCount, uint32 values representing the indices
###########################################################################

bl_info = {
	"name": "G3D Mesh Import/Export",
	"author": "William Zheng (corrected by MrPostiga)",
	"version": (0, 1, 1),
	"blender": (2, 6, 0),
	"api": 36079,
	"location": "File > Import-Export",
	"description": "Import/Export .g3d file",
	"warning": "",
	"wiki_url": "",
	"tracker_url": "",
	"category": "Import-Export"}
###########################################################################
# Importing Structures needed (must later verify if i need them really all)
###########################################################################
import bpy
from bpy.props import StringProperty
from bpy_extras.image_utils import load_image
from bpy_extras.io_utils import ImportHelper, ExportHelper

import sys, struct, string, types
from types import *
import os
from os import path
from os.path import dirname
###########################################################################
# Variables that are better Global to handle
###########################################################################
imported = []   #List of all imported Objects
toexport = []   #List of Objects to export (actually only meshes)
sceneID  = None #Points to the active Blender Scene
def unpack_list(list_of_tuples):
	l = []
	for t in list_of_tuples:
		l.extend(t)
	return l
###########################################################################
# Declaring Structures of G3D Format
###########################################################################
class G3DHeader:							#Read first 4 Bytes of file should be G3D + Versionnumber
	binary_format = "<3cB"
	def __init__(self, fileID):
		temp = fileID.read(struct.calcsize(self.binary_format))
		data = struct.unpack(self.binary_format,temp)
		self.id = str(data[0]+data[1]+data[2], "utf-8")
		self.version = data[3]

class G3DModelHeaderv3:					 #Read Modelheader in V3 there is only the number of Meshes in file
	binary_format = "<I"
	def __init__(self, fileID):
		temp = fileID.read(struct.calcsize(self.binary_format))
		data = struct.unpack(self.binary_format,temp)
		self.meshcount = data[0]

class G3DModelHeaderv4:					 #Read Modelheader: Number of Meshes and Meshtype (must be 0)
	binary_format = "<HB"
	def __init__(self, fileID):
		temp = fileID.read(struct.calcsize(self.binary_format))
		data = struct.unpack(self.binary_format,temp)
		self.meshcount = data[0]
		self.mtype = data[1]
		
class G3DMeshHeaderv3:										 #Read Meshheader
	binary_format = "<7I64c"
	def __init__(self,fileID):
		temp = fileID.read(struct.calcsize(self.binary_format))
		data = struct.unpack(self.binary_format,temp)
		self.framecount = data[0]				 #Framecount = Number of Animationsteps
		self.normalframecount= data[1]		 #Number of Normal Frames actualli equal to Framecount
		self.texturecoordframecount= data[2]#Number of Frames of Texturecoordinates seems everytime to be 1
		self.colorframecount= data[3]		  #Number of Frames of Colors seems everytime to be 1
		self.vertexcount= data[4]				  #Number of Vertices in each Frame
		self.indexcount= data[5]					   #Number of Indices in Mesh (Triangles = Indexcount/3)
		self.properties= data[6]					   #Property flags
		if self.properties & 1:					  #PropertyBit is Mesh Textured ?
			self.hastexture = False
			self.texturefilename = None
		else:
			self.texturefilename = "".join([str(x, "ascii") for x in data[7:-1] if x[0]< 127 ])
			self.hastexture = True
		if self.properties & 2:					  #PropertyBit is Mesh TwoSided ?
			self.istwosided = True
		else:
			self.istwosided = False
		if self.properties & 4:					  #PropertyBit is Mesh Alpha Channel custom Color in Game ?
			self.customalpha = True
		else:
			self.customalpha = False
		
class G3DMeshHeaderv4:										 #Read Meshheader
	binary_format = "<64c3I8f2I"
	texname_format = "<64c"
	def __init__(self,fileID):
		temp = fileID.read(struct.calcsize(self.binary_format))
		data = struct.unpack(self.binary_format,temp)
		self.meshname = "".join([str(x, "ascii") for x in data[0:64] if x[0] < 127 ]) #Name of Mesh every Char is a  String on his own
		self.framecount = data[64]				#Framecount = Number of Animationsteps
		self.vertexcount = data[65]			   #Number of Vertices in each Frame
		self.indexcount = data[66]				#Number of Indices in Mesh (Triangles = Indexcount/3)
		self.diffusecolor = data[67:70]	   #RGB diffuse color
		self.specularcolor = data[70:73]	  #RGB specular color (unused)
		self.specularpower = data[73]		 #Specular power (unused)
		self.opacity = data[74]					   #Opacity
		self.properties= data[75]				  #Property flags
		self.textures = data[76]					  #Texture flag
		if self.properties & 1:					  #PropertyBit is Mesh TwoSided ?
			self.istwosided = True
		else:
			self.istwosided = False
		if self.properties & 2:					  #PropertyBit is Mesh Alpha Channel custom Color in Game ?
			self.customalpha = True
		else:
			self.customalpha = False
		if self.textures & 1:						#PropertyBit is Mesh Textured ?
			temp = fileID.read(struct.calcsize(self.texname_format))
			data = struct.unpack(self.texname_format,temp)
			self.texturefilename = "".join([str(x, "ascii") for x in data[0:-1] if x[0] < 127 ])
			self.hastexture = True
		else:
			self.hastexture = False
			self.texturefilename = None

class G3DMeshdataV3:											   #Calculate and read the Mesh Datapack
	def __init__(self,fileID,header):
		#Calculation of the Meshdatasize to load because its variable
		#Animationframes * Vertices per Animation * 3 (Each Point are 3 Float X Y Z Coordinates)
		vertex_format = "<%if" % int(header.framecount * header.vertexcount * 3)
		#The same for Normals
		normals_format = "<%if" % int(header.normalframecount * header.vertexcount * 3)
		#Same here but Textures are 2D so only 2 Floats needed for Position inside Texture Bitmap
		texturecoords_format = "<%if" % int(header.texturecoordframecount * header.vertexcount * 2)
		#Colors in format RGBA
		colors_format = "<%if" % int(header.colorframecount * 4)
		#Indices
		indices_format = "<%iI" % int(header.indexcount)
		#Load the Meshdata as calculated above
		self.vertices = struct.unpack(vertex_format,fileID.read(struct.calcsize(vertex_format)))
		self.normals = struct.unpack(normals_format,fileID.read(struct.calcsize(normals_format)))
		self.texturecoords = struct.unpack(texturecoords_format,fileID.read(struct.calcsize(texturecoords_format)))
		self.colors = struct.unpack(colors_format,fileID.read(struct.calcsize(colors_format)))
		self.indices = struct.unpack(indices_format ,fileID.read(struct.calcsize(indices_format)))

class G3DMeshdataV4:											   #Calculate and read the Mesh Datapack
	def __init__(self,fileID,header):
		#Calculation of the Meshdatasize to load because its variable
		#Animationframes * Points (Vertex) per Animation * 3 (Each Point are 3 Float X Y Z Coordinates)
		vertex_format = "<%if" % int(header.framecount * header.vertexcount * 3)
		#The same for Normals
		normals_format = "<%if" % int(header.framecount * header.vertexcount * 3)
		#Same here but Textures are 2D so only 2 Floats needed for Position inside Texture Bitmap
		texturecoords_format = "<%if" % int(header.vertexcount * 2)
		#Indices
		indices_format = "<%iI" % int(header.indexcount)
		#Load the Meshdata as calculated above
		self.vertices = struct.unpack(vertex_format,fileID.read(struct.calcsize(vertex_format)))
		self.normals = struct.unpack(normals_format,fileID.read(struct.calcsize(normals_format)))
		if header.hastexture:
			self.texturecoords = struct.unpack(texturecoords_format,fileID.read(struct.calcsize(texturecoords_format)))
		self.indices = struct.unpack(indices_format ,fileID.read(struct.calcsize(indices_format)))

def createMesh(filename,header,data):						  #Create a Mesh inside Blender
	mesh = bpy.data.meshes.new(header.meshname)		#New Mesh
	meshobj = bpy.data.objects.new(header.meshname+'Object', mesh)	 #New Object for the new Mesh
	scene = bpy.context.scene
	scene.objects.link(meshobj)
	scene.update()
	uvcoords = []
	image = None
	if header.hastexture:												  #Load Texture when assigned
		texturefile = dirname(filename)+os.sep+header.texturefilename
		image = bpy.data.images.load(texturefile) #load_image(texturefile, dirname(filename))
		for x in range(0,len(data.texturecoords),2): #Prepare the UV
			uvcoords.append([data.texturecoords[x],data.texturecoords[x+1]])
	
	vertsCO = []
	vertsNormal = []
	for x in range(0,header.vertexcount*3,3):	   #Get the Vertices and Normals into empty Mesh
		vertsCO.extend([(data.vertices[x],data.vertices[x+1],data.vertices[x+2])])
		vertsNormal.extend([(data.normals[x],data.normals[x+1],data.normals[x+2])])
		#vertsCO.extend([(data.vertices[x+(header.framecount-1)*header.vertexcount*3],data.vertices[x+(header.framecount-1)*header.vertexcount*3+1],data.vertices[x+(header.framecount-1)*header.vertexcount*3+2])])
		#vertsNormal.extend([(data.normals[x+(header.framecount-1)*header.vertexcount*3],data.normals[x+(header.framecount-1)*header.vertexcount*3+1],data.normals[x+(header.framecount-1)*header.vertexcount*3+2])])
	mesh.vertices.add(len(vertsCO))
	mesh.vertices.foreach_set("co", unpack_list(vertsCO))
	mesh.vertices.foreach_set("normal", unpack_list(vertsNormal))
	
	faces = []
	faceuv = []
	for i in range(0,len(data.indices),3):			  #Build Faces into Mesh
		faces.extend([data.indices[i], data.indices[i+1], data.indices[i+2], 0])
		if header.hastexture:	   
			uv = []
			u0 = uvcoords[data.indices[i]][0]
			v0 = uvcoords[data.indices[i]][1]
			uv.append([u0,v0])
			u1 = uvcoords[data.indices[i+1]][0]
			v1 = uvcoords[data.indices[i+1]][1]
			uv.append([u1,v1])
			u2 = uvcoords[data.indices[i+2]][0]
			v2 = uvcoords[data.indices[i+2]][1]
			uv.append([u2,v2])
			faceuv.append([uv,0,0,0])
		else:
			uv.append([0,0])
			uv.append([0,0])
			uv.append([0,0])
			faceuv.append([uv,0,0,0])
	mesh.faces.add(len(faces)//4)
	mesh.faces.foreach_set("vertices_raw", faces)
	mesh.faces.foreach_set("use_smooth", [True] * len(mesh.faces))
	mesh.update_tag()
	mesh.update()																   #Update changes to Mesh
	#===================================================================================================
#Material Setup
#===================================================================================================
	if header.hastexture:	   
		materialname = "pskmat"
		materials = []
		texture = bpy.data.textures.new(name=header.texturefilename,type='IMAGE')
		texture.image = image
		matdata = bpy.data.materials.new(materialname + '1')
		slot = matdata.texture_slots.add()
		slot.texture = texture
		slot.texture_coords = 'UV'
		if header.isv4:
			matdata.diffuse_color = (header.diffusecolor[0], header.diffusecolor[1],header.diffusecolor[2])
			matdata.alpha = header.opacity
			matdata.specular_color = (header.specularcolor[0], header.specularcolor[1],header.specularcolor[2])
		materials.append(matdata)

		for material in materials:
			#add material to the mesh list of materials
			mesh.materials.append(material)

		countm = 0
		psktexname="psk" + str(countm)
		mesh.uv_textures.new(name=psktexname)
		for countm in range(len(mesh.uv_textures)):
			mesh.update()
			uvtex = mesh.uv_textures[countm] #add one uv texture
			mesh.update()
			if (len(faceuv) > 0):
				counttex = 0
				countm = 0
				for countm in range(len(mesh.uv_textures)):
					mesh.update()
					psktexname="psk" + str(countm)
					uvtex = mesh.uv_textures[countm] #add one uv texture
					mesh.update()
					for i, face in enumerate(mesh.faces):
						blender_tface = uvtex.data[i] #face
						mfaceuv = faceuv[i]
						#face.material_index = faceuv[i][1]
						if countm == faceuv[i][1]:
							face.material_index = faceuv[i][1]
							blender_tface.uv1 = mfaceuv[0][0] #uv = (0,0)
							blender_tface.uv2 = mfaceuv[0][1] #uv = (0,0)
							blender_tface.uv3 = mfaceuv[0][2] #uv = (0,0)
							blender_tface.image = image
							#blender_tface.use_image = True
							#blender_tface.blend_type = 'ALPHA'
							#blender_tface.use_twoside = True
						else:
							blender_tface.uv1 = [0,0]
							blender_tface.uv2 = [0,0]
							blender_tface.uv3 = [0,0]
	mesh.update()
	imported.append(meshobj)						#Add to Imported Objects
	for x in range(header.framecount):					  #Put in Vertex Positions for Keyanimation
		print("Frame"+str(x))
		for i in range(0,header.vertexcount*3,3):
			print(str(i//3)+':\t'+str(data.vertices[x*header.vertexcount*3 + i])+'\t'+
				str(data.vertices[x*header.vertexcount*3 + i +1])+'\t'+
				str(data.vertices[x*header.vertexcount*3 + i +2]))
			mesh.vertices[i//3].co[0]= data.vertices[x*header.vertexcount*3 + i]
			mesh.vertices[i//3].co[1]= data.vertices[x*header.vertexcount*3 + i +1]
			mesh.vertices[i//3].co[2]= data.vertices[x*header.vertexcount*3 + i +2]
		meshobj.keyframe_insert("location",-1, frame=(x+1))
	mesh.update()
	return
###########################################################################
# Import
###########################################################################
def G3DLoader(filepath):			#Main Import Routine
	global imported, sceneID
	print ("\nNow Importing File: " + filepath)
	fileID = open(filepath,"rb")
	header = G3DHeader(fileID)
	print ("\nHeader ID         : " + header.id)
	print ("Version           : " + str(header.version))
	if header.id != "G3D":
		print ("This is Not a G3D Model File")
		fileID.close
		return
	if header.version not in (3, 4):
		print ("The Version of this G3D File is not Supported")
		fileID.close
		return
	#in_editmode = Blender.Window.EditMode()			 #Must leave Editmode when active
	#if in_editmode: Blender.Window.EditMode(0)
	sceneID = bpy.context.scene						  #Get active Scene
	#scenecontext=sceneID.getRenderingContext()		  #To Access the Start/Endframe its so hidden i searched till i got angry :-)
	basename=os.path.basename(filepath).split('.')[0]   #Generate the Base Filename without Path + extension
	imported = []
	maxframe=0
	if header.version == 3:
		modelheader = G3DModelHeaderv3(fileID)
		print ("Number of Meshes  : " + str(modelheader.meshcount))
		for x in range(modelheader.meshcount):
			meshheader = G3DMeshHeaderv3(fileID)
			meshheader.isv4 = False	
			print ("\nMesh Number         : " + str(x+1))
			print ("framecount            : " + str(meshheader.framecount))
			print ("normalframecount      : " + str(meshheader.normalframecount))
			print ("texturecoordframecount: " + str(meshheader.texturecoordframecount))
			print ("colorframecount       : " + str(meshheader.colorframecount))
			print ("pointcount            : " + str(meshheader.vertexcount))
			print ("indexcount            : " + str(meshheader.indexcount))
			print ("texturename           : " + str(meshheader.texturefilename))
			print ("hastexture            : " + str(meshheader.hastexture))
			print ("istwosided            : " + str(meshheader.istwosided))
			print ("customalpha           : " + str(meshheader.customalpha))
			meshheader.meshname = basename+str(x+1)	 #Generate Meshname because V3 has none
			if meshheader.framecount > maxframe: maxframe = meshheader.framecount #Evaluate the maximal animationsteps
			meshdata = G3DMeshdataV3(fileID,meshheader)
			createMesh(filepath,meshheader,meshdata)
		fileID.close
		bpy.context.scene.frame_start=1
		bpy.context.scene.frame_end=maxframe
		bpy.context.scene.frame_current=1
		anchor = bpy.data.objects.new('Empty', None)
		anchor.select = True
		bpy.context.scene.objects.link(anchor)
		for ob in imported:
				ob.parent = anchor
		bpy.context.scene.update()
		return
	if header.version == 4:
		modelheader = G3DModelHeaderv4(fileID)
		print ("Number of Meshes  : " + str(modelheader.meshcount))
		for x in range(modelheader.meshcount):
			meshheader = G3DMeshHeaderv4(fileID)
			meshheader.isv4 = True	  
			print ("\nMesh Number   : " + str(x+1))
			print ("meshname        : " + str(meshheader.meshname))
			print ("framecount      : " + str(meshheader.framecount))
			print ("vertexcount     : " + str(meshheader.vertexcount))
			print ("indexcount      : " + str(meshheader.indexcount))
			print ("diffusecolor    : %1.6f %1.6f %1.6f" %meshheader.diffusecolor)
			print ("specularcolor   : %1.6f %1.6f %1.6f" %meshheader.specularcolor)
			print ("specularpower   : %1.6f" %meshheader.specularpower)
			print ("opacity         : %1.6f" %meshheader.opacity)
			print ("properties      : " + str(meshheader.properties))
			print ("textures        : " + str(meshheader.textures))
			print ("texturename     : " + str(meshheader.texturefilename))
			if len(meshheader.meshname) ==0:	#When no Meshname in File Generate one
					meshheader.meshname = basename+str(x+1)
			if meshheader.framecount > maxframe: maxframe = meshheader.framecount #Evaluate the maximal animationsteps
			meshdata = G3DMeshdataV4(fileID,meshheader)
			createMesh(filepath,meshheader,meshdata)
		fileID.close
		
		bpy.context.scene.frame_start=1
		bpy.context.scene.frame_end=maxframe
		bpy.context.scene.frame_current=1
		anchor = bpy.data.objects.new('Empty', None)
		anchor.select = True
		bpy.context.scene.objects.link(anchor)
		for ob in imported:
				ob.parent = anchor
		bpy.context.scene.update()
		print ("Created a empty Object as 'Grip' where all imported Objects are parented to")
		print ("To move the complete Meshes only select this empty Object and move it")
		print ("All Done, have a good Day :-)\n\n")
		return

def G3DSaver(filepath, context):
	print ("\nNow Exporting File: " + filepath)
	fileID = open(filepath,"wb")

	# G3DHeader v4
	fileID.write(struct.pack("<3cB", b'G', b'3', b'D', 4))
	#get real meshcount as len(bpy.data.meshes) holds also old meshes
	meshCount = 0
	for obj in bpy.data.objects:#context.selected_objects:
		if obj.type == 'MESH':
			meshCount += 1
	# G3DModelHeaderv4
	fileID.write(struct.pack("<HB", meshCount, 0))
	# meshes
	#for mesh in bpy.data.meshes:
	for obj in bpy.data.objects:#context.selected_objects:
		if obj.type != 'MESH':
			continue
		mesh = obj.data
		diffuseColor = [1.0, 1.0, 1.0]
		specularColor = [0.9, 0.9, 0.9]
		opacity = 1.0
		textures = 0
		if len(mesh.materials) > 0:
			# we have a texture, hopefully
			material = mesh.materials[0]
			if material.active_texture.type == 'IMAGE':
				diffuseColor = material.diffuse_color
				specularColor = material.specular_color
				opacity = material.alpha
				textures = 1
				texname = bpy.path.basename(material.active_texture.image.filepath)
			else:
				#FIXME: needs warning in gui
				print("active texture in first material isn't of type IMAGE")

		meshname = mesh.name
		frameCount = context.scene.frame_end - context.scene.frame_start +1
		#Real face count (only use triangle)
		realFaceCount = 0
		indices=[]
		newverts=[]
		if textures == 1:
			uvtex = mesh.uv_textures[0]
			uvlist = []
			uvlist[:] = [[0]*2 for i in range(len(mesh.vertices))]
			s = set()
			for face in mesh.faces:
				faceindices = [] # we create new faces when duplicating vertices
				realFaceCount += 1
				uvdata = uvtex.data[face.index]
				for i in range(3):
					vindex = face.vertices[i]
					if vindex not in s:
						s.add(vindex)
						uvlist[vindex] = uvdata.uv[i]
					elif uvlist[vindex] != uvdata.uv[i]:
						# duplicate vertex because it takes part in different faces
						# with different texcoords
						newverts.append(vindex)
						uvlist.append(uvdata.uv[i])
						#FIXME: probably better with some counter
						vindex = len(mesh.vertices) + len(newverts) -1

					faceindices.append(vindex)
				indices.extend(faceindices)

				#FIXME: stupid copy&paste
				if len(face.vertices) == 4:
					faceindices = []
					realFaceCount += 1
					for i in [0,2,3]:
						vindex = face.vertices[i]
						if vindex not in s:
							s.add(vindex)
							uvlist[vindex] = uvdata.uv[i]
						elif uvlist[vindex] != uvdata.uv[i]:
							# duplicate vertex because it takes part in different faces
							# with different texcoords
							newverts.append(vindex)
							uvlist.append(uvdata.uv[i])
							#FIXME: probably better with some counter
							vindex = len(mesh.vertices) + len(newverts) -1

						faceindices.append(vindex)
					indices.extend(faceindices)
		else:
			for face in mesh.faces:
				realFaceCount += 1
				indices.extend(face.vertices[0:3])
				if len(face.vertices) == 4:
					realFaceCount += 1
					# new face because quad got split
					indices.append(face.vertices[0])
					indices.append(face.vertices[2])
					indices.append(face.vertices[3])


		#FIXME: abort when no triangles as it crashs g3dviewer
		if realFaceCount == 0:
			print("no triangles found")
		indexCount = realFaceCount * 3
		vertexCount = len(mesh.vertices) + len(newverts)
		specularPower = 9.999999  # unused, same as old exporter
		properties = 0
		if mesh.show_double_sided:
			properties |= 1
		if textures==1 and mesh.materials[0].use_face_texture_alpha:
			properties |= 2

		#MeshData
		vertices = []
		normals = []
		fcurrent = context.scene.frame_current
		for i in range(context.scene.frame_start, context.scene.frame_end+1):
			context.scene.frame_set(i)
			#FIXME: this is hacky
			if obj.find_armature() == None:
				m = mesh.copy()
				m.transform(obj.matrix_world)
			else:
				#FIXME: not sure what's better: PREVIEW or RENDER settings
				m = obj.to_mesh(context.scene, True, 'RENDER')
			for vertex in m.vertices:
				vertices.extend(vertex.co)
				normals.extend(vertex.normal)
			for nv in newverts:
				vertices.extend(m.vertices[nv].co)
				normals.extend(m.vertices[nv].normal)
		context.scene.frame_set(fcurrent)

		# MeshHeader
		fileID.write(struct.pack("<64s3I8f2I",
			bytes(meshname, "ascii"),
			frameCount, vertexCount, indexCount,
			diffuseColor[0], diffuseColor[1], diffuseColor[2],
			specularColor[0], specularColor[1], specularColor[2],
			specularPower, opacity,
			properties, textures
		))
		#Texture names
		if textures == 1: # only when we have one
			fileID.write(struct.pack("<64s", bytes(texname, "ascii")))

		# see G3DMeshdataV4
		vertex_format = "<%if" % int(frameCount * vertexCount * 3)
		normals_format = "<%if" % int(frameCount * vertexCount * 3)
		texturecoords_format = "<%if" % int(vertexCount * 2)
		indices_format = "<%iI" % int(indexCount)

		fileID.write(struct.pack(vertex_format, *vertices))
		fileID.write(struct.pack(normals_format, *normals))

		# texcoords
		if textures == 1: # only when we have one
			texcoords = []
			for uv in uvlist:
				texcoords.extend(uv)
			fileID.write(struct.pack(texturecoords_format, *texcoords))

		fileID.write(struct.pack(indices_format, *indices))

	fileID.close()
	return


#---=== Register ===
class ImportG3D(bpy.types.Operator, ImportHelper):
	'''Load a G3D file'''
	bl_idname = "importg3d.g3d"
	bl_label = "Import G3D"

	filename_ext = ".g3d"
	filter_glob = StringProperty(default="*.g3d", options={'HIDDEN'})

	def execute(self, context):
		try:
			G3DLoader(**self.as_keywords(ignore=("filter_glob",)))
		except:
			import traceback
			traceback.print_exc()

			return {'CANCELLED'}

		return {'FINISHED'}

class ExportG3D(bpy.types.Operator, ExportHelper):
	'''Save a G3D file'''
	bl_idname = "exportg3d.g3d"
	bl_label = "Export G3D"

	filename_ext = ".g3d"
	filter_glob = StringProperty(default="*.g3d", options={'HIDDEN'})

	def execute(self, context):
		try:
			G3DSaver(self.filepath, context)
		except:
			import traceback
			traceback.print_exc()

			return {'CANCELLED'}

		return {'FINISHED'}

def menu_func_import(self, context):
	self.layout.operator(ImportG3D.bl_idname, text="Glest 3D File (.g3d)")

def menu_func_export(self, context):
	self.layout.operator(ExportG3D.bl_idname, text="Glest 3D File (.g3d)")

def register():
	bpy.utils.register_module(__name__)

	bpy.types.INFO_MT_file_import.append(menu_func_import)
	bpy.types.INFO_MT_file_export.append(menu_func_export)


def unregister():
	bpy.utils.unregister_module(__name__)

	bpy.types.INFO_MT_file_import.remove(menu_func_import)
	bpy.types.INFO_MT_file_export.remove(menu_func_export)

if __name__ == '__main__':
	register()

