#!BPY
""" 
Name: 'OpenGL-Code (.h)...'
Blender: '248'
Group: 'System'
Tooltip: 'Export C++-OpenGL-Code (.h)'
"""

__author__= 'Michael Gantenbrinker'
__version__= '0.1'
__bpydoc__= '''Exporter for OpenGL-Code'''

# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2008 Michael Gantenbrinker
#
# 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 modules
# #####################################################
# General Imports
import math
from math import *

import Blender
# Blender-API Imports
from Blender import *
#Mesh, Object, Material, Image, Texture, Lamp, Draw, Window, Scene
from Blender.Mathutils import *

import time

# #####################################################
# Constants
# #####################################################
BLENDER_VERSION = Blender.Get('version')

# General Options
EXPORT_ONLY_ACTIVE = False
USE_GLOBAL_DATA = True

# RenderType: DEFAULT: gl_Functions; LISTS: compiled glLists; ARRAYS: Vertex-Arrays
RT_DEFAULT = 0
RT_LISTS = 1
RT_ARRAYS = 2
RENDER_TYPE = RT_DEFAULT

# ApplicationType: DEFAULT: includable functions;  COMPLETE_APP: complete compilable Source-Code
AT_INCLUDABLE = 0
AT_COMPILABLE = 1
APP_TYPE = AT_INCLUDABLE

# PlatformType: LINUX: Linux; WINDOWS: Windows
PT_LINUX = 0
PT_WINDOWS = 1
PLATFORM_TYPE = PT_WINDOWS



# #####################################################
# Global CPP-Data
# #####################################################
MESHES = list()
LIGHTS = list()
CAMERA = list()


# #####################################################
# CLASSES
# #####################################################
class OpenGLTexture:
	def __init__(self):
		self.ID = -1
		self.strFilename = ""
	
class OpenGLMaterial:
	def __init__(self):
		self.ID = -1
		self.ambient = list((0.0, 0.0, 0.0))
		self.diffuse = list((0.0, 0.0, 0.0))
		self.specular = list((0.0, 0.0, 0.0))
		self.emission = list((0.0, 0.0, 0.0))
		self.shininess = 0.0
		
class OpenGLMesh:
	def __init__(self):
		self.ID = -1
		self.vertices = list()
		self.normals = list()
		self.colors = list()
		self.texCoords = list()
		self.triangleIndices = list()
		self.quadIndices = list()
		self.polygonIndices = list()
		
		
# #####################################################
# Helper-Methods
# #####################################################
def appendCameraData(obj):
	pass
	
def appendLightData(obj):
	pass
	
def appendMeshData(obj):
	mesh = Mesh.New()
	mesh.getFromObject(obj.name)
	oglMesh = OpenGLMesh()
	
	if(mesh.vertexUV):
		# Add Vertices, Normals and TextureCoordinates
		for v in mesh.verts:
			oglMesh.vertices.extend([[v.co.x, v.co.y, v.co.z]])
			oglMesh.normals.extend([[v.no.x, v.no.y, v.no.z]])
			oglMesh.texCoords.extend([[v.uvco.u, v.uvco.v]])
	else:
		# Add Vertices and Normals
		for v in mesh.verts:
			oglMesh.vertices.extend([[v.co.x, v.co.y, v.co.z]])
			oglMesh.normals.extend([[v.no.x, v.no.y, v.no.z]])
	
	# Add Faces
	for f in mesh.faces:
		if (len(f) == 3):
			oglMesh.triangleIndices.extend([[f.verts[0].index, f.verts[1].index, f.verts[2].index]])
		elif (len(f) == 4):
			oglMesh.quadIndices.extend([[f.verts[0].index, f.verts[1].index, f.verts[2].index, f.verts[3].index]])
		elif (len(f) > 4):
			indices = list()
			for v in f.verts:
				indices.append(v.index)
			oglMesh.polygonIndices.extend(indices)
			
#	# Add Material
#	if(len(oglMesh.materials)):
#		material = oglMesh.materials[0]
#	elif(oglMesh.vertexColors):
#		pass
		
		
	MESHES.append(oglMesh)


def writeDefines(file):
	global MESHES, LIGHTS
	
	file.write("/////////////////////////////////////////////////////////////////////////\n// DEFINES\n")
	file.write("#define NUM_MESHES %i\n" % len(MESHES))
	file.write("#define NUM_LIGHTS %i\n\n\n" % len(LIGHTS))
	
	file.flush()

def writeGlobalData(file):
	global MESHES, LIGHTS, CAMERA
	
	file.write("/////////////////////////////////////////////////////////////////////////\n// CONSTANTS\n")
	
	# Write Arrays with Mesh-Data
	if(len(MESHES)):
		# Write Vertex-Data
		file.write("// Vertex-Array for each Mesh\n")
		m = 0
		v = 0
		while(m < len(MESHES)):
			if(len(MESHES[m].vertices)):
				file.write("const float fVertices_%i[%i][3] = { " % ((m+1), len(MESHES[m].vertices)))
				while(v < len(MESHES[m].vertices)):
					file.write("{%ff, %ff, %ff}" % (MESHES[m].vertices[v][0], MESHES[m].vertices[v][1], MESHES[m].vertices[v][2]))
					if(v < len(MESHES[m].vertices)-1):
						file.write(", ")
					if(((v+1) % 4) == 0):
						file.write("\n")
					v += 1
					file.flush()
				file.write(" };\n")
			file.flush()
			m += 1
			v = 0
		
		# Write Normal-Data
		file.write("// Normal-Array for each Mesh\n")
		m = 0
		n = 0
		while(m < len(MESHES)):
			if(len(MESHES[m].vertices)):
				file.write("const float fNormals_%i[%i][3] = { " % ((m+1), len(MESHES[m].normals)))
				while(n < len(MESHES[m].normals)):
					file.write("{%ff, %ff, %ff}" % (MESHES[m].normals[n][0], MESHES[m].normals[n][1], MESHES[m].normals[n][2]))
					if(n < len(MESHES[m].normals)-1):
						file.write(", ")
					if(((n+1) % 4) == 0):
						file.write("\n")
					n += 1
					file.flush()
				file.write(" };\n")
			file.flush()
			m += 1
			n = 0
		
		# Write Triangle-Data
		file.write("\n// Triangle-Indices for each Mesh\n")
		m = 0
		t = 0
		while(m < len(MESHES)):
			if(len(MESHES[m].triangleIndices)):
				file.write("const unsigned long ulTriangleIndices_%i[%i][3] = { " % ((m+1),len(MESHES[m].triangleIndices)))
				while(t < len(MESHES[m].triangleIndices)):
					file.write("{%i, %i, %i}" % (MESHES[m].triangleIndices[t][0], MESHES[m].triangleIndices[t][1], MESHES[m].triangleIndices[t][2]))
					if(t < len(MESHES[m].triangleIndices)-1):
						file.write(", ")
					if(((t+1) % 8) == 0):
						file.write("\n")
					t += 1
					file.flush()
				file.write(" };\n")
			file.flush()
			m += 1
			t = 0

		# Write Quad-Data
		file.write("\n// Quad-Indices for each Mesh\n")
		m = 0
		q = 0
		while(m < len(MESHES)):
			if(len(MESHES[m].quadIndices)):
				file.write("const unsigned long ulQuadIndices_%i[%i][4] = { " % ((m+1),len(MESHES[m].quadIndices)))
				while(q < len(MESHES[m].quadIndices)):
					file.write("{%i, %i, %i, %i}" % (MESHES[m].quadIndices[q][0], MESHES[m].quadIndices[q][1], MESHES[m].quadIndices[q][2], MESHES[m].quadIndices[q][3]))
					if(q < len(MESHES[m].quadIndices)-1):
						file.write(", ")
					if(((q+1) % 8) == 0):
						file.write("\n")
					q += 1
					file.flush()
				file.write(" };\n")
			file.flush()
			m += 1
			q = 0
	
	
	
	
	file.write("\n// Array with Vertex-Array-Pointers\n")
	file.write("const float* pVertexPointers[] = {")
	m = 0
	while(m < len(MESHES)):
		if(len(MESHES[m].vertices)):
			file.write("&fVertices_%i[0][0]"%(m+1))
		else:
			file.write("0")
		if(m < len(MESHES)-1):
			file.write(", ")
		m += 1
	file.write("};")
	file.flush()
	
	
	file.write("\n// Array with Normal-Array-Pointers\n")
	file.write("const float* pNormalPointers[] = {")
	m = 0
	while(m < len(MESHES)):
		if(len(MESHES[m].vertices)):
			file.write("&fNormals_%i[0][0]"%(m+1))
		else:
			file.write("0")
		if(m < len(MESHES)-1):
			file.write(", ")
		m += 1
	file.write("};")
	file.flush()
	
	
	file.write("\n// Array with TriangleIndex-Array-Pointers\n")
	file.write("const unsigned long* pTriangleIndexPointers[] = {")
	m = 0
	while(m < len(MESHES)):
		if(len(MESHES[m].triangleIndices)):
			file.write("&ulTriangleIndices_%i[0][0]"%(m+1))
		else:
			file.write("0")
		if(m < len(MESHES)-1):
			file.write(", ")
		m += 1
	file.write("};")
	file.flush()
	
	
	file.write("\n// Array with QuadIndex-Array-Pointers\n")
	file.write("const unsigned long* pQuadIndexPointers[] = {")
	m = 0
	while(m < len(MESHES)):
		if(len(MESHES[m].quadIndices)):
			file.write("&ulQuadIndices_%i[0][0]"%(m+1))
		else:
			file.write("0")
		if(m < len(MESHES)-1):
			file.write(", ")
		m += 1
	file.write("};\n")
	file.flush()
	
	
	
	
	file.write("\n// Array with Vertex-Array-Lengths\n")
	file.write("const unsigned long ulVertexLengths[] = {")
	m = 0
	while(m < len(MESHES)):
		file.write("%i"%len(MESHES[m].vertices))
		if(m < len(MESHES)-1):
			file.write(", ")
		m += 1
	file.write("};")
	file.flush()
	
	
	file.write("\n// Array with TriangleIndex-Array-Lengths\n")
	file.write("const unsigned long ulTriangleIndexLengths[] = {")
	m = 0
	while(m < len(MESHES)):
		file.write("%i"%len(MESHES[m].triangleIndices))
		if(m < len(MESHES)-1):
			file.write(", ")
		m += 1
	file.write("};")
	file.flush()
	
	
	file.write("\n// Array with QuadIndex-Array-Lengths\n")
	file.write("const unsigned long ulQuadIndexLengths[] = {")
	m = 0
	while(m < len(MESHES)):
		file.write("%i"%len(MESHES[m].quadIndices))
		if(m < len(MESHES)-1):
			file.write(", ")
		m += 1
	file.write("};\n")
	file.flush()
	
	
	
	
def writeInitFunc(file):
	file.write("\n\nvoid Init()\n{\n")
	
	file.write("}\n\n")
	file.flush()
	
def writeRenderFunc(file):
	file.write("void Render(int iWidth = 1024, int iHeight = 768)\n{\n")
	
	file.write("\t// Setup Projektion-Matrix\n")
	file.write("\tglMatrixMode(GL_PROJECTION);\n")
	file.write("\tglLoadIdentity();\n")
	file.write("\tdouble dAspectRatio = (double)iWidth / (double)iHeight;\n")
	file.write("\tgluPerspective(45.0f, dAspectRatio, 1.0f, 100.0f);\n")
	file.write("\tglViewport(0, 0, iWidth, iHeight);\n")
	file.write("\tgluLookAt(5.0f, 5.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);\n\n")
				  
	file.write("\t// Setup Lights\n")
	file.write("\tfloat lPos[] = {5.0f, 5.0f, 5.0f, 1.0f};\n")
	file.write("\tfloat lDir[] = {-0.707f, -0.707f, -0.707f};\n")
	file.write("\tglLightfv(GL_LIGHT0, GL_AMBIENT,               StdColor_White);\n")
	file.write("\tglLightfv(GL_LIGHT0, GL_DIFFUSE,               StdColor_BrightGrey);\n")
	file.write("\tglLightfv(GL_LIGHT0, GL_SPECULAR,              StdColor_White);\n")
	file.write("\tglLightfv(GL_LIGHT0, GL_POSITION,              lPos);\n")
	file.write("\tglLightfv(GL_LIGHT0, GL_SPOT_DIRECTION,        lDir);\n")
	file.write("\tglLightf (GL_LIGHT0, GL_SPOT_CUTOFF,           180.f);\n")
	file.write("\tglLightf (GL_LIGHT0, GL_SPOT_EXPONENT,         1.0f);\n")
	file.write("\tglLightf (GL_LIGHT0, GL_CONSTANT_ATTENUATION,  1.0f);\n")
	file.write("\tglLightf (GL_LIGHT0, GL_LINEAR_ATTENUATION,    0.6f);\n")
	file.write("\tglLightf (GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.06f);\n")
	file.write("\tglEnable(GL_LIGHTING);\n")
	file.write("\tglEnable(GL_LIGHT0);\n")

	file.write("\t// Setup Scene-Content\n")
	file.write("\tglMatrixMode(GL_MODELVIEW);\n")
	file.write("\tglLoadIdentity();\n")
	file.write("\tfloat*         fVertices = 0;\n")
	file.write("\tfloat*         fNormals = 0;\n")
	file.write("\tunsigned long* ulTriangleIndices = 0;\n")
	file.write("\tunsigned long* ulQuadIndices = 0;\n")
	file.write("\tunsigned long* ulPtr = 0;\n\n")
	
	file.write("\tfor(int i = 0; i < NUM_MESHES; i++)\n\t{\n")
	file.write("\t\tfVertices = (float*)pVertexPointers[i];\n")
	file.write("\t\tfNormals = (float*)pNormalPointers[i];\n")
	file.write("\t\tulTriangleIndices = (unsigned long*)pTriangleIndexPointers[i];\n")
	file.write("\t\tulQuadIndices = (unsigned long*)pQuadIndexPointers[i];\n\n")
	file.write("\t\tif(ulTriangleIndices)\n\t\t{\n")
	file.write("\t\t\tglBegin(GL_TRIANGLES);\n")
	file.write("\t\t\t\tunsigned long t = 0;\n")
	file.write("\t\t\t\twhile(t < ulTriangleIndexLengths[i]*3)\n\t\t\t\t{\n")
	file.write("\t\t\t\t\tulPtr = &ulTriangleIndices[t];\n")
	file.write("\t\t\t\t\tglNormal3fv(&fNormals[ulPtr[0]*3]);\n")
	file.write("\t\t\t\t\tglVertex3fv(&fVertices[ulPtr[0]*3]);\n\n")
	file.write("\t\t\t\t\tglNormal3fv(&fNormals[ulPtr[1]*3]);\n")
	file.write("\t\t\t\t\tglVertex3fv(&fVertices[ulPtr[1]*3]);\n\n")
	file.write("\t\t\t\t\tglNormal3fv(&fNormals[ulPtr[2]*3]);\n")
	file.write("\t\t\t\t\tglVertex3fv(&fVertices[ulPtr[2]*3]);\n\n")
	file.write("\t\t\t\t\tt += 3;\n\t\t\t\t}\n")
	file.write("\t\t\tglEnd();\n\t\t}\n\n")
	file.write("\t\tif(ulQuadIndices)\n\t\t{\n")
	file.write("\t\t\tglBegin(GL_QUADS);\n")
	file.write("\t\t\t\tunsigned long q = 0;\n")
	file.write("\t\t\t\twhile(q < ulQuadIndexLengths[i]*4)\n\t\t\t\t{\n")
	file.write("\t\t\t\t\tulPtr = &ulQuadIndices[q];\n")
	file.write("\t\t\t\t\tglNormal3fv(&fNormals[ulPtr[0]*3]);\n")
	file.write("\t\t\t\t\tglVertex3fv(&fVertices[ulPtr[0]*3]);\n\n")
	file.write("\t\t\t\t\tglNormal3fv(&fNormals[ulPtr[1]*3]);\n")
	file.write("\t\t\t\t\tglVertex3fv(&fVertices[ulPtr[1]*3]);\n\n")
	file.write("\t\t\t\t\tglNormal3fv(&fNormals[ulPtr[2]*3]);\n")
	file.write("\t\t\t\t\tglVertex3fv(&fVertices[ulPtr[2]*3]);\n\n")
	file.write("\t\t\t\t\tglNormal3fv(&fNormals[ulPtr[3]*3]);\n")
	file.write("\t\t\t\t\tglVertex3fv(&fVertices[ulPtr[3]*3]);\n\n")
	file.write("\t\t\t\t\tq += 4;\n\t\t\t\t}\n")
	file.write("\t\t\tglEnd();\n\t\t}\n\t}\n")
		
	file.write("}\n\n")
	file.flush()
	
	
# #####################################################
# Exporting-Method
# #####################################################
def exportOpenGL(filename):
	# Check for correct User-Input
	if(filename is None):
		return
	
	# OpenFile for output
	file = open(filename, 'wb')
	
	# Write initial header
	header = ("/////////////////////////////////////////////////////////////////////////\n",\
		      "//\n",\
		      "//    %s.h - Renderfunctions\n" % Blender.sys.splitext(Blender.sys.basename(filename))[0],\
		      "//\n",\
		      "//    This file was created by the OpenGL-Export-Script for Blender.\n",\
		      "//\n",\
		      "//    Export-Time: %s\n" % time.strftime("%d.%m.%Y, %H:%M:%S", time.localtime()),\
		      "//\n"
		      "//    Script written by Michael Gantenbrinker.\n",\
		      "//\n",\
		      "/////////////////////////////////////////////////////////////////////////\n\n",\
		      "#ifndef __%s_H__\n" % Blender.sys.splitext(Blender.sys.basename(filename))[0].upper(),\
		      "#define __%s_H__\n\n\n" % Blender.sys.splitext(Blender.sys.basename(filename))[0].upper())
	file.writelines(header)
	file.flush()
	
	# Get the current scene
	scene = Scene.GetCurrent()
	
	# Create Data-Structures for only the active Object
	if (EXPORT_ONLY_ACTIVE):
		pass
	# Create Data-Structures for all Objects
	else:
		# Get all Objects
		if(BLENDER_VERSION <= 242):
			objects = scene.getChildren()
		else:
			objects = scene.objects
			
		# Go throw all objects
		for obj in objects:
			if(obj.type == "Mesh"):
				appendMeshData(obj)
			elif(obj.type == "Lamp"):
				appendLightData(obj)
			elif(obj.type == "Camera"):
				appendCameraData(obj)
	
	# The Data-Structures have been constructed, now write the data
	writeDefines(file)
	writeGlobalData(file)
	writeInitFunc(file)
	writeRenderFunc(file)
	
	# Write final stuff
	file.write("#endif  /* __%s_H__ */\n" % Blender.sys.splitext(Blender.sys.basename(filename))[0].upper())
	file.flush()
	
	file.close()
	
	
Blender.Window.FileSelector(exportOpenGL, 'Export OpenGL', '*.h')