Add vertex anim, light pos export

This commit is contained in:
ABelliqueux 2021-02-02 12:15:11 +01:00
parent 9cb70c7ae8
commit 6c2b090e73
1 changed files with 211 additions and 22 deletions

View File

@ -22,7 +22,8 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
def execute(self, context):
import bmesh
from math import degrees
from math import degrees, floor, cos, sin
from mathutils import Vector
def triangulate_object(obj): # Stolen from here : https://blender.stackexchange.com/questions/45698/triangulate-mesh-in-python/45722#45722
me = obj.data
@ -42,7 +43,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
if bpy.data.objects[m].type == 'MESH':
triangulate_object(bpy.data.objects[m])
scale = 200
scale = 65
f = open(os.path.normpath(self.filepath),"w+")
# write BODY struct def
@ -53,8 +54,14 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
"\tVECTOR min; \n" +
"\tVECTOR max; \n" +
"\t} BODY;\n\n")
# write typedef struct
# VERTEX ANIM struct
f.write("typedef struct { \n" +
"\tint nframes; // number of frames e.g 20\n" +
"\tint nvert; // number of vertices e.g 21\n" +
"\tSVECTOR data[]; // vertex pos as SVECTORs e.g 20 * 21 SVECTORS\n" +
"\t} VANIM;\n\n")
# MESH struct
f.write("typedef struct { \n"+
"\tTMESH * tmesh;\n" +
"\tint * index;\n" +
@ -65,9 +72,117 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
"\tSVECTOR * rot;\n" +
"\tshort * isRigidBody;\n" +
"\tshort * isPrism;\n" +
"\tshort * isAnim;\n" +
"\tlong * p;\n" +
"\tBODY * body;\n" +
"\tVANIM * anim;\n" +
"\t} MESH;\n\n")
# CAM POSITION struct
f.write("typedef struct {\n" +
"\tVECTOR pos;\n" +
"\tSVECTOR rot;\n" +
"\t} CAMPOS;\n\n" +
"\n// Blender cam ~= PSX cam with these settings : TV NTSC 4:3, Cam focal length : 100° ( 13.43 mm ))\n")
# CAM PATH struct
f.write("typedef struct {\n" +
"\tshort len, cursor;\n" +
"\tVECTOR points[];\n" +
"\t} CAMPATH;\n\n")
camPathPoints = []
# set camera position and rotation in the scene
for o in range(len(bpy.data.objects)):
if bpy.data.objects[o].type == 'CAMERA':
f.write("CAMPOS camStartPos = {\n" +
"\t{" + str(round(-bpy.data.objects[o].location.x * scale)) + "," + str(round(bpy.data.objects[o].location.z * scale)) + "," +str(round(-bpy.data.objects[o].location.y * scale)) + "},\n" +
"\t{" + str(round(-(degrees(bpy.data.objects[o].rotation_euler.x)-90)/360 * 4096)) + "," + str(round(degrees(bpy.data.objects[o].rotation_euler.z)/360 * 4096)) + "," + str(round(-(degrees(bpy.data.objects[o].rotation_euler.y))/360 * 4096)) + "},\n" +
"};\n\n")
# find camStart and camEnd empties for camera trajectory
if bpy.data.objects[o].type == 'EMPTY' :
if bpy.data.objects[o].name.startswith("camPath"):
camPathPoints.append(bpy.data.objects[o].name)
if camPathPoints:
# ~ camPathPoints = list(reversed(camPathPoints))
for p in range(len(camPathPoints)):
if p == 0:
f.write("CAMPATH camPath = {\n" +
"\t" + str(len(camPathPoints)) + ",\n" +
"\t0,\n" +
"\t{\n")
f.write("\t\t{" + str(round(-bpy.data.objects[camPathPoints[p]].location.x * scale)) + "," + str(round(bpy.data.objects[camPathPoints[p]].location.z * scale)) + "," +str(round(-bpy.data.objects[camPathPoints[p]].location.y * scale)) + "}")
if p != len(camPathPoints) - 1:
f.write(",\n")
f.write("\n\t}\n};\n\n")
# Lights : max 3 sunlamp, no space coords
# LLM : Local Light Matrix
if len(bpy.data.lamps) is not None:
# ~ f.write( "static MATRIX lgtmat = {\n" +
# ~ "\t 4096, 4096, 4096,\n" +
# ~ "\t -4096, 4096, 4096,\n" +
# ~ "\t -4096, 4096, -4096\n" +
# ~ "};\n")
cnt = 0
pad = 3 - len(bpy.data.lamps)
f.write( "static MATRIX lgtmat = {\n")
for l in range(len(bpy.data.lamps)):
## intensity
energy = int(bpy.data.lamps[l].energy * 4096)
# Euler based
# get a direction vector from world matrix
lightdir = bpy.data.objects[bpy.data.lamps[l].name].matrix_world * Vector((0,0,-1,0))
f.write(
"\t" + str(int(lightdir.x * energy)) + "," +
"\t" + str(int(-lightdir.z * energy)) + "," +
"\t" + str(int(lightdir.y * energy))
)
if l != len(bpy.data.lamps) - 1:
f.write(",\n")
if pad:
while cnt < pad:
f.write("\t0,0,0")
if cnt != 1:
f.write(",\n")
cnt += 1
f.write("\n\t};\n\n")
# LCM : Local Color Matrix
f.write( "static MATRIX cmat = {\n")
LCM = []
for l in bpy.data.lamps:
LCM.append(str(int(l.color.r * 4096) if l.color.r else 0))
LCM.append(str(int(l.color.g * 4096) if l.color.g else 0))
LCM.append(str(int(l.color.b * 4096) if l.color.b else 0))
if len(LCM) < 9:
while len(LCM) < 9:
LCM.append('0')
f.write(
"\t" + LCM[0] + "," + LCM[3] + "," + LCM[6] + ",\n" +
"\t" + LCM[1] + "," + LCM[4] + "," + LCM[7] + ",\n" +
"\t" + LCM[2] + "," + LCM[5] + "," + LCM[8] + "\n" )
f.write("\t};\n\n")
for m in bpy.data.meshes:
# Write vertices vectors
@ -88,9 +203,9 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
# AABB : append vertices coords by axis
Xvals.append(v.x)
Yvals.append(v.y)
Zvals.append(v.z)
Zvals.append(-v.z)
f.write("\t{"+str(v.x*scale)+","+str(v.y*scale)+","+str(v.z*scale)+"}")
f.write("\t{"+str(round(v.x*scale))+","+str(round(-v.z*scale)) + "," + str(round(v.y*scale)) +"}")
if i != len(m.vertices) - 1:
f.write(",")
@ -100,9 +215,9 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
# Write normals vectors
f.write("SVECTOR "+"model"+cleanName+"_normal[] = {\n")
for i in range(len(m.polygons)):
poly = m.polygons[i]
f.write("\t"+str(poly.normal.x)+","+str(poly.normal.y)+","+str(poly.normal.z)+",0")
for i in range(len(m.vertices)):
poly = m.vertices[i]
f.write("\t"+str(round(-poly.normal.x * 4096))+","+str(round(poly.normal.z * 4096))+","+str(round(-poly.normal.y * 4096))+",0")
if i != len(m.polygons) - 1:
f.write(",")
f.write("\n")
@ -130,7 +245,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
u = uv_layer[i].uv
ux = u.x * tex_width
uy = u.y * tex_height
f.write("\t"+str(ux)+","+str(tex_height - uy)+", 0, 0")
f.write("\t"+str(max(0, min( round(ux) , 255 )))+","+str(max(0, min(round(tex_height - uy) , 255 )))+", 0, 0") # Clamp values to 0-255 to avoid tpage overflow
if i != len(uv_layer) - 1:
f.write(",")
f.write("\n")
@ -168,21 +283,90 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
f.write(",")
f.write("\n")
f.write("};\n\n")
# get custom properties isRigidBody, isPrism, isAnim
chkProp = {
'isAnim':0,
'isRigidBody':0,
'isPrism':0,
'mass':1000
}
for prop in chkProp:
if m.get(prop) is not None:
chkProp[prop] = m[prop]
# write vertex anim if isAnim != 0 # https://stackoverflow.com/questions/9138637/vertex-animation-exporter-for-blender
if m.get("isAnim") is not None and m["isAnim"] != 0:
#write vertex pos
o = bpy.data.objects[m.name]
frame_start = bpy.context.scene.frame_start
frame_end = bpy.context.scene.frame_end
nFrame = frame_end - frame_start
# ~ f.write("int "+"model"+cleanName+"_anim_nframes = " + str(nFrame) + ";\n")
# ~ f.write("int "+"model"+cleanName+"_anim_nvert = {" + str(len(nm.vertices)) + "};")
# ~ f.write("SVECTOR "+"model"+cleanName+"_anim_data[")
c = 0;
tmp_meshes = []
for i in range(frame_start - 1, frame_end):
bpy.context.scene.frame_set(i)
bpy.context.scene.update()
nm = o.to_mesh(bpy.context.scene, True, 'PREVIEW')
# ~ f.write(str(len(nm.vertices)))
if i == 0 :
f.write("VANIM modelCylindre_anim = {\n" +
"\t" + str(nFrame) + ",\n" +
"\t" + str(len(nm.vertices)) + ",\n" +
"\t{\n"
)
for v in range(len(nm.vertices)):
if v == 0:
# ~ f.write("{\n")
f.write("\t\t//Frame %d\n" % i)
f.write("\t\t{ " + str(round(nm.vertices[v].co.x*scale)) + "," + str(round(-nm.vertices[v].co.z*scale)) + "," + str(round(nm.vertices[v].co.y*scale)) + " }")
if c != len(nm.vertices) * (nFrame + 1) * 3 - 3:
f.write(",\n")
if v == len(nm.vertices) - 1:
f.write("\n")
c += 3;
# ~ if i != (frame_end - frame_start):
# ~ f.write(",")
tmp_meshes.append(nm)
# ~ tmp_meshes.remove(nm)
f.write("\n\t}\n};\n\n")
for nm in tmp_meshes:
# ~ f.write(str(nm))
bpy.data.meshes.remove(nm)
#Stuff # ~ bpy.data.objects[bpy.data.meshes[0].name].active_shape_key.value : access shape_key
#write object matrix, rot and pos vectors
f.write("MATRIX model"+cleanName+"_matrix = {0};\n" +
"VECTOR model"+cleanName+"_pos = {"+ str(bpy.data.objects[m.name].location.x * 100) + "," + str(bpy.data.objects[m.name].location.y * 100) + "," + str(bpy.data.objects[m.name].location.z * 100) + ", 0};\n" +
"SVECTOR model"+cleanName+"_rot = {"+ str(degrees(bpy.data.objects[m.name].rotation_euler.x)/360 * 4096) + "," + str(degrees(bpy.data.objects[m.name].rotation_euler.y)/360 * 4096) + "," + str(degrees(bpy.data.objects[m.name].rotation_euler.z)/360 * 4096) + "};\n" +
"short model"+cleanName+"_isRigidBody = 0;\n" +
"short model"+cleanName+"_isPrism = 0;\n" +
"VECTOR model"+cleanName+"_pos = {"+ str(round(bpy.data.objects[m.name].location.x * scale)) + "," + str(round(-bpy.data.objects[m.name].location.z * scale)) + "," + str(round(bpy.data.objects[m.name].location.y * scale)) + ", 0};\n" +
"SVECTOR model"+cleanName+"_rot = {"+ str(round(degrees(bpy.data.objects[m.name].rotation_euler.x)/360 * 4096)) + "," + str(round(degrees(-bpy.data.objects[m.name].rotation_euler.z)/360 * 4096)) + "," + str(round(degrees(bpy.data.objects[m.name].rotation_euler.y)/360 * 4096)) + "};\n" +
"short model"+cleanName+"_isRigidBody =" + str(int(chkProp['isRigidBody'])) + ";\n" +
"short model"+cleanName+"_isPrism =" + str(int(chkProp['isPrism'])) + ";\n" +
"short model"+cleanName+"_isAnim =" + str(int(chkProp['isAnim'])) + ";\n" +
"long model"+cleanName+"_p = 0;\n" +
"BODY model"+cleanName+"_body = {\n" +
"\t0, 0, 0, 0,\n" +
"\t0, 0, 0, 0,\n" +
"\t1,\n" +
"\t" + str(round(bpy.data.objects[m.name].location.x * scale)) + "," + str(round(-bpy.data.objects[m.name].location.z * scale)) + "," + str(round(bpy.data.objects[m.name].location.y * scale)) + ", 0,\n" +
"\t"+ str(round(degrees(bpy.data.objects[m.name].rotation_euler.x)/360 * 4096)) + "," + str(round(degrees(-bpy.data.objects[m.name].rotation_euler.z)/360 * 4096)) + "," + str(round(degrees(bpy.data.objects[m.name].rotation_euler.y)/360 * 4096)) + ", 0,\n" +
"\t" + str(int(chkProp['mass'])) + ",\n" +
# write min and max values of AABBs on each axis
"\t" + str(min(Xvals) * scale) + "," + str(min(Yvals) * scale) + "," + str(min(Zvals) * scale) + ", 0,\n" +
"\t" + str(max(Xvals) * scale) + "," + str(max(Yvals) * scale) + "," + str(max(Zvals) * scale) + ", 0,\n" +
"\t" + str(round(min(Xvals) * scale)) + "," + str(round(min(Zvals) * scale)) + "," + str(round(min(Yvals) * scale)) + ", 0,\n" +
"\t" + str(round(max(Xvals) * scale)) + "," + str(round(max(Zvals) * scale)) + "," + str(round(max(Yvals) * scale)) + ", 0,\n" +
"\t};\n\n")
# Write TMESH struct
@ -233,8 +417,13 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
"\t&model"+cleanName+"_rot,\n" +
"\t&model"+cleanName+"_isRigidBody,\n" +
"\t&model"+cleanName+"_isPrism,\n" +
"\t&model"+cleanName+"_p\n")
"\t&model"+cleanName+"_isAnim,\n" +
"\t&model"+cleanName+"_p,\n" +
"\t&model"+cleanName+"_body")
if m.get("isAnim") is not None and m["isAnim"] != 0:
f.write(",\n\t&model"+cleanName+"_anim\n")
else:
f.write("\n")
f.write("};\n\n")