#!BPY

"""
Name: 'Nendo (.ndo)...'
Blender: 232
Group: 'Export'
Tooltip: 'Export selected mesh to Nendo File Format (*.ndo)'
"""

__author__ = "Anthony D'Agostino (Scorpius)"
__url__ = ("blender", "elysiun",
"Author's homepage, http://www.redrival.com/scorpius")
__version__ = "Part of IOSuite 0.5"

__bpydoc__ = """\
This script exports meshes to Nendo file format.

Nendo is (was) a commercial polygon modeler that has about half of the
features found in Wings. The .ndo file format is a simple, uncompressed,
memory dump of structures that represent the mesh objects, uv coords,
and image textures.

Usage:<br>
	Select meshes to be exported and run this script from "File->Export" menu.

Supported:<br>
	1. Exports meshes only. Hint: use ALT-C to convert non-mesh objects,
and CTRL-ALT-A if you have "dupliverts" objects.<br>
	2. Exports Vertex Colors & Radiosity Solutions.

Missing:<br>
	Materials and UV Coordinates info will be ignored.

Known issues:<br>
	Exports only well-behaved and topologically correct meshes (i.e,
closed meshes, manifolds, meshes imported from wings, etc). The mesh
cannot have duplicate vertices, missing faces (holes), open edges, etc.<br>
	PowerUser Hint: In editmode, if CTRL-ALT-SHIFT-M results in a selection,
then your mesh is not a manifold and most likely will not export.

Notes:<br>
	Blender & Wings can read/write ndo files with a maximum of 65,535 edges.
Nendo can read/write ndo files with a maximum of 32,767 edges.<br>
	If you have a very large mesh that you want to import into nendo, modify
the 'write_edge_table' function to use a signed integer (i.e., ">h") for the 'len(edge_table)'
field.
"""

# $Id: nendo_export.py,v 1.7 2005/12/19 17:21:55 ianwill Exp $
#
# +---------------------------------------------------------+
# | Copyright (c) 2001 Anthony D'Agostino                   |
# | http://www.redrival.com/scorpius                        |
# | scorpius@netzero.com                                    |
# | September 25, 2001                                      |
# | Read and write Nendo File Format (*.nendo)              |
# +---------------------------------------------------------+

# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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, meshtools
import struct, time, sys, os

# ==============================
# === Write Nendo 1.1 Format ===
# ==============================
def write(filename):
	start = time.clock()

	objects = Blender.Object.GetSelected()
	objname = objects[0].name
	meshname = objects[0].data.name
	mesh = Blender.NMesh.GetRaw(meshname)
	obj = Blender.Object.Get(objname)

	numedges = len(mesh.verts)+len(mesh.faces)-2
	maxedges = (2**16)-1	# Blender & Wings can read more edges
	#maxedges = 32767		# Nendo can't
	if numedges > maxedges:
		message = objname + " can't be exported to Nendo format (too many edges)."
		Blender.Draw.PupMenu("Nendo Export Error%t|"+message)
		return

	edge_table = meshtools.generate_edgetable(mesh)

	try:
		edge_table = meshtools.generate_edgetable(mesh)
		assert len(edge_table) <= maxedges
	except:
		edge_table = {}
		message = "Unable to generate Edge Table for the object named " + meshname
		meshtools.print_boxed(message)
		Blender.Draw.PupMenu("Edge Table Error%t|"+message)
		Blender.Window.DrawProgressBar(1.0, "")    # clear progressbar
		return

	file = open(filename, "wb")
	write_header(file)
	write_object_flags(file, objname)
	write_edge_table(file, edge_table)
	write_face_table(file, edge_table)
	write_vert_table(file, edge_table, mesh)
	write_texture(file)
	file.close()

	Blender.Window.DrawProgressBar(1.0, "")    # clear progressbar
	print '\a\r',
	end = time.clock()
	seconds = " in %.2f %s" % (end-start, "seconds")
	message = "Successfully exported " + os.path.basename(filename) + seconds
	meshtools.print_boxed(message)

# ====================
# === Write Header ===
# ====================
def write_header(file):
	file.write("nendo 1.1")
	file.write("\0\0")
	file.write("\1") # numobjects

# ==========================
# === Write Object Flags ===
# ==========================
def write_object_flags(file, objname):
	file.write("\1") # good flag
	file.write(struct.pack(">H", len(objname)))
	file.write(objname)
	file.write("\1"*4)
	data = struct.pack(">18f",0,0,0,1,1,1,1,1,1,1,1,1,0.2,0.2,0.2,1,100,1)
	data = "<<<< Nendo Export Script for Blender -- (c) 2004 Anthony D'Agostino >>>>"
	file.write(data)

# ========================
# === Write Edge Table ===
# ========================
def write_edge_table(file, edge_table):
	"+--------------------------------------+"
	"| Wings: Sv Ev | Lf Rf | Lp Ls | Rp Rs |"
	"| Nendo: Ev Sv | Lf Rf | Ls Rs | Rp Lp |"
	"+--------------------------------------+"
	#$print "edge_table"; pprint.pprint(edge_table)
	file.write(struct.pack(">H", len(edge_table)))
	keys = edge_table.keys()
	keys.sort()
	for key in keys:
		file.write(struct.pack(">2H", key[0], key[1]))                          # Ev Sv
		file.write(struct.pack(">2H", edge_table[key][0], edge_table[key][1]))  # Lf Rf
		file.write(struct.pack(">2H", edge_table[key][3], edge_table[key][5]))  # Ls Rs
		file.write(struct.pack(">2H", edge_table[key][4], edge_table[key][2]))  # Rp Lp
		file.write(struct.pack(">1B", 0))                                       # Hard flag
		try:
			r1,g1,b1 = map(lambda x:x*255, edge_table[key][8])
			r2,g2,b2 = map(lambda x:x*255, edge_table[key][7])
		except:
			r1,g1,b1 = map(lambda x:x*255, [0.9,0.8,0.7])
			r2,g2,b2 = r1,g1,b1
		file.write(struct.pack(">8B", r1,g1,b1,0,r2,g2,b2,0))

# ========================
# === Write Face Table ===
# ========================
def write_face_table(file, edge_table):
	face_table = build_face_table(edge_table)
	#$print "face_table"; pprint.pprint(face_table)
	file.write(struct.pack(">H", len(face_table)))
	keys = face_table.keys()
	keys.sort()
	for key in keys:
		file.write(struct.pack(">1H", face_table[key]))

# ========================
# === Write Vert Table ===
# ========================
def write_vert_table(file, edge_table, mesh):
	vert_table = build_vert_table(edge_table)
	#$print "vert_table"; pprint.pprint(vert_table)
	file.write(struct.pack(">H", len(vert_table)))
	keys = vert_table.keys()
	keys.sort()
	for key in keys:
		vertex = mesh.verts[key].co
		x,y,z = map(lambda x:x*10, vertex) # scale
		idx = vert_table[key]
		#$print "%i % f % f % f" % (idx, x, y, z)
		file.write(struct.pack(">1H3f", idx, x, z, -y))

# =====================
# === Write Texture ===
# =====================
def write_texture(file):
	file.write("\0"*5)

# ========================
# === Build Vert Table ===
# ========================
def build_vert_table(edge_table): # For Nendo
	vert_table = {}
	for key in edge_table.keys():
		i = edge_table[key][6]
		Sv = key[0]
		Ev = key[1]
		vert_table[Sv] = i
		vert_table[Ev] = i
	return vert_table

# ========================
# === Build Face Table ===
# ========================
def build_face_table(edge_table): # For Nendo
	face_table = {}
	for key in edge_table.keys():
		i = edge_table[key][6]
		Lf = edge_table[key][0]
		Rf = edge_table[key][1]
		face_table[Lf] = i
		face_table[Rf] = i
	return face_table

def fs_callback(filename):
	if filename.find('.ndo', -4) <= 0: filename += '.ndo'
	write(filename)

Blender.Window.FileSelector(fs_callback, "Export Nendo")
