# ##### BEGIN GPL LICENSE BLOCK ##### # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License version 2 # as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ This script imports a MSH2 files to Blender. Usage: Run this script from "File->Import" menu and then load the desired MSH2 file. Note, This loads mesh objects and materials only, nurbs and curves are not supported. https://schlechtwetterfront.github.io/ze_filetypes/msh.html """ import bpy from .msh2 import msh2 msh_handler = msh2.MSH2(None) from .msh2 import msh2_unpack from .msh2 import msh2_crc class MshImportError(Exception): def __init__(self, msg): self.msg = msg def __str__(self): return str(self.msg) # class MaterialBuilder(object): # # def __init__(self, imp, msh): # self.msh = msh # self.imp = imp # # self.xsi = self.imp.xsi # # self.pb = self.imp.pb # # def build(self): # logging.info('Building {0} materials.'.format(len(self.msh.materials))) # coll = self.msh.materials # if len(coll) < 1: # logging.debug('No materials in collection.') # return () # matlib = self.xsi.ActiveProject.ActiveScene.ActiveMaterialLibrary # materials = {} # for mat in coll: # logging.info('Building Material {0}.'.format(mat.name)) # simat = matlib.CreateMaterial('Phong', mat.name) # # Colors. # shader = simat.Shaders(0) # col = shader.Parameters('diffuse').Value # col.Red = mat.diff_color.red # col.Green = mat.diff_color.green # col.Blue = mat.diff_color.blue # col.Alpha = mat.diff_color.alpha # # col = shader.Parameters('ambient').Value # col.Red = mat.ambt_color.red # col.Green = mat.ambt_color.green # col.Blue = mat.ambt_color.blue # col.Alpha = mat.ambt_color.alpha # # col = shader.Parameters('specular').Value # col.Red = mat.spec_color.red # col.Green = mat.spec_color.green # col.Blue = mat.spec_color.blue # col.Alpha = mat.spec_color.alpha # # shader.Parameters('shiny').Value = mat.gloss # # # Image. # if mat.tex0: # if self.imp.config.get('btexpath'): # imgfolder = self.imp.config.get('texpath') # else: # imgfolder = os.path.dirname(self.imp.config.get('path')) # imgshader = self.xsi.CreateShaderFromPreset('$XSI_DSPRESETS\\Shaders\\Texture\\Image.Preset', simat) # imgpath = os.path.join(imgfolder, mat.tex0) # img_clip = self.xsi.SICreateImageClip2(imgpath) # self.xsi.SIConnectShaderToCnxPoint(img_clip, imgshader.tex, False) # self.xsi.SIConnectShaderToCnxPoint(imgshader, simat.Shaders(0).Parameters('diffuse'), False) # # ZEFlags. # simat2 = self.get_si_mat(mat) # if simat2: # self.add_flag_prop(simat2, mat) # materials[mat.name] = simat # logging.info('Finished building {0}.'.format(mat.name)) # logging.info('Finished building materials.') # return materials # # def get_si_mat(self, mat): # name = mat.name # mats = self.imp.material_name_dict() # try: # mat = mats[name] # return mat # except KeyError: # logging.exception('Couldnt find material {0}.'.format(name)) # return None # # def add_flag_prop(self, simat, mat): # pset = simat.AddProperty('CustomProperty', False, 'ZeroEngine Flags') # pset.AddParameter3('tex1', const.siString, mat.tex1) # pset.AddParameter3('tex2', const.siString, mat.tex2) # pset.AddParameter3('tex3', const.siString, mat.tex3) # # if mat.flags[4][1]: # transp = 2 # elif mat.flags[5][1]: # transp = 1 # else: # transp = 0 # pset.AddParameter3('emissive', const.siBool, mat.flags[7][1], '', '', 0) # pset.AddParameter3('glow', const.siBool, mat.flags[6][1], '', '', 0) # pset.AddParameter3('transparency', const.siInt4, transp, 0, 2, 0) # pset.AddParameter3('hardedged', const.siBool, mat.flags[3][1], '', '', 0) # pset.AddParameter3('perpixel', const.siBool, mat.flags[2][1], '', '', 0) # pset.AddParameter3('additive', const.siBool, mat.flags[1][1], '', '', 0) # pset.AddParameter3('specular', const.siBool, mat.flags[0][1], '', '', 0) # pset.AddParameter3('rendertype', const.siInt4, mat.render_type, 0, 31, 0) # pset.AddParameter3('data0', const.siInt4, mat.data0, 0, 255, 0) # pset.AddParameter3('data1', const.siInt4, mat.data1, 0, 255, 0) # # lay = pset.PPGLayout # # lay.AddGroup('ZeroEngine Material Flags', 1) # lay.AddGroup('Additional Textures', 1) # lay.AddItem('tex1', 'Texture 1') # lay.AddItem('tex2', 'Texture 2') # lay.AddItem('tex3', 'Texture 3') # lay.EndGroup() # lay.AddGroup('Flags', 1) # lay.AddItem('emissive', 'Emissive') # lay.AddItem('glow', 'Glow') # lay.AddItem('transparency', 'Transparency') # lay.AddItem('hardedged', 'Hardedged Transparency') # lay.AddItem('perpixel', 'Per-Pixel Lighting') # lay.AddItem('additive', 'Additive Transparency') # lay.AddItem('specular', 'Specular') # lay.AddItem('rendertype', 'RenderType') # lay.AddItem('data0', 'Data0') # lay.AddItem('data1', 'Data1') # lay.EndGroup() # lay.EndGroup() class ChainItemBuilder: prim_types = {0: 'Sphere', 1: 'Sphere', 2: 'Cylinder', 4: 'Cube'} cloth_prim_types = {0: 'Sphere', 1: 'Cylinder', 2: 'Cube'} def __init__(self, model, chainbuilder): self.model = model # Will be set in build() after the model is built. self.si_model = None self.chainbuilder = chainbuilder self.geo = None def build(self): '''Builds an object depending on the model type.''' if 'geo' in self.model.model_type: if self.model.collprim: pass # self.build_prim() elif self.model.name.startswith(b'c_'): # and self.get_c_prim_data(): pass # self.build_c_prim() else: self.build_geo() # if self.model.model_type == 'null' or self.model.model_type == 'bone': # self.build_null() # elif self.model.model_type == 'geoshadow': # self.build_shadow() # elif 'geo' in self.model.model_type: # if self.model.collprim: # self.build_prim() # elif self.model.name.startswith('c_') and self.get_c_prim_data(): # self.build_c_prim() # else: # self.build_geo() # elif self.model.model_type == 'cloth': # self.build_cloth() # else: # raise MshImportError('Unsupported model type {0} on {1}.'.format(self.model.model_type, # self.model.name)) return self.si_model def build_geo(self): # logging.info('Building {0} as polymesh(originally {1}).'.format(self.model.name, self.model.model_type)) # verts = self.get_vertex_positions() vertices = self.get_vertex_positions() faces = self.get_faces() verts = [] edges = [] name = self.model.name.decode("utf-8") # print(verts) # print(faces) # print("") mesh2 = bpy.data.meshes.new("{}_obj".format(name)) # Add the vertices to the mesh mesh2.from_pydata(verts, edges, faces) # Create an object that uses the mesh data myobj = bpy.data.objects.new("{}".format(name), mesh2) # Link the object to the scene sceen.objects.link(myobj) # logging.info('Building {0} as polymesh(originally {1}).'.format(self.model.name, self.model.model_type)) # vertex_positions = self.get_vertex_positions() # faces = self.get_faces() # if self.model.parent_name: # parent = self.chainbuilder.name_dict[self.model.parent_name] # else: # parent = self.xsi.ActiveSceneRoot # if not parent: # logging.error('Cant find parent {0} for {1}.'.format(self.model.parent_name, # self.model.name)) # if len(vertex_positions) == 0: # logging.info('Building {0} as null (originally {1}) because no geometry information was found.'.format(self.model.name, self.model.model_type)) # self.build_null() # return # try: # with zetcore.Timer('Built polygon mesh in %ss %sms.'): # self.si_model = parent.AddPolygonMesh(vertex_positions, # faces, # self.model.name) # except com_error: # logging.exception('verts: {0}, faces: {1}, name: {2}.'.format(vertex_positions, # faces, self.model.name)) # self.imp.abort_checklog() # self.geo = self.si_model.ActivePrimitive.GetGeometry2(0) # # # if self.model.vis == 1: # # self.xsi.ToggleVisibility(self.si_model, None, None) # # self.process_normals() # self.process_uvs() # self.process_colors() # # with zetcore.Timer('Creating segments in %ss %sms.'): # if len(self.model.segments) > 1: # logging.debug('Model {0} has {1} segments, creating poly clusters.'.format(self.model.name, len(self.model.segments))) # self.create_poly_clusters() # else: # self.xsi.SIAssignMaterial(self.si_model, # self.chainbuilder.materials[self.model.segments[0].material.name]) # # self.set_transform() # self.set_vis() def get_vertex_positions(self): v_pos = [] for segment in self.model.segments: for vert in segment.vertices: v_pos.append(vert.pos) return v_pos def get_faces(self): faces = [] offset = 0 numfaces = 0 for segment in self.model.segments: for face in segment.faces: numfaces += 1 # faces.append(face.sides) sii = face.SIindices() print(sii) if len(sii) == 4: sii = (sii[0] + offset, sii[1] + offset, sii[2] + offset, sii[3] + offset) else: sii = (sii[0] + offset, sii[1] + offset, sii[2] + offset) print("") print(sii) faces.append(sii) offset += len(segment.vertices) return faces class ChainBuilder(object): def __init__(self, imp, msh, materials=None): self.msh = msh self.imp = imp self.materials = materials self.scn = bpy.context.scene self.name_dict = {} def build(self): coll = self.msh.models lencoll = len(coll) chain = [] for ind, model in enumerate(coll): builder = ChainItemBuilder(model, self) item = builder.build() self.name_dict[model.name] = item chain.append(item) return chain class Import: def __init__(self, config = None): self.msh = None self.config = config def do_import(self, path): '''Actual import function.''' unpacker = msh2_unpack.MSHUnpack(path) try: self.msh = unpacker.unpack() except (msh2_crc.CRCError, msh2_unpack.UnpackError): pass ignoregeo = False ignoreanim = True if not ignoregeo: # matbuilder = MaterialBuilder(self, self.msh) # materials = matbuilder.build() materials = {} builder = ChainBuilder(self, self.msh, materials) else: builder = ChainBuilder(self, self.msh) try: self.chain = builder.build() except MshImportError: enveloper = Enveloper(self, self.msh, self.chain) enveloper.envelope() if not self.msh.animation.empty and not ignoreanim: anim = AnimationImport(self, self.chain, self.msh.animation.bones) anim.import_() def load(context, filepath, *, files, directory, global_clamp_size=0.0, use_smooth_groups=True, use_edges=True, use_split_objects=True, use_split_groups=True, use_image_search=True, use_groups_as_vgroups=False, use_cycles=True, relpath=None, global_matrix=None ): """ Called by the user interface or another script. load_msh2(path) - should give acceptable results. This function passes the file and sends the data off to be split into objects and then converted into mesh objects """ # ZEROEDIT IMPORTER CONVERSION TO BLENDER # importer = Import() # importer.do_import(filepath) # return {'FINISHED'} # TEST IMPORT TO BLENDER msh_handler.import_file(filepath) msh = msh_handler.get_mesh_obj() sceen = bpy.context.scene # Test adding mesh2 to blender for model in msh.models: name = model.name.decode("utf-8") type = model.model_type if 'geo' in type: if model.collprim: continue # self.build_prim() elif name.startswith('c_'): # and self.get_c_prim_data(): continue # self.build_c_prim() else: # print(model) # print(model.name) # print(model.index) # print(model.collection) # print("") # Create a mesh data block mesh2 = bpy.data.meshes.new("{}_obj".format(name)) verts = [] edges = [] faces = [] offset = 0 segments = model.segments for segment in segments: if segment.classname == "SegmentGeometry": vertices = segment.vertices for vert in vertices: x = vert.x y = vert.y z = vert.z verts.append((x, y, z)) sfaces = segment.faces for face in sfaces: '''Using CCW order for importing.''' sii = face.SIindices() if len(sii) == 4: sii = (sii[0] + offset, sii[1] + offset, sii[2] + offset, sii[3] + offset) else: sii = (sii[0] + offset, sii[1] + offset, sii[2] + offset) faces.append(sii) offset += len(segment.vertices) # Add the vertices to the mesh mesh2.from_pydata(verts, edges, faces) # Create an object that uses the mesh data myobj = bpy.data.objects.new("{}".format(name), mesh2) # Link the object to the scene sceen.objects.link(myobj) return {'FINISHED'}