blender_io_export_psx_mesh/io_export_psx_tmesh.py

729 lines
32 KiB
Python
Raw Normal View History

2021-03-01 20:05:38 +01:00
# bpy. app. debug = True
bl_info = {
"name": "PSX TMesh exporter",
"author": "Schnappy, TheDukeOfZill",
"blender": (2,7,9),
"version": (0,0,2),
"location": "File > Import-Export",
"description": "Export psx data format",
"category": "Import-Export"
}
2021-03-01 20:05:38 +01:00
import os
import bpy
2021-03-12 11:21:18 +01:00
import bmesh
2021-02-19 18:00:42 +01:00
import unicodedata
2021-03-12 11:21:18 +01:00
from math import radians, degrees, floor, cos, sin
from mathutils import Vector
2021-02-19 18:00:42 +01:00
from bpy.props import (CollectionProperty,
StringProperty,
BoolProperty,
EnumProperty,
FloatProperty
)
from bpy_extras.io_utils import (ExportHelper,
axis_conversion
)
class ExportMyFormat(bpy.types.Operator, ExportHelper):
bl_idname = "export_psx.c";
2021-02-19 18:00:42 +01:00
bl_label = "PSX compatible scene exporter";
bl_options = {'PRESET'};
filename_ext = ".c";
2021-02-19 18:00:42 +01:00
exp_Triangulate = BoolProperty(
name="Triangulate meshes ( Destructive ! )",
description="Triangulate meshes (destructive ! Do not use your original file)",
default=False,
)
exp_Scale = FloatProperty(
name="Scale",
description="Scale of exported mesh.",
min=1, max=1000,
default=65,
)
2021-03-01 20:05:38 +01:00
exp_Precalc = BoolProperty(
name="Use precalculated BGs",
description="Set the BGs UV to black",
default=False,
)
def execute(self, context):
2021-03-12 11:21:18 +01:00
2020-12-30 22:09:12 +01:00
def triangulate_object(obj): # Stolen from here : https://blender.stackexchange.com/questions/45698/triangulate-mesh-in-python/45722#45722
me = obj.data
# Get a BMesh representation
bm = bmesh.new()
bm.from_mesh(me)
bmesh.ops.triangulate(bm, faces=bm.faces[:], quad_method=0, ngon_method=0)
# Finish up, write the bmesh back to the mesh
bm.to_mesh(me)
bm.free()
2021-02-19 18:00:42 +01:00
# ~ return bm
2021-02-19 18:00:42 +01:00
def CleanName(strName):
name = strName.replace(' ','_')
name = name.replace('.','_')
name = unicodedata.normalize('NFKD',name).encode('ASCII', 'ignore').decode()
return name
2021-03-12 12:13:08 +01:00
# Leave edit mode to avoid errors
2020-12-29 15:53:47 +01:00
bpy.ops.object.mode_set(mode='OBJECT')
2020-12-30 22:09:12 +01:00
# triangulate objects of type mesh
2021-02-19 18:00:42 +01:00
if self.exp_Triangulate:
for o in range(len(bpy.data.objects)):
if bpy.data.objects[o].type == 'MESH':
triangulate_object(bpy.data.objects[o])
# ~ obj = bpy.data.objects[bpy.data.objects[o].name]
# ~ tm = obj.to_mesh(bpy.context.scene, False, 'PREVIEW')
# ~ work_meshes.append(tm)
scale = self.exp_Scale
2020-12-30 22:09:12 +01:00
2021-03-01 20:05:38 +01:00
# get working directory path
filepath = bpy.data.filepath
folder = os.path.dirname(bpy.path.abspath(filepath))
dirpath = os.path.join(folder, "TIM")
camAngles = []
2021-03-12 11:21:18 +01:00
defaultCam = 'NULL'
2021-03-01 20:05:38 +01:00
# if using precalculated BG, render and export them to ./TIM/
if self.exp_Precalc:
# create folder if !exist
os.makedirs(dirpath, exist_ok = 1)
# file format config
bpy.context.scene.render.image_settings.file_format = 'PNG'
bpy.context.scene.render.image_settings.quality = 100
bpy.context.scene.render.image_settings.compression = 0
bpy.context.scene.render.image_settings.color_depth = '8'
# get current cam
cam = bpy.context.scene.camera
# store cam location and rot for restoration later
# ~ originLoc = cam.location
# ~ originRot = cam.rotation_euler
for o in bpy.data.objects:
2021-03-12 11:21:18 +01:00
if o.type == 'CAMERA' and o.data.get('isDefault'):
defaultCam = o.name
2021-03-01 20:05:38 +01:00
if o.type == 'CAMERA' and o.name.startswith("camPath"):
# set cam as active - could be useful if multiple cam are present
bpy.context.scene.camera = o
# set cam Rot/Loc to empty rot/loc
# ~ cam.location = o.location
# ~ cam.rotation_euler = o.rotation_euler
# apply 90degrees rotation on local X axis, as EMPTYs are pointing to -Z (bottom of the screen) by default
# ~ cam.rotation_euler.rotate_axis('X', radians(90))
# render and save image
bpy.ops.render.render()
bpy.data.images["Render Result"].save_render(folder + os.sep + "TIM" + os.sep + "bg_" + CleanName(o.name) + "." + str(bpy.context.scene.render.image_settings.file_format).lower())
camAngles.append(o)
# set cam back to original pos/rot
# ~ cam.location = originLoc
# ~ cam.rotation_euler = originRot
f = open(os.path.normpath(self.filepath),"w+")
2020-12-30 11:23:36 +01:00
2021-01-14 17:22:44 +01:00
# write BODY struct def
f.write("typedef struct {\n" +
2021-02-19 18:00:42 +01:00
"\tVECTOR gForce;\n" +
2021-01-14 17:22:44 +01:00
"\tVECTOR position;\n" +
"\tSVECTOR velocity;\n" +
2021-03-01 20:05:38 +01:00
"\tint mass;\n" +
2021-02-19 18:00:42 +01:00
"\tint invMass;\n" +
2021-01-14 17:22:44 +01:00
"\tVECTOR min; \n" +
"\tVECTOR max; \n" +
2021-02-19 18:00:42 +01:00
"\tint restitution; \n" +
2021-01-14 17:22:44 +01:00
"\t} BODY;\n\n")
2021-03-12 12:13:08 +01:00
2021-02-02 12:15:11 +01:00
# 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" +
2021-03-01 20:05:38 +01:00
"\tint cursor; // anim cursor\n" +
"\tint lerpCursor; // anim cursor\n" +
"\tint dir; // playback direction (1 or -1)\n" +
"\tint interpolate; // use lerp to interpolate keyframes\n" +
2021-02-02 12:15:11 +01:00
"\tSVECTOR data[]; // vertex pos as SVECTORs e.g 20 * 21 SVECTORS\n" +
2021-02-19 18:00:42 +01:00
# ~ "\tSVECTOR normals[]; // vertex pos as SVECTORs e.g 20 * 21 SVECTORS\n" +
2021-02-02 12:15:11 +01:00
"\t} VANIM;\n\n")
2021-02-19 18:00:42 +01:00
# PRIM struc
f.write("typedef struct {\n" +
"\tVECTOR order;\n" +
"\tint code; // Same as POL3/POL4 codes : Code (F3 = 1, FT3 = 2, G3 = 3, GT3 = 4) Code (F4 = 5, FT4 = 6, G4 = 7, GT4 = 8)\n" +
"\t} PRIM;\n\n")
2021-02-02 12:15:11 +01:00
# MESH struct
2020-12-30 11:23:36 +01:00
f.write("typedef struct { \n"+
2021-01-04 18:28:27 +01:00
"\tTMESH * tmesh;\n" +
2021-02-19 18:00:42 +01:00
"\tPRIM * index;\n" +
2021-01-04 18:28:27 +01:00
"\tTIM_IMAGE * tim; \n" +
2021-03-01 20:05:38 +01:00
"\tunsigned long * tim_data;\n"+
2021-01-04 18:28:27 +01:00
"\tMATRIX * mat;\n" +
"\tVECTOR * pos;\n" +
"\tSVECTOR * rot;\n" +
2021-01-14 17:22:44 +01:00
"\tshort * isRigidBody;\n" +
2021-02-19 18:00:42 +01:00
"\tshort * isStaticBody;\n" +
2021-01-04 18:28:27 +01:00
"\tshort * isPrism;\n" +
2021-02-02 12:15:11 +01:00
"\tshort * isAnim;\n" +
2021-02-19 18:00:42 +01:00
"\tshort * isActor;\n" +
"\tshort * isLevel;\n" +
2021-03-01 20:05:38 +01:00
"\tshort * isBG;\n" +
2021-01-04 18:28:27 +01:00
"\tlong * p;\n" +
2021-03-01 20:05:38 +01:00
"\tlong * OTz;\n" +
2021-02-19 18:00:42 +01:00
"\tBODY * body;\n" +
"\tVANIM * anim;\n" +
2020-12-30 11:23:36 +01:00
"\t} MESH;\n\n")
2021-02-02 12:15:11 +01:00
# CAM POSITION struct
f.write("typedef struct {\n" +
"\tVECTOR pos;\n" +
"\tSVECTOR rot;\n" +
"\t} CAMPOS;\n\n" +
2021-03-01 20:05:38 +01:00
"\n// Blender cam ~= PSX cam with these settings : NTSC - 320x240, PAL 320x256, pixel ratio 1:1, cam focal length : perspective 90° ( 16 mm ))\n\n")
# CAM ANGLE
f.write("typedef struct {\n" +
"\tCAMPOS * campos;\n" +
"\tTIM_IMAGE * BGtim;\n" +
"\tunsigned long * tim_data;\n" +
"\t} CAMANGLE;\n\n")
2021-02-02 12:15:11 +01:00
# CAM PATH struct
f.write("typedef struct {\n" +
2021-03-01 20:05:38 +01:00
"\tshort len, cursor, pos;\n" +
2021-02-02 12:15:11 +01:00
"\tVECTOR points[];\n" +
"\t} CAMPATH;\n\n")
2021-03-12 12:13:08 +01:00
# NODE struc
f.Write("typedef struct {\n" +
"\tMESH * curPlane;\n" +
"\tMESH * siblings[];" +
"\tMESH * objects[];" +
"\t} NODE;\n\n")
2021-02-02 12:15:11 +01:00
camPathPoints = []
2021-02-19 18:00:42 +01:00
first_mesh = CleanName(bpy.data.meshes[0].name)
2021-02-02 12:15:11 +01:00
# set camera position and rotation in the scene
for o in range(len(bpy.data.objects)):
2021-03-01 20:05:38 +01:00
if bpy.data.objects[o].type == 'CAMERA' and bpy.data.objects[o].data.get('isDefault'):
defaultCam = bpy.data.objects[o].name
2021-02-02 12:15:11 +01:00
if bpy.data.objects[o].type == 'CAMERA':
2021-03-01 20:05:38 +01:00
f.write("CAMPOS camPos_" + CleanName(bpy.data.objects[o].name) + " = {\n" +
2021-02-02 12:15:11 +01:00
"\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" +
2021-03-01 20:05:38 +01:00
"\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" +
2021-02-02 12:15:11 +01:00
"};\n\n")
2021-03-01 20:05:38 +01:00
2021-02-02 12:15:11 +01:00
# find camStart and camEnd empties for camera trajectory
2021-03-01 20:05:38 +01:00
if bpy.data.objects[o].type == 'CAMERA' :
if bpy.data.objects[o].name.startswith("camPath") and not bpy.data.objects[o].data.get('isDefault'):
2021-02-02 12:15:11 +01:00
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" +
2021-03-01 20:05:38 +01:00
"\t0,\n" +
2021-02-02 12:15:11 +01:00
"\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")
2021-02-19 18:00:42 +01:00
else:
f.write("CAMPATH camPath = {\n" +
"\t0,\n" +
"\t0,\n" +
"\t0\n" +
"};\n\n")
2021-02-02 12:15:11 +01:00
# 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)) + "," +
2021-02-19 18:00:42 +01:00
"\t" + str(int(lightdir.y * energy))
2021-02-02 12:15:11 +01:00
)
if l != len(bpy.data.lamps) - 1:
f.write(",\n")
2021-02-19 18:00:42 +01:00
2021-02-02 12:15:11 +01:00
if pad:
2021-02-19 18:00:42 +01:00
f.write(",\n")
2021-02-02 12:15:11 +01:00
while cnt < pad:
f.write("\t0,0,0")
2021-02-19 18:00:42 +01:00
if cnt != pad:
2021-02-02 12:15:11 +01:00
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")
2021-02-19 18:00:42 +01:00
actorPtr = first_mesh
levelPtr = first_mesh
propPtr = first_mesh
2021-03-12 12:13:08 +01:00
nodePtr = first_mesh
2021-02-19 18:00:42 +01:00
2021-03-12 11:21:18 +01:00
timList = []
for m in bpy.data.meshes:
# Write vertices vectors
2021-01-14 17:22:44 +01:00
# AABB : Store vertices coordinates by axis
Xvals = []
Yvals = []
Zvals = []
# remove '.' from mesh name
2021-02-19 18:00:42 +01:00
cleanName = CleanName(m.name)
# ~ cleanName = m.name.replace('.','_')
# ~ cleanName = unicodedata.normalize('NFKD',cleanName).encode('ASCII', 'ignore').decode()
2021-01-14 17:22:44 +01:00
f.write("SVECTOR "+"model"+cleanName+"_mesh[] = {\n")
for i in range(len(m.vertices)):
v = m.vertices[i].co
2021-01-14 17:22:44 +01:00
# AABB : append vertices coords by axis
Xvals.append(v.x)
Yvals.append(v.y)
2021-02-02 12:15:11 +01:00
Zvals.append(-v.z)
2021-01-14 17:22:44 +01:00
2021-02-02 12:15:11 +01:00
f.write("\t{"+str(round(v.x*scale))+","+str(round(-v.z*scale)) + "," + str(round(v.y*scale)) +"}")
2021-01-14 17:22:44 +01:00
if i != len(m.vertices) - 1:
f.write(",")
f.write("\n")
f.write("};\n\n")
# Write normals vectors
2021-01-14 17:22:44 +01:00
f.write("SVECTOR "+"model"+cleanName+"_normal[] = {\n")
2021-02-02 12:15:11 +01:00
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")
2021-02-19 18:00:42 +01:00
if i != len(m.vertices) - 1:
f.write(",")
f.write("\n")
f.write("};\n\n")
2020-12-30 11:23:36 +01:00
# Write UVs vectors if a texture exists
# get name of texture image https://docs.blender.org/api/2.79b/bpy.types.Image.html#bpy.types.Image
# bpy.context.active_object.data.uv_textures.active.data[0].image.name
# bpy.context.active_object.data.uv_textures.active.data[0].image.filepath
# bpy.context.active_object.data.uv_textures.active.data[0].image.filepath_from_user()
#
# get image size x, y
# print(bpy.data.meshes[0].uv_textures[0].data[0].image.size[0]) # x
# print(bpy.data.meshes[0].uv_textures[0].data[0].image.size[1]) # y
2021-03-01 20:05:38 +01:00
2021-02-19 18:00:42 +01:00
if len(m.uv_textures) != None:
2021-01-04 18:28:27 +01:00
for t in range(len(m.uv_textures)):
if m.uv_textures[t].data[0].image != None:
2021-01-14 17:22:44 +01:00
f.write("SVECTOR "+"model"+cleanName+"_uv[] = {\n")
2021-01-04 18:28:27 +01:00
texture_image = m.uv_textures[t].data[0].image
tex_width = texture_image.size[0]
tex_height = texture_image.size[1]
uv_layer = m.uv_layers[0].data
for i in range(len(uv_layer)):
u = uv_layer[i].uv
ux = u.x * tex_width
uy = u.y * tex_height
2021-03-12 11:21:18 +01:00
# ~ if self.exp_Precalc and m.get('isBG'):
# ~ f.write("\t255, 255, 0, 0") # Clamp values to 0-255 to avoid tpage overflow
# ~ else:
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
2021-01-04 18:28:27 +01:00
if i != len(uv_layer) - 1:
f.write(",")
f.write("\n")
f.write("};\n\n")
2021-02-19 18:00:42 +01:00
# save uv tex if needed - still have to convert them to tim...
if texture_image.filepath == '':
2021-03-01 20:05:38 +01:00
os.makedirs(dirpath, exist_ok = 1)
texture_image.filepath_raw = folder + os.sep + "TIM" + os.sep + CleanName(texture_image.name) + "." + texture_image.file_format
2021-02-19 18:00:42 +01:00
texture_image.save()
# Write vertex colors vectors
2021-01-14 17:22:44 +01:00
f.write("CVECTOR "+"model"+cleanName+"_color[] = {\n")
# If vertex colors exist, use them
if len(m.vertex_colors) != 0:
2020-12-30 22:09:12 +01:00
colors = m.vertex_colors[0].data
for i in range(len(colors)):
f.write("\t"+str(int(colors[i].color.r*255))+","+str(int(colors[i].color.g*255))+","+str(int(colors[i].color.b*255))+", 0")
if i != len(colors) - 1:
f.write(",")
f.write("\n")
# If no vertex colors, default to 2 whites, 1 grey
else:
for i in range(len(m.polygons) * 3):
if i % 3 == 0:
2020-12-30 11:23:36 +01:00
f.write("\t80,80,80,0") # Let's add a bit more relief with a shade of grey
else:
2020-12-30 11:23:36 +01:00
f.write("\t128,128,128,0")
if i != (len(m.polygons) * 3) - 1:
f.write(",")
f.write("\n")
f.write("};\n\n")
2021-02-19 18:00:42 +01:00
# Write polygons index + type
f.write("PRIM "+"model"+cleanName+"_index[] = {\n")
for i in range(len(m.polygons)):
poly = m.polygons[i]
f.write("\t"+str(poly.vertices[0])+","+str(poly.vertices[1])+","+str(poly.vertices[2]))
2021-02-19 18:00:42 +01:00
if len(poly.vertices) > 3:
f.write("," + str(poly.vertices[3]) + ",8")
else:
f.write(",0,4")
if i != len(m.polygons) - 1:
f.write(",")
f.write("\n")
f.write("};\n\n")
2021-02-02 12:15:11 +01:00
# get custom properties isRigidBody, isPrism, isAnim
chkProp = {
'isAnim':0,
'isRigidBody':0,
2021-02-19 18:00:42 +01:00
'isStaticBody':0,
2021-02-02 12:15:11 +01:00
'isPrism':0,
2021-02-19 18:00:42 +01:00
'isActor':0,
'isLevel':0,
2021-03-01 20:05:38 +01:00
'isBG':0,
2021-02-19 18:00:42 +01:00
'mass': 1,
2021-03-01 20:05:38 +01:00
'restitution': 0,
'lerp': 0
2021-02-02 12:15:11 +01:00
}
for prop in chkProp:
if m.get(prop) is not None:
chkProp[prop] = m[prop]
2021-03-12 11:21:18 +01:00
# put isBG back to 0 if using precalculated BGs
if not self.exp_Precalc:
chkProp['isBG'] = 0;
2021-02-19 18:00:42 +01:00
if m.get('isActor'):
actorPtr = cleanName
if m.get('isLevel'):
levelPtr = cleanName
if m.get('isProp'):
propPtr = cleanName
2021-03-12 12:13:08 +01:00
if m.get('isLevel'):
nodePtr = cleanName
2021-02-02 12:15:11 +01:00
# 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
2021-02-19 18:00:42 +01:00
2021-02-02 12:15:11 +01:00
o = bpy.data.objects[m.name]
2021-03-01 20:05:38 +01:00
# ~ frame_start = bpy.context.scene.frame_start
frame_start = int(bpy.data.actions[m.name].frame_range[0])
# ~ frame_end = bpy.context.scene.frame_end
frame_end = int(bpy.data.actions[m.name].frame_range[1])
2021-02-02 12:15:11 +01:00
nFrame = frame_end - frame_start
c = 0;
tmp_meshes = []
2021-03-01 20:05:38 +01:00
for i in range(frame_start, frame_end):
2021-02-02 12:15:11 +01:00
bpy.context.scene.frame_set(i)
bpy.context.scene.update()
nm = o.to_mesh(bpy.context.scene, True, 'PREVIEW')
2021-02-19 18:00:42 +01:00
2021-02-02 12:15:11 +01:00
if i == 0 :
2021-02-19 18:00:42 +01:00
f.write("VANIM model"+cleanName+"_anim = {\n" +
2021-02-02 12:15:11 +01:00
"\t" + str(nFrame) + ",\n" +
"\t" + str(len(nm.vertices)) + ",\n" +
2021-03-01 20:05:38 +01:00
"\t0,\n" +
"\t0,\n" +
"\t1,\n" +
"\t" + str(chkProp['lerp']) + ",\n" +
2021-02-02 12:15:11 +01:00
"\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)) + " }")
2021-03-01 20:05:38 +01:00
if c != len(nm.vertices) * (nFrame) * 3 - 3:
2021-02-02 12:15:11 +01:00
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)
2021-02-19 18:00:42 +01:00
f.write("\n\t}\n};\n")
2021-02-02 12:15:11 +01:00
for nm in tmp_meshes:
bpy.data.meshes.remove(nm)
2021-02-19 18:00:42 +01:00
2021-02-02 12:15:11 +01:00
#Stuff # ~ bpy.data.objects[bpy.data.meshes[0].name].active_shape_key.value : access shape_key
2021-01-04 18:28:27 +01:00
#write object matrix, rot and pos vectors
2021-01-14 17:22:44 +01:00
f.write("MATRIX model"+cleanName+"_matrix = {0};\n" +
2021-02-02 12:15:11 +01:00
"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" +
2021-03-12 11:21:18 +01:00
"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" +
2021-03-01 20:05:38 +01:00
"short model"+cleanName+"_isRigidBody = " + str(int(chkProp['isRigidBody'])) + ";\n" +
"short model"+cleanName+"_isStaticBody = " + str(int(chkProp['isStaticBody'])) + ";\n" +
"short model"+cleanName+"_isPrism = " + str(int(chkProp['isPrism'])) + ";\n" +
"short model"+cleanName+"_isAnim = " + str(int(chkProp['isAnim'])) + ";\n" +
"short model"+cleanName+"_isActor = " + str(int(chkProp['isActor'])) + ";\n" +
"short model"+cleanName+"_isLevel = " + str(int(chkProp['isLevel'])) + ";\n" +
"short model"+cleanName+"_isBG = " + str(int(chkProp['isBG'])) + ";\n" +
2021-01-14 17:22:44 +01:00
"long model"+cleanName+"_p = 0;\n" +
2021-03-01 20:05:38 +01:00
"long model"+cleanName+"_OTz = 0;\n" +
2021-01-14 17:22:44 +01:00
"BODY model"+cleanName+"_body = {\n" +
2021-02-19 18:00:42 +01:00
"\t{0, 0, 0, 0},\n" +
2021-02-02 12:15:11 +01:00
"\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" +
2021-03-01 20:05:38 +01:00
"\t" + str(int(chkProp['mass'])) + ",\n" +
2021-02-19 18:00:42 +01:00
"\tONE/" + str(int(chkProp['mass'])) + ",\n" +
2021-01-14 17:22:44 +01:00
# write min and max values of AABBs on each axis
2021-02-02 12:15:11 +01:00
"\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" +
2021-02-19 18:00:42 +01:00
"\t" + str(int(chkProp['restitution'])) + "\n" +
2021-01-14 17:22:44 +01:00
"\t};\n\n")
2021-01-04 18:28:27 +01:00
# Write TMESH struct
2021-01-14 17:22:44 +01:00
f.write("TMESH "+"model"+cleanName+" = {\n")
f.write("\t"+"model"+cleanName+"_mesh, \n")
f.write("\t"+"model"+cleanName+"_normal,\n")
2020-12-30 22:09:12 +01:00
2021-02-19 18:00:42 +01:00
if len(m.uv_textures) != None:
2021-01-04 18:28:27 +01:00
for t in range(len(m.uv_textures)):
if m.uv_textures[0].data[0].image != None:
2021-01-14 17:22:44 +01:00
f.write("\t"+"model"+cleanName+"_uv,\n")
2021-02-19 18:00:42 +01:00
else:
f.write("\t0,\n")
2020-12-30 11:23:36 +01:00
else:
f.write("\t0,\n")
2020-12-30 22:09:12 +01:00
2021-01-14 17:22:44 +01:00
f.write("\t"+"model"+cleanName+"_color, \n")
# According to libgte.h, TMESH.len should be # of vertices. Meh...
f.write("\t"+str(len(m.polygons))+"\n")
f.write("};\n\n")
# write texture binary name and declare TIM_IMAGE
# by default, load the file from the TIM folder
2020-12-30 22:09:12 +01:00
# ~ if len(m.uv_textures) != 0:
2021-03-12 11:21:18 +01:00
2021-02-19 18:00:42 +01:00
if len(m.uv_textures) != None:
2021-01-04 18:28:27 +01:00
for t in range(len(m.uv_textures)):
if m.uv_textures[0].data[0].image != None:
2021-03-12 11:21:18 +01:00
2021-01-04 18:28:27 +01:00
tex_name = texture_image.name
prefix = str.partition(tex_name, ".")[0].replace('-','_')
2021-02-19 18:00:42 +01:00
prefix = CleanName(prefix)
2021-03-12 11:21:18 +01:00
# add Tex name to array if !exist
if prefix in timList:
break
else:
f.write("extern unsigned long "+"_binary_TIM_" + prefix + "_tim_start[];\n")
f.write("extern unsigned long "+"_binary_TIM_" + prefix + "_tim_end[];\n")
f.write("extern unsigned long "+"_binary_TIM_" + prefix + "_tim_length;\n\n")
f.write("TIM_IMAGE tim_" + prefix + ";\n\n")
timList.append(prefix)
2021-01-14 17:22:44 +01:00
f.write("MESH mesh"+cleanName+" = {\n")
f.write("\t&model"+ cleanName +",\n")
f.write("\tmodel" + cleanName + "_index,\n")
2020-12-30 22:09:12 +01:00
2021-02-19 18:00:42 +01:00
if len(m.uv_textures) != None:
2021-01-04 18:28:27 +01:00
for t in range(len(m.uv_textures)):
if m.uv_textures[0].data[0].image != None:
2021-03-12 11:21:18 +01:00
tex_name = texture_image.name
prefix = str.partition(tex_name, ".")[0].replace('-','_')
prefix = CleanName(prefix)
2021-01-04 18:28:27 +01:00
f.write("\t&tim_"+ prefix + ",\n")
2021-02-19 18:00:42 +01:00
f.write("\t_binary_TIM_" + prefix + "_tim_start,\n")
else:
f.write("\t0,\n" +
"\t0,\n")
2020-12-30 22:09:12 +01:00
else:
2021-01-04 18:28:27 +01:00
f.write("\t0,\n" +
2021-02-19 18:00:42 +01:00
"\t0,\n")
2021-01-14 17:22:44 +01:00
f.write("\t&model"+cleanName+"_matrix,\n" +
"\t&model"+cleanName+"_pos,\n" +
"\t&model"+cleanName+"_rot,\n" +
"\t&model"+cleanName+"_isRigidBody,\n" +
2021-02-19 18:00:42 +01:00
"\t&model"+cleanName+"_isStaticBody,\n" +
2021-01-14 17:22:44 +01:00
"\t&model"+cleanName+"_isPrism,\n" +
2021-02-02 12:15:11 +01:00
"\t&model"+cleanName+"_isAnim,\n" +
2021-02-19 18:00:42 +01:00
"\t&model"+cleanName+"_isActor,\n" +
"\t&model"+cleanName+"_isLevel,\n" +
2021-03-01 20:05:38 +01:00
"\t&model"+cleanName+"_isBG,\n" +
2021-02-02 12:15:11 +01:00
"\t&model"+cleanName+"_p,\n" +
2021-03-01 20:05:38 +01:00
"\t&model"+cleanName+"_OTz,\n" +
2021-02-02 12:15:11 +01:00
"\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")
2021-01-04 18:28:27 +01:00
2020-12-30 11:23:36 +01:00
f.write("};\n\n")
f.write("MESH * meshes[" + str(len(bpy.data.meshes)) + "] = {\n")
2021-02-19 18:00:42 +01:00
for k in range(len(bpy.data.meshes)):
2021-03-12 11:21:18 +01:00
2021-02-19 18:00:42 +01:00
cleanName = CleanName(bpy.data.meshes[k].name)
f.write("\t&mesh" + cleanName)
2021-03-12 11:21:18 +01:00
2020-12-30 11:23:36 +01:00
if k != len(bpy.data.meshes) - 1:
f.write(",\n")
f.write("\n}; \n")
2021-03-01 20:05:38 +01:00
# nothing in camAngles, use default camera
if not camAngles:
f.write("CAMANGLE camAngle_" + CleanName(defaultCam) + " = {\n" +
"\t&camPos_" + CleanName(defaultCam) + ",\n" +
"\t0,\n" +
"\t0\n" +
"};\n\n")
# cam angles is populated
for o in camAngles:
prefix = CleanName(o.name)
# include Tim data
f.write("extern unsigned long "+"_binary_TIM_bg_" + prefix + "_tim_start[];\n")
f.write("extern unsigned long "+"_binary_TIM_bg_" + prefix + "_tim_end[];\n")
f.write("extern unsigned long "+"_binary_TIM_bg_" + prefix + "_tim_length;\n\n")
# write corresponding TIM_IMAGE struct
f.write("TIM_IMAGE tim_bg_" + prefix + ";\n\n")
# write corresponding CamAngle struct
f.write("CAMANGLE camAngle_" + prefix + " = {\n" +
"\t&camPos_" + prefix + ",\n" +
"\t&tim_bg_" + prefix + ",\n" +
"\t_binary_TIM_bg_" + prefix + "_tim_start\n" +
"};\n\n")
# write cam angles array for loops
f.write("CAMANGLE * camAngles[" + str(len(camAngles)) + "] = {\n")
for o in camAngles:
prefix = CleanName(o.name)
f.write("\t&camAngle_" + prefix + ",\n")
f.write("};\n\n")
2020-12-30 11:23:36 +01:00
2021-03-01 20:05:38 +01:00
2021-02-19 18:00:42 +01:00
f.write("MESH * actorPtr = &mesh" + actorPtr + ";\n")
f.write("MESH * levelPtr = &mesh" + levelPtr + ";\n")
2021-03-01 20:05:38 +01:00
f.write("MESH * propPtr = &mesh" + propPtr + ";\n\n")
2021-02-19 18:00:42 +01:00
2021-03-01 20:05:38 +01:00
f.write("CAMANGLE * camPtr = &camAngle_" + CleanName(defaultCam) + ";\n\n")
2021-03-12 11:21:18 +01:00
2021-03-12 12:13:08 +01:00
f.write("NODE * curNode = &node_" + nodePtr + ";\n\n")
2021-03-12 11:21:18 +01:00
# set default cam back
if defaultCam != 'NULL':
bpy.context.scene.camera = bpy.data.objects[defaultCam]
f.close()
return {'FINISHED'};
def menu_func(self, context):
self.layout.operator(ExportMyFormat.bl_idname, text="PSX Format(.c)");
def register():
bpy.utils.register_module(__name__);
bpy.types.INFO_MT_file_export.append(menu_func);
def unregister():
bpy.utils.unregister_module(__name__);
bpy.types.INFO_MT_file_export.remove(menu_func);
if __name__ == "__main__":
register()