From f3e040230772f978540a71aea43dfde200992922 Mon Sep 17 00:00:00 2001 From: "John Wilbert M. Villamor" Date: Sat, 6 Apr 2019 10:11:07 +0800 Subject: First commit --- tools/plugin/io_export_smx_v3.py | 320 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 tools/plugin/io_export_smx_v3.py (limited to 'tools/plugin') diff --git a/tools/plugin/io_export_smx_v3.py b/tools/plugin/io_export_smx_v3.py new file mode 100644 index 0000000..22c38b6 --- /dev/null +++ b/tools/plugin/io_export_smx_v3.py @@ -0,0 +1,320 @@ +# This plugin is part of Scarlet Engine (formerly Project Scarlet) +# +# It is still a work in progress and the SMX file specification may change +# in future versions. + +""" +This script exports Scarlet Game Engine SDK compatible SMX files. +Supports normals, colors and texture mapped triangles. +Only one object can be exported at a time. +""" + +import os +import bpy + +from bpy.props import (CollectionProperty, + StringProperty, + BoolProperty, + EnumProperty, + FloatProperty, + ) + +from bpy_extras.io_utils import (ImportHelper, + ExportHelper, + axis_conversion, + ) + +bl_info = { + "name": "Export: Project Scarlet SMX Raw Model", + "author": "Jobert 'Lameguy' Villamor (Lameguy64)", + "blender": (2,6,9), + "version": (3,1,2), + "location": "File > Export", + "description": "Export mesh to Project Scarlet SMX model format", + "category": "Import-Export" +} + +class ExportSMX(bpy.types.Operator, ExportHelper): + + bl_idname = "export_test.smx"; + bl_label = "Export SMX"; + + filename_ext = ".smx"; + filter_glob = StringProperty(default="*.smx", options={'HIDDEN'}) + + # Export options + exp_applyModifiers = BoolProperty( + name="Apply Modifiers", + description="Apply modifiers to the exported mesh", + default=True, + ) + + exp_writeNormals = BoolProperty( + name="Normals", + description="Export normals for smooth and hard shaded faces", + default=True, + ) + + #exp_vertexWeights = BoolProperty( + # name="Vertex Weights", + # description="Export vertex weights", + # default=False, + # ) + + #exp_vertexGroups = BoolProperty( + # name="Vertex Groups", + # description="Export vertex group information", + # default=False, + # ) + + #exp_doubleSided = BoolProperty( + # name="Double-sided", + # description="Sets the double-sided attribute to all exported polygons", + # default=False, + # ) + + #exp_subsurfMode = BoolProperty( + # name="Subsurf-Mode", + # description="Enable this if the mesh you're exporting uses a subsurf divide modifier, faster but often wasteful", + # default=False, + # ) + + #exp_blendMode = EnumProperty( + # name="Semi-trans:", + # description="Sets the semi-transparency attribute for all exported polygons", + # items=(('BN', "Off", ""), + # ('B0', "0: 50%B + 50%F", ""), + # ('B1', "1: 100%B + 100%F", ""), + # ('B2', "2: 100%B - 100%F", ""), + # ('B3', "3: 100%B + 25%F", ""), + # ), + # default='BN', + # ) + + #exp_scaleFactor = FloatProperty( + # name="Scale Factor", + # description="Scale factor of exported mesh", + # min=0.01, max=1000.0, + # default=1.0, + # ) + + def execute(self, context): + + print("Export execute...\n") + + obj = context.object + mesh = obj.to_mesh(context.scene, self.exp_applyModifiers, 'PREVIEW') + + if not mesh.tessfaces and mesh.polygons: + mesh.calc_tessface() + + filepath = self.filepath + filepath = bpy.path.ensure_ext(filepath, self.filename_ext) + + with open(filepath, "w") as f: + + # Write a banner + f.write("\n") + f.write("\n") + f.write("\n") + + f.write("\n") + + # Write vertices + f.write("\n" % len(mesh.vertices)) + for v in mesh.vertices: + f.write("\n" % (v.co.x, -v.co.z, v.co.y)) + f.write("\n") + + + # Scan if there are any flat primitives + has_flats = False + for i,p in enumerate(mesh.tessfaces): + if p.use_smooth is False: + has_flats = True + break + + # Export normals + if self.exp_writeNormals: + if has_flats: + f.write("\n" % (len(mesh.vertices)+len(mesh.polygons))) + else: + f.write("\n" % (len(mesh.vertices))) + f.write("\n") + for v in mesh.vertices: + f.write("\n" % (v.normal.x, -v.normal.z, v.normal.y)) + if has_flats: + f.write("\n") + flatnorms_start = len(mesh.vertices) + for p in mesh.polygons: + f.write("\n" % (p.normal.x, -p.normal.z, p.normal.y)) + f.write("\n") + + + # Write texture files + mesh_uvs = mesh.tessface_uv_textures.active + + if mesh_uvs is not None: + mesh_uvs = mesh_uvs.data + + # Scan through all faces for assigned textures + if mesh_uvs is not None: + tex_table = [] + tex_files = [] + for uv in mesh_uvs: + if uv.image is not None: + addTex = True + texFileName = bpy.path.display_name_from_filepath(uv.image.filepath) + if len(tex_files)>0: + for c,t in enumerate(tex_files): + if t == texFileName: + tex_table.append(c+1) + addTex = False + break + if addTex: + print("TF:%s" % (texFileName)) + tex_files.append(texFileName) + tex_table.append(len(tex_files)) + else: + tex_table.append(0) + + # Write texture files + f.write("\n" % len(tex_files)) + for n in tex_files: + f.write("\n" % n) + f.write("\n") + else: + tex_table = None + tex_files = None + + + mesh_cols = mesh.tessface_vertex_colors.active + + if mesh_cols is not None: + mesh_cols = mesh_cols.data + + tri_indices = ( 0, 2, 1 ); + quad_indices = ( 3, 2, 0, 1 ); + + f.write("\n" % len(mesh.tessfaces)) + for i,p in enumerate(mesh.tessfaces): + + # Write vertex indices + f.write(" 0): + color_mul = 128.0 + else: + color_mul = 255.0 + else: + color_mul = 255.0 + + # Write out vertex colors if available + if mesh_cols is None: + f.write("r0=\"128\" g0=\"128\" b0=\"128\" ") + typecode = "F" + else: + col = mesh_cols[i] + col = col.color1[:], col.color2[:], col.color3[:], col.color4[:] + # Check if polygon is flat shaded + if (col[0] == col[1]) and (col[1] == col[2]) and (col[2] == col[0]): + # is flat... + color = col[0] + color = (int(color[0]*color_mul), + int(color[1]*color_mul), + int(color[2]*color_mul), + ) + f.write("r0=\"%d\" g0=\"%d\" b0=\"%d\" " % color[:]) + typecode = "F" + else: + # is gouraud... + for j,c in enumerate(p.vertices): + if (len(p.vertices) == 4): + color = col[quad_indices[j]] + else: + color = col[tri_indices[j]] + color = (int(color[0]*color_mul), + int(color[1]*color_mul), + int(color[2]*color_mul), + ) + f.write("r%d=\"%d\" g%d=\"%d\" b%d=\"%d\" " % + (j, color[0], j, color[1], j, color[2])) + typecode = "G" + + # Add texcoords + if tex_table is not None: + if (tex_table[i] > 0): + f.write("texture=\"%d\" " % (tex_table[i]-1)); + if (len(p.vertices) == 3): + uv = (mesh_uvs[i].uv1, + mesh_uvs[i].uv3, + mesh_uvs[i].uv2 + ) + elif (len(p.vertices) == 4): + uv = (mesh_uvs[i].uv4, + mesh_uvs[i].uv3, + mesh_uvs[i].uv1, + mesh_uvs[i].uv2 + ) + tex_w = mesh_uvs[i].image.size[0]-0.85#(1.0/mesh_uvs[i].image.size[0]) + tex_h = mesh_uvs[i].image.size[1]-0.85#(1.0-(1.0/mesh_uvs[i].image.size[1])) + for j,c in enumerate(uv): + f.write("tu%d=\"%d\" tv%d=\"%d\" " % + (j, round(tex_w*uv[j].x), j, round(tex_h-(tex_h*uv[j].y)))) + typecode += "T" + + typecode += "%d" % len(p.vertices) + f.write("type=\"%s\" " % typecode) + f.write("/>\n") + + f.write("\n") + + f.write("") + + f.close() + + return {'FINISHED'}; + +# For registering to Blender menus +def menu_func(self, context): + self.layout.operator(ExportSMX.bl_idname, text="Scarlet 3D SMX v3 (.smx)"); + +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() + # Uncomment when testing this script + #bpy.ops.export_test.smx('INVOKE_DEFAULT') \ No newline at end of file -- cgit v1.2.3