From 0adfd9cc302d78738f63037145e65bf1dd1a47fa Mon Sep 17 00:00:00 2001 From: TigerKat Date: Thu, 12 Sep 2019 14:42:12 +0930 Subject: [PATCH] Added support for Blender 2.80 --- __init__.py | 40 +++++++++++++++++----- export_geo.py | 93 +++++++++++++++++++++++++++++++++++++-------------- import_geo.py | 32 ++++++++++++++++++ 3 files changed, 131 insertions(+), 34 deletions(-) diff --git a/__init__.py b/__init__.py index eef6f21..0c83161 100644 --- a/__init__.py +++ b/__init__.py @@ -2,8 +2,8 @@ bl_info = { "name": "City of Heroes (.geo)", "author": "TigerKat", - "version": (0, 1, 3), - "blender": (2, 79, 0), + "version": (0, 2, 0), + "blender": (2, 80, 0), "location": "File > Import/Export,", "description": "City of Heroes (.geo)", "tracker_url": "https://git.ourodev.com/tigerkat/geopy/issues", @@ -107,15 +107,39 @@ def menu_func_export(self, context): self.layout.operator(ExportGeoMetric.bl_idname, text="City of Heroes (Meters) (.geo)") +def make_annotations(cls): + """Converts class fields to annotations if running with Blender 2.8""" + if bpy.app.version < (2, 80): + return cls + bl_props = {k: v for k, v in cls.__dict__.items() if isinstance(v, tuple)} + if bl_props: + if '__annotations__' not in cls.__dict__: + setattr(cls, '__annotations__', {}) + annotations = cls.__dict__['__annotations__'] + for k, v in bl_props.items(): + annotations[k] = v + delattr(cls, k) + return cls +classes = ( + ImportGeo, + ImportGeoMetric, + ExportGeo, + ExportGeoMetric + ) def register(): - bpy.utils.register_module(__name__) - bpy.types.INFO_MT_file_import.append(menu_func_import) - bpy.types.INFO_MT_file_export.append(menu_func_export) + #bpy.utils.register_module(__name__) + for cls in classes: + make_annotations(cls) + bpy.utils.register_class(cls) + bpy.types.TOPBAR_MT_file_import.append(menu_func_import) + bpy.types.TOPBAR_MT_file_export.append(menu_func_export) def unregister(): - bpy.utils.unregister_module(__name__) - bpy.types.INFO_MT_file_import.remove(menu_func_import) - bpy.types.INFO_MT_file_export.remove(menu_func_export) + #bpy.utils.unregister_module(__name__) + for cls in reversed(classes): + bpy.utils.unregister_class(cls) + bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) + bpy.types.TOPBAR_MT_file_export.remove(menu_func_export) if __name__ == "__main__": register() diff --git a/export_geo.py b/export_geo.py index 822d216..401ee32 100644 --- a/export_geo.py +++ b/export_geo.py @@ -6,41 +6,75 @@ import bpy from bpy_extras.io_utils import axis_conversion def convert_mesh(geo_model, mesh, obj): - # Be sure tessface & co are available! - if not mesh.tessfaces and mesh.polygons: - mesh.calc_tessface() + if bpy.app.version < (2, 80): + # Be sure tessface & co are available! + if not mesh.tessfaces and mesh.polygons: + mesh.calc_tessface() + else: + # Be sure tessellated loop trianlges are available! + if not mesh.loop_triangles and mesh.polygons: + mesh.calc_loop_triangles() mesh_verts = mesh.vertices # save a lookup - has_uv = bool(mesh.tessface_uv_textures) - if has_uv: - active_uv_layer = mesh.tessface_uv_textures.active - if not active_uv_layer: - has_uv = False - else: - active_uv_layer = active_uv_layer.data + if bpy.app.version < (2, 80): + has_uv = bool(mesh.tessface_uv_textures) + if has_uv: + active_uv_layer = mesh.tessface_uv_textures.active + if not active_uv_layer: + has_uv = False + else: + active_uv_layer = active_uv_layer.data + else: + has_uv = bool(mesh.uv_layers) + if has_uv: + active_uv_layer = mesh.uv_layers.active + if not active_uv_layer: + has_uv = False + else: + active_uv_layer = active_uv_layer.data geomesh = GeoMesh() - texture_name = "white" - print("len(mesh.tessfaces): %s" % len(mesh.tessfaces)) - print("mesh.tessfaces: %s" % repr(mesh.tessfaces)) - for i, f in enumerate(mesh.tessfaces): + texture_name = "white.tga" + if bpy.app.version < (2, 80): + faces = mesh.tessfaces + print("len(mesh.tessfaces): %s" % len(faces)) + print("mesh.tessfaces: %s" % repr(faces)) + else: + faces = mesh.loop_triangles + for i, f in enumerate(faces): if has_uv: uv = active_uv_layer[i] - texture_image = uv.image - uv = [uv.uv1, uv.uv2, uv.uv3, uv.uv4] - if texture_image is None: - texture_name = "white" + if bpy.app.version < (2, 80): + texture_image = uv.image + if texture_image is None: + texture_name = "white.tga" + else: + texture_name = texture_image.name + if texture_name == "": + texture_name = bpy.path.display_name_from_filepath(texture_image.filepath) + if texture_name == "": + texture_name = "white.tga" + else: + mat = mesh.materials[f.material_index] + if len(mat.texture_paint_images) <= 0: + texture_name = mat.name + else: + texture_image = mat.texture_paint_images[0] + texture_name = texture_image.name + if texture_name == "": + texture_name = bpy.path.display_name_from_filepath(texture_image.filepath) + if texture_name == "": + texture_name = "white.tga" + if bpy.app.version < (2, 80): + uv = [uv.uv1, uv.uv2, uv.uv3, uv.uv4] else: - texture_name = texture_image.name - if texture_name == "": - texture_name = bpy.path.display_name_from_filepath(texture_image.filepath) - if texture_name == "": - texture_name = "white" + print("uv.uv: %s" % uv.uv) + uv = [active_uv_layer[l].uv[:] for l in f.loops] else: uv = [(0, 0)] * 4 - texture_name = "white" + texture_name = "white.tga" f_verts = f.vertices verts = [] norms = [] @@ -55,6 +89,7 @@ def convert_mesh(geo_model, mesh, obj): group = obj.vertex_groups[weight.group] w = [group.name, weight.weight] weights.append(w) + print("i: %s f_verts: %s uv: %s" % (i, repr(f_verts), repr(uv))) gv = GeoVertex(v.co, v.normal, uv[i], weights) geoverts.append(gv) geomesh.addFace(geoverts, texture_name) @@ -90,7 +125,10 @@ def save(operator, context, scale = 1.0, filepath = "", global_matrix = None, us global_matrix = Matrix() # get the modifiers - mesh = ob.to_mesh(bpy.context.scene, use_mesh_modifiers, "PREVIEW") + if bpy.app.version < (2, 80): + mesh = ob.to_mesh(bpy.context.scene, use_mesh_modifiers, "PREVIEW") + else: + mesh = ob.to_mesh(preserve_all_data_layers = True) #translate_matrix = Matrix.Translation(-ob.location) translate_matrix = Matrix() @@ -101,7 +139,10 @@ def save(operator, context, scale = 1.0, filepath = "", global_matrix = None, us print("obj_scale: %s final_scale: %s" % (obj_scale, obj_scale * scale)) print(obj_scale * scale) scale_matrix = Matrix.Scale(obj_scale * scale, 4) - mesh.transform(global_matrix * scale_matrix * translate_matrix * axis_rotation) + if bpy.app.version < (2, 80): + mesh.transform(global_matrix * scale_matrix * translate_matrix * axis_rotation) + else: + mesh.transform(global_matrix @ scale_matrix @ translate_matrix @ axis_rotation) mesh.calc_normals() diff --git a/import_geo.py b/import_geo.py index 8b13789..42162fe 100644 --- a/import_geo.py +++ b/import_geo.py @@ -1 +1,33 @@ +def convert_model(geo_model, mesh, obj): + #Create vertices + #todo: populate coordinates + #todo: populate normals + #todo: create edges + #todo: create faces + #todo: populate uvs + mesh.validate() + mesh.update() + #todo: attempt to load textures/images + + +def load(operator, context, scale = 1.0, filepath = "", global_matrix = None, use_mesh_modifiers = True): + #load .geo + fh_in = open(filepath, "rb") + geo = Geo() + geo.loadFromFile(fh_in) + fh_in.close() + for geo_model in geo.models: + #create object matching model's name (or next equivilant) + mesh = bpy.data.meshes.new(name = model.name.decode("utf-8")) + #convert model to mesh + convert_mode(geo_model, mesh, None) + #Create object for this mesh + scn = bpy.context.scene + + obj = bpy.data.objects.new(ply_name, mesh) + scn.objects.link(obj) + scn.objects.active = obj + obj.select = True + pass + pass