blender exporter

import bpy
import math
import time
import bmesh
from os.path import expanduser

# 2014 march 14 sphere is not yet implemented.

# Inputs:
# c_=cylinder, lc_=looped-cylinder, f_=frame, h_=hemisphere, l_=line, p_=pipe, r_=ribbon, s_=sphere
# 

# Outputs (to glData.hpp, glData.cpp):
# array types: vtx, txc, idx, nml
# n99 = indicates an array of 99 elements
# alpha, cull, having txt or not etc.
# primitive types: TG=triangles, TS=TriangleStrip, LN=lines, LS=LineStrip, PS=Points
# Word of primitiv types are only used for idx.

# example formats in glData.hpp
#
# extern GLfloat glData_Objectname_body_vtx[];
# extern GLint glData_Objectname_body_vtx_n;
# extern GLuint glData_Objectname_body_idx_type;
# extern GLint glData_Objectname_body_idx_n;
# Definition is in glData.cppp.
# It should be used in application as below;
# glBufferData(GL_ARRAY_BUFFER, glData_Objectname_body_vtx_n * sizeof(GLfloat), 
#     glData_Objectname_body_vtx, GL_DYNAMIC_DRAW);
# glDrawElements(glData_Objectname_body_idx_type, glData_Objectname_body_idx_n, GL_UNSIGNED_SHORT, 0);
#
# Plz note in "_n" always means lenth of array, neither bytes or vertices,
# i.e. vtx_ is the size of 3x verts (and txc_ 2x verts, idx_ 1x verts).

# index
def printIdx(f,idx, nIdx):
    nListLines = 1+floor(nIdx/10)
    print("nIdx = "+str(nIdx), "nListLines ="+str(nListLines))
    i = 0
    for j in range(nListLines):
        print("j= "+str(j))
        s = "\t"
        for k in range(10):
            if i < nIdx-1:
                s = s+str(idx[i])+", "
            elif i < nIdx:
                s = s+str(idx[i])
            else:
                break
            print("hi["+str(i)+"] = "+str(idx[i]))
            i += 1
        s += "\n"
        f.write(s)

def writeIdx(f, attributes, nVert):
    print("\nname="+attributes[1]+" nVert="+str(nVert))
    f.write("GLushort glData_"+attributes[1]+"_idx[] = {\n")
    n = int(attributes[-2].lstrip("n"))
    if n != nVert:
        print("Error: The num of verts does not match.")
    prm_s = attributes[-1].split("x")
    if attributes[0] is 'h':
        print("idx for h_")
        # hemisphere
        # h_Objectname_n37_3 
        # The last int is the ltatitudes, which is the param for hemisphere.py,
        # and means "skirt" edge.
        nLat = int(prm_s[0])
        nLatitudes = floor(math.sqrt(float((nVert-1)/3)))
        if nLat != nLatitudes:
            print("Wrong num latitude!", )
        hi = list(hemisphereIdx(nLat))
        print("hi",hi)
        nIdx = len(hi)
        printIdx(f,hi, nIdx)
    elif attributes[0] is 'c':
        print("idx for c_")
        # cylinder
        # c_Objectname_n192_12x16
        n = int(prm_s[0])
        nn = int(prm_s[1])
        print("n="+str(n), "nn="+str(nn))
        ci = list(cylinderIdx(n, nn))
        print("ci",ci)
        nIdx=len(ci)
        printIdx(f,ci, nIdx)
    elif attributes[0] is 'r':
        print("idx for r_")
        # ribbon
        # r_Objectname_n32_12x2x10. 
        # ribbon has pair of verts
        n = int(prm_s[0])
        nn = int(prm_s[2])
        print("ribbon",n,nn)
        ri = list(ribbonIdx(n, nn))
        print("ri",ri)
        nIdx=len(ri)
        printIdx(f,ri, nIdx)
    else:
        print("idx for none")
        nIdx=0
    f.write("};\n")
    f.write("GLint glData_"+attributes[1] +"_idx_n = "+str(nIdx)+";\n\n")

def printMeshes():
    for m in bpy.data.meshes:
        print(m.name)

def printObjects():
    for m in bpy.data.objects:
        print(m.name)

def hemisphereIdx(n):
#    for k in range(3*n*(n+1)):
#        yield(k, k+1)
    for p in range(n):
        # u0 = upper origin of p_th latitude
        # l0 = lower origin of p_th latitude (on p+1_th latitude)
        if p == 0:
            u0 = 0
        else:
            u0 = 1+3*p*(p-1)
        l0 = 1+3*p*(p+1)
        for q in range(6):
            # on q_th edge of p_th latitude
            # u, l are edge-origins
            u = u0+p*q
            l = l0+(p+1)*q
            # redundancy required
            yield(u)
            yield(l)
            for r in range(p):
                # r_th point on q_th edge of p_th latitude
                uu = u+r
                ll = l+r+1
                yield(uu)
                yield(ll)
        # for each latitude, last vtx should be the origin
        yield(u0)
        yield(l0)
    
def cylinderIdx(m, n):
    for y in range(n-1):
        for x in range(m):
            yield y*m + x
            yield (y+1)*m + x
        yield y*m
        yield (y+1)*m

    
def ribbonIdx(n, nn):
    # ribbon has pair
    for i in range(nn):
        if nn%2 ==0:
            d = 1
            o = (2*n)*i
        else:
            d = -1
            o = (2*n)*(i+1)-2
        for i in range(n):
            yield o+d*2*i        
            yield o+d*2*i+1
        
def main():
    nTotalVerts = 0
    home = expanduser("~")
    myTimeStamp = time.ctime().translate(str.maketrans(" :","_-"))
    f = open(home+"/Workspace/heap/glData-"+myTimeStamp+".c", "w")
    headerList = "//glData-"+myTimeStamp+".h\n"
    headerList += "#ifndef _MY_GLDATA_H_\n"
    headerList += "#define _MY_GLDATA_H_\n"
    headerList += "#include <GLES2/gl2.h>\n"
    # 
    f.write("// glData-"+myTimeStamp+".c\n")
    f.write("#include \"glData-"+myTimeStamp+".h\"")
    scn = bpy.context.scene
    for o in scn.objects:
        if o.type != 'MESH':
            continue
        scn.objects.active = o
        bpy.ops.object.select_pattern(pattern=o.name)
        if bpy.ops.object.mode_set.poll():
            bpy.ops.object.mode_set(mode='EDIT', toggle=False)
        #bpy.ops.mesh.select_all(action='SELECT')
        m = o.data
        l = len(m.vertices)
        nTotalVerts += l
        if l==0:
            continue
        attributes = o.name.split('_')
        if len(attributes) < 4:
            print("object name error:"+attributes[0]+"\n")
            continue
        headerList += "\n////////// "+attributes[1]+" //////////\n"
        f.write("\n////////// "+attributes[1]+" //////////\n")
        headerList += "extern GLint glData_"+attributes[1]+"_vtx_n;\n"
        f.write("GLint glData_"+attributes[1]+"_vtx_n = "+str(l)+";\n")
        headerList += "extern GLfloat glData_"+attributes[1]+"_vtx[];\n"
        f.write("GLfloat glData_"+attributes[1]+"_vtx[] = {\n")
        for n in range(l):
            if n % 10 == 0:
                f.write("\t// "+str(n)+"th vert\n")
            v = m.vertices[n]
            if n < l-1:
                f.write("\t"+str(v.co[0])
                    +",\t"+str(v.co[1])
                    +",\t"+str(v.co[2])+",\n")
            else:
                f.write("\t"+str(v.co[0])
                    +",\t"+str(v.co[1])
                    +",\t"+str(v.co[2])+"\n")
        f.write("};\n\n")
        # Normal
        headerList += "extern GLint glData_"+attributes[1]+"_nml_n;\n"
        f.write("GLint glData_"+attributes[1]+"_nml_n = "+str(l)+";\n")
        headerList += "extern GLfloat glData_"+attributes[1]+"_nml[];\n"
        f.write("GLfloat glData_"+attributes[1]+"_nml[] = {\n")
        for n in range(l):
            if n % 10 == 0:
                f.write("\t// "+str(n)+"th vert\n")
            nml = m.vertices[n].normal
            if n < l-1:
                f.write("\t"+str(nml.x)
                    +",\t"+str(nml.y)
                    +",\t"+str(nml.z)+",\n")
            else:
                f.write("\t"+str(nml.x)
                    +",\t"+str(nml.y)
                    +",\t"+str(nml.z)+"\n")
        f.write("};\n\n")
        # 
        if bpy.ops.object.mode_set.poll():
            bpy.ops.object.mode_set(mode='EDIT', toggle=False)
        bpy.context.scene.objects.active = o
        bm = bmesh.from_edit_mesh(m)
        uv_lay = bm.loops.layers.uv.active
        # Indices
        headerList += "extern GLint glData_"+attributes[1]+"_idx_n;\n"
        headerList += "extern GLushort glData_"+attributes[1]+"_idx[];\n"
        n = len(o.data.vertices)
        print("n = "+str(n))
        writeIdx(f, attributes, n)
        #
        uv = {}
        nFaces = len(bm.faces)
        for face in bm.faces:
            for loop in face.loops:
                if uv_lay is not None:
                    uv[loop.vert.index] = loop[uv_lay].uv
        #
        # matrix TRANSPOSED
        mx = o.matrix_basis
        headerList += "extern GLfloat glData_"+attributes[1]+"_mtrx[];\n"
        f.write("GLfloat glData_"+attributes[1]+"_mtrx[] = {\n")
        #
        f.write("\t"+str(mx[0][0])+", "+str(mx[2][0])+", "+str(-mx[1][0])+", "+str(mx[3][0])+",\n")
        f.write("\t"+str(mx[0][1])+", "+str(mx[2][1])+", "+str(-mx[1][1])+", "+str(mx[3][1])+",\n")
        f.write("\t"+str(mx[0][2])+", "+str(mx[2][2])+", "+str(-mx[1][2])+", "+str(mx[3][2])+",\n")
        f.write("\t"+str(mx[0][3])+", "+str(mx[2][3])+", "+str(-mx[1][3])+", "+str(mx[3][3])+"\n")
        #
        f.write("};\n\n")
        # 
        # uv texture
        n = len(uv)
        headerList += "extern int glData_"+attributes[1]+"_hasTexture;\n"
        if n==0:
            f.write("int glData_"+attributes[1]+"_hasTexture = 0;\n")
            continue
        f.write("int glData_"+attributes[1]+"_hasTexture = 1;\n")
        headerList += "extern GLfloat glData_"+attributes[1]+"_uv[];\n"
        f.write("GLfloat glData_"+attributes[1]+"_uv[] = {\n")
        #index starts with 0
        for d in sorted(uv):
            if d % 10 == 0:
                f.write("\t// "+str(d)+"th vert\n")
            if d < n-1:
                f.write("\t"+str(uv[d][0])+",\t"+str(uv[d][1])+",\n")
            else:
                f.write("\t"+str(uv[d][0])+",\t"+str(uv[d][1])+"\n")
        f.write("};\n\n")
    #
    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    f.close()
    # write header file
    headerList += "\n////////////////////////////////////////\n"
    headerList += "// Total number of verts = "+str(nTotalVerts)+"\n"
    headerList += "#endif // _MY_GLDATA_H_\n"
    f = open(home+"/Workspace/heap/glData-"+myTimeStamp+".h", "w")
    f.write(headerList)
    f.close