2020-12-27 17:13:58 +01:00
|
|
|
import os
|
|
|
|
import bpy
|
|
|
|
|
|
|
|
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"
|
|
|
|
}
|
|
|
|
|
|
|
|
import bpy
|
|
|
|
from bpy_extras.io_utils import ExportHelper
|
|
|
|
|
|
|
|
class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|
|
|
bl_idname = "export_psx.c";
|
|
|
|
bl_label = "PSX compatible format exporter";
|
|
|
|
bl_options = {'PRESET'};
|
|
|
|
filename_ext = ".c";
|
|
|
|
|
|
|
|
def execute(self, context):
|
2020-12-30 22:09:12 +01:00
|
|
|
import bmesh
|
|
|
|
|
|
|
|
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()
|
2020-12-29 15:01:44 +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
|
|
|
|
for m in range(len(bpy.data.objects)):
|
|
|
|
if bpy.data.objects[m].type == 'MESH':
|
|
|
|
triangulate_object(bpy.data.objects[m])
|
|
|
|
|
|
|
|
scale = 120
|
2020-12-27 17:13:58 +01:00
|
|
|
f = open(os.path.normpath(self.filepath),"w+")
|
2020-12-30 11:23:36 +01:00
|
|
|
|
|
|
|
# write typedef struct
|
|
|
|
f.write("typedef struct { \n"+
|
|
|
|
"\tTMESH * tmesh;\n" +
|
|
|
|
"\tint * index;\n" +
|
2020-12-30 22:09:12 +01:00
|
|
|
"\tTIM_IMAGE * tim; \n" +
|
2020-12-30 11:23:36 +01:00
|
|
|
"\tu_long * tim_data;\n"
|
|
|
|
"\t} MESH;\n\n")
|
|
|
|
|
2020-12-27 17:13:58 +01:00
|
|
|
for m in bpy.data.meshes:
|
|
|
|
|
2020-12-29 15:01:44 +01:00
|
|
|
# Write vertices vectors
|
|
|
|
|
2020-12-27 17:13:58 +01:00
|
|
|
f.write("SVECTOR "+"model"+m.name+"_mesh[] = {\n")
|
|
|
|
for i in range(len(m.vertices)):
|
|
|
|
v = m.vertices[i].co
|
|
|
|
f.write("\t{"+str(v.x*scale)+","+str(v.y*scale)+","+str(v.z*scale)+"}")
|
|
|
|
if i != len(m.vertices) - 1:
|
|
|
|
f.write(",")
|
|
|
|
f.write("\n")
|
|
|
|
f.write("};\n\n")
|
2020-12-29 15:01:44 +01:00
|
|
|
|
|
|
|
# Write normals vectors
|
2020-12-27 17:13:58 +01:00
|
|
|
|
|
|
|
f.write("SVECTOR "+"model"+m.name+"_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")
|
|
|
|
if i != len(m.polygons) - 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
|
|
|
|
|
2020-12-29 15:01:44 +01:00
|
|
|
# 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
|
2020-12-30 22:09:12 +01:00
|
|
|
if m.uv_textures[0].data[0].image != None:
|
2020-12-30 11:23:36 +01:00
|
|
|
f.write("SVECTOR "+"model"+m.name+"_uv[] = {\n")
|
2020-12-30 22:09:12 +01:00
|
|
|
texture_image = m.uv_textures[0].data[0].image
|
2020-12-30 11:23:36 +01:00
|
|
|
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
|
|
|
|
f.write("\t"+str(ux)+","+str(tex_height - uy)+", 0, 0")
|
|
|
|
if i != len(uv_layer) - 1:
|
|
|
|
f.write(",")
|
|
|
|
f.write("\n")
|
|
|
|
f.write("};\n\n")
|
|
|
|
|
2020-12-29 15:01:44 +01:00
|
|
|
# Write vertex colors vectors
|
|
|
|
|
|
|
|
f.write("CVECTOR "+"model"+m.name+"_color[] = {\n")
|
2020-12-27 17:13:58 +01:00
|
|
|
# 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
|
2020-12-27 17:13:58 +01:00
|
|
|
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
|
2020-12-27 17:13:58 +01:00
|
|
|
else:
|
2020-12-30 11:23:36 +01:00
|
|
|
f.write("\t128,128,128,0")
|
2020-12-27 17:13:58 +01:00
|
|
|
if i != (len(m.polygons) * 3) - 1:
|
|
|
|
f.write(",")
|
|
|
|
f.write("\n")
|
|
|
|
f.write("};\n\n")
|
2020-12-29 15:01:44 +01:00
|
|
|
|
|
|
|
# Write polygons index
|
2020-12-27 17:13:58 +01:00
|
|
|
f.write("int "+"model"+m.name+"_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]))
|
|
|
|
if i != len(m.polygons) - 1:
|
|
|
|
f.write(",")
|
|
|
|
f.write("\n")
|
|
|
|
f.write("};\n\n")
|
|
|
|
|
2020-12-29 15:01:44 +01:00
|
|
|
# Write TMESH struct
|
2020-12-27 17:13:58 +01:00
|
|
|
f.write("TMESH "+"model"+m.name+" = {\n")
|
2020-12-30 11:23:36 +01:00
|
|
|
f.write("\t"+"model"+m.name+"_mesh, \n")
|
2020-12-27 17:13:58 +01:00
|
|
|
f.write("\t"+"model"+m.name+"_normal,\n")
|
2020-12-30 22:09:12 +01:00
|
|
|
|
|
|
|
if m.uv_textures[0].data[0].image != None:
|
2020-12-30 11:23:36 +01:00
|
|
|
f.write("\t"+"model"+m.name+"_uv,\n")
|
|
|
|
else:
|
|
|
|
f.write("\t0,\n")
|
2020-12-30 22:09:12 +01:00
|
|
|
|
2020-12-30 11:23:36 +01:00
|
|
|
f.write("\t"+"model"+m.name+"_color, \n")
|
2020-12-29 15:01:44 +01:00
|
|
|
|
2020-12-27 17:13:58 +01:00
|
|
|
# According to libgte.h, TMESH.len should be # of vertices. Meh...
|
|
|
|
f.write("\t"+str(len(m.polygons))+"\n")
|
2020-12-29 15:01:44 +01:00
|
|
|
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:
|
|
|
|
if m.uv_textures[0].data[0].image != None:
|
2020-12-30 11:23:36 +01:00
|
|
|
tex_name = texture_image.name
|
2020-12-30 22:09:12 +01:00
|
|
|
prefix = str.partition(tex_name, ".")[0].replace('-','_')
|
2020-12-30 11:23:36 +01:00
|
|
|
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")
|
2020-12-29 15:01:44 +01:00
|
|
|
|
2020-12-30 11:23:36 +01:00
|
|
|
f.write("MESH mesh"+m.name+" = {\n")
|
|
|
|
f.write("\t&model"+ m.name +",\n")
|
|
|
|
f.write("\tmodel" + m.name + "_index,\n")
|
2020-12-30 22:09:12 +01:00
|
|
|
|
|
|
|
if m.uv_textures[0].data[0].image != None:
|
|
|
|
f.write("\t&tim_"+ prefix + ",\n")
|
|
|
|
f.write("\t_binary_TIM_" + prefix + "_tim_start\n")
|
|
|
|
else:
|
|
|
|
f.write("0,\n" +
|
|
|
|
"0,\n")
|
|
|
|
|
2020-12-30 11:23:36 +01:00
|
|
|
f.write("};\n\n")
|
|
|
|
|
|
|
|
f.write("MESH * meshes[" + str(len(bpy.data.meshes)) + "] = {\n")
|
|
|
|
for k in range(len(bpy.data.meshes)):
|
|
|
|
f.write("\t&mesh" + bpy.data.meshes[k].name)
|
|
|
|
if k != len(bpy.data.meshes) - 1:
|
|
|
|
f.write(",\n")
|
|
|
|
f.write("\n}; \n")
|
|
|
|
|
2020-12-27 17:13:58 +01:00
|
|
|
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()
|