Initial Blender 2.8 changes - it works, now it's time for improvements

This commit is contained in:
khreathor 2019-01-08 03:02:11 +01:00 committed by Bill Currie
parent 8112c4e8b6
commit ae86790e6c
3 changed files with 119 additions and 68 deletions

View file

@ -24,14 +24,14 @@
bl_info = {
"name": "Quake MDL format",
"author": "Bill Currie",
"blender": (2, 6, 3),
"blender": (2, 80, 0),
"api": 35622,
"location": "File > Import-Export",
"description": "Import-Export Quake MDL (version 6) files. (.mdl)",
"warning": "not even alpha",
"warning": "still work in progress",
"wiki_url": "",
"tracker_url": "",
# "support": 'OFFICIAL',
# "support": 'OFFICIAL',
"category": "Import-Export"}
# To support reload properly, try to access a package var, if it's there,
@ -64,28 +64,35 @@ EFFECTS=(
('EF_TRACER2', "Tracer 2", "Orange split trail + rotate"),
('EF_TRACER3', "Tracer 3", "Purple split trail"),
)
'''
class QFMDLSettings(bpy.types.PropertyGroup):
# eyeposition = FloatVectorProperty(
# name="Eye Position",
# description="View possion relative to object origin")
# synctype = EnumProperty(
# items=SYNCTYPE,
# name="Sync Type",
# description="Add random time offset for automatic animations")
# rotate = BoolProperty(
# name="Rotate",
# description="Rotate automatically (for pickup items)")
# effects = EnumProperty(
# items=EFFECTS,
# name="Effects",
# description="Particle trail effects")
# #doesn't work :(
# #script = PointerProperty(
# # type=bpy.types.Object,
# # name="Script",
# # description="Script for animating frames and skins")
class QFMDLSettings(bpy.types.PropertyGroup):
'''
eyeposition = FloatVectorProperty(
name="Eye Position",
description="View possion relative to object origin")
synctype = EnumProperty(
items=SYNCTYPE,
name="Sync Type",
description="Add random time offset for automatic animations")
rotate = BoolProperty(
name="Rotate",
description="Rotate automatically (for pickup items)")
effects = EnumProperty(
items=EFFECTS,
name="Effects",
description="Particle trail effects")
#doesn't work :(
#script = PointerProperty(
# type=bpy.types.Object,
# name="Script",
# description="Script for animating frames and skins")
# xform = BoolProperty(
# name="Auto transform",
# description="Auto-apply location/rotation/scale when exporting",
# default=True)
# md16 = BoolProperty(
# name="16-bit",
# description="16 bit vertex coordinates: QuakeForge only")
xform = BoolProperty(
name="Auto transform",
@ -94,10 +101,10 @@ class QFMDLSettings(bpy.types.PropertyGroup):
md16 = BoolProperty(
name="16-bit",
description="16 bit vertex coordinates: QuakeForge only")
'''
script = StringProperty(
name="Script",
description="Script for animating frames and skins")
description="Script for animating frames and skins")
'''
class ImportMDL6(bpy.types.Operator, ImportHelper):
'''Load a Quake MDL (v6) File'''
@ -155,6 +162,7 @@ class ExportMDL6(bpy.types.Operator, ExportHelper):
keywords = self.as_keywords (ignore=("check_existing", "filter_glob"))
return export_mdl.export_mdl(self, context, **keywords)
'''
class OBJECT_PT_MDLPanel(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
@ -176,6 +184,7 @@ class OBJECT_PT_MDLPanel(bpy.types.Panel):
layout.prop(obj.qfmdl, "script")
layout.prop(obj.qfmdl, "xform")
layout.prop(obj.qfmdl, "md16")
'''
def menu_func_import(self, context):
self.layout.operator(ImportMDL6.bl_idname, text="Quake MDL (.mdl)")
@ -184,21 +193,25 @@ def menu_func_import(self, context):
def menu_func_export(self, context):
self.layout.operator(ExportMDL6.bl_idname, text="Quake MDL (.mdl)")
classes = (
#OBJECT_PT_MDLPanel,
ImportMDL6,
ExportMDL6
)
def register():
bpy.utils.register_module(__name__)
bpy.types.Object.qfmdl = PointerProperty(type=QFMDLSettings)
bpy.types.INFO_MT_file_import.append(menu_func_import)
bpy.types.INFO_MT_file_export.append(menu_func_export)
for cls in classes:
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__)
for cls in classes:
bpy.utils.unregister_class(cls)
bpy.types.INFO_MT_file_import.remove(menu_func_import)
bpy.types.INFO_MT_file_export.remove(menu_func_export)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
if __name__ == "__main__":
register()

View file

@ -86,7 +86,7 @@ def null_skin(size):
return skin
def active_uv(mesh):
for uvt in mesh.uv_textures:
for uvt in mesh.uv_layers:
if uvt.active:
return uvt
return None
@ -95,6 +95,18 @@ def make_skin(operator, mdl, mesh):
uvt = active_uv(mesh)
mdl.skinwidth, mdl.skinheight = (4, 4)
skin = null_skin((mdl.skinwidth, mdl.skinheight))
mat = bpy.context.object.data.materials[0]
allNodes = mat.node_tree.nodes
for node in allNodes:
if node.type == "TEX_IMAGE":
image = node.image
mdl.skinwidth, mdl.skinheight = image.size
skin = convert_image(image)
mdl.skins.append(skin)
'''
if (uvt and uvt.data and uvt.data[0].image):
image = uvt.data[0].image
if (uvt.data[0].image.size[0] and uvt.data[0].image.size[1]):
@ -103,7 +115,9 @@ def make_skin(operator, mdl, mesh):
else:
operator.report({'WARNING'},
"Texture '%s' invalid (missing?)." % image.name)
mdl.skins.append(skin)
'''
def build_tris(mesh):
# mdl files have a 1:1 relationship between stverts and 3d verts.
@ -183,7 +197,7 @@ def calc_average_area(mdl):
a = Vector(verts[0].r) - Vector(verts[1].r)
b = Vector(verts[2].r) - Vector(verts[1].r)
c = a.cross(b)
totalarea += (c * c) ** 0.5 / 2.0
totalarea += (c @ c) ** 0.5 / 2.0
return totalarea / len(mdl.tris)
def get_properties(
@ -301,7 +315,8 @@ def export_mdl(
):
obj = context.active_object
mesh = obj.to_mesh(context.scene, True, 'PREVIEW') #wysiwyg?
#mesh = obj.to_mesh(context.scene, True, 'PREVIEW') #wysiwyg?
mesh = obj.to_mesh(context.depsgraph, True, calc_undeformed=False)
#if not check_faces(mesh):
# operator.report({'ERROR'},
# "Mesh has faces with more than 3 vertices.")
@ -334,7 +349,7 @@ def export_mdl(
curframe = context.scene.frame_current
for fno in range(context.scene.frame_start, context.scene.frame_end + 1):
context.scene.frame_set(fno)
mesh = obj.to_mesh(context.scene, True, 'PREVIEW') #wysiwyg?
mesh = obj.to_mesh(context.depsgraph, True, calc_undeformed=False) #wysiwyg?
if xform:
mesh.transform(mdl.obj.matrix_world)
mdl.frames.append(make_frame(mesh, vertmap))

View file

@ -39,7 +39,7 @@ def make_verts(mdl, framenum, subframenum=0):
( 0, 0,s.z,o.z),
( 0, 0, 0, 1)))
for v in frame.verts:
verts.append(m * Vector(v.r))
verts.append(m @ Vector(v.r))
return verts
def make_faces(mdl):
@ -87,7 +87,7 @@ def load_skins(mdl):
p[l + 2] = c[2] / 255.0
p[l + 3] = 1.0
img.pixels[:] = p[:]
img.pack(True)
img.pack(as_png=True)
img.use_fake_user = True
mdl.images=[]
@ -100,27 +100,47 @@ def load_skins(mdl):
def setup_skins(mdl, uvs):
load_skins(mdl)
img = mdl.images[0] # use the first skin for now
uvlay = mdl.mesh.uv_textures.new(mdl.name)
uvloop = mdl.mesh.uv_layers[0]
for i, texpoly in enumerate(uvlay.data):
# img = mdl.images[0] # use the first skin for now
# uvlay = mdl.mesh.uv_textures.new(mdl.name)
# uvloop = mdl.mesh.uv_layers[0]
# for i, texpoly in enumerate(uvlay.data):
uvloop = mdl.mesh.uv_layers.new(name = mdl.name)
for i in range(len(mdl.mesh.polygons)):
poly = mdl.mesh.polygons[i]
mdl_uv = uvs[i]
texpoly.image = img
# texpoly.image = img # TODO: commented out by jazz
for j,k in enumerate(poly.loop_indices):
uvloop.data[k].uv = mdl_uv[j]
# Create main material
mat = bpy.data.materials.new(mdl.name)
mat.blend_method = 'OPAQUE'
mat.diffuse_color = (1,1,1)
mat.use_raytrace = False
tex = bpy.data.textures.new(mdl.name, 'IMAGE')
tex.extension = 'CLIP'
tex.use_preview_alpha = True
tex.image = img
mat.texture_slots.add()
ts = mat.texture_slots[0]
ts.texture = tex
ts.use_map_alpha = True
ts.texture_coords = 'UV'
mat.metallic = 1
mat.roughness = 1
mat.specular_intensity = 0
mat.use_nodes = True
# TODO: turn transform to True and position it properly in editor
emissionNode = mat.node_tree.nodes.new("ShaderNodeEmission")
shaderOut = mat.node_tree.nodes["Material Output"]
bdsf_node = mat.node_tree.nodes["Principled BSDF"]
mat.node_tree.nodes.remove(bdsf_node)
#Add skingroup
#bpy.ops.object.material_slot_add()
#bpy.ops.material.new()
#Add all existing textures to shader node
for i in range(len(mdl.images)):
tex_node = mat.node_tree.nodes.new("ShaderNodeTexImage")
tex_node.image = mdl.images[i]
tex_node.interpolation = "Closest"
if i == 0:
# connect only first texture (we'll need something smarter in the future)
mat.node_tree.links.new(tex_node.outputs[0], emissionNode.inputs[0])
mat.node_tree.links.new(emissionNode.outputs[0], shaderOut.inputs[0])
mdl.mesh.materials.append(mat)
def make_shape_key(mdl, framenum, subframenum=0):
@ -133,7 +153,7 @@ def make_shape_key(mdl, framenum, subframenum=0):
name = frame.name
else:
frame.name = name
frame.key = mdl.obj.shape_key_add(name)
frame.key = mdl.obj.shape_key_add(name=name)
frame.key.value = 0.0
mdl.keys.append(frame.key)
s = Vector(mdl.scale)
@ -143,11 +163,11 @@ def make_shape_key(mdl, framenum, subframenum=0):
( 0, 0,s.z,o.z),
( 0, 0, 0, 1)))
for i, v in enumerate(frame.verts):
frame.key.data[i].co = m * Vector(v.r)
frame.key.data[i].co = m @ Vector(v.r)
def build_shape_keys(mdl):
mdl.keys = []
mdl.obj.shape_key_add("Basis")
mdl.obj.shape_key_add(name="Basis",from_mix=False)
mdl.mesh.shape_keys.name = mdl.name
mdl.obj.active_shape_key_index = 0
for i, frame in enumerate(mdl.frames):
@ -327,6 +347,7 @@ def parse_flags(flags):
else:
return 'EF_NONE'
'''
def set_properties(mdl):
mdl.obj.qfmdl.eyeposition = mdl.eyeposition
try:
@ -337,12 +358,13 @@ def set_properties(mdl):
mdl.obj.qfmdl.effects = parse_flags(mdl.flags)
mdl.obj.qfmdl.script = mdl.text.name #FIXME really want the text object
mdl.obj.qfmdl.md16 = (mdl.ident == "MD16")
'''
def import_mdl(operator, context, filepath):
bpy.context.user_preferences.edit.use_global_undo = False
def import_mdl(operator, context, filepath, **opts):
bpy.context.preferences.edit.use_global_undo = False
for obj in bpy.context.scene.objects:
obj.select = False
for obj in bpy.context.scene.collection.objects:
obj.select_set(False)
mdl = MDL()
if not mdl.read(filepath):
@ -354,18 +376,19 @@ def import_mdl(operator, context, filepath):
mdl.mesh = bpy.data.meshes.new(mdl.name)
mdl.mesh.from_pydata(verts, [], faces)
mdl.obj = bpy.data.objects.new(mdl.name, mdl.mesh)
bpy.context.scene.objects.link(mdl.obj)
bpy.context.scene.objects.active = mdl.obj
mdl.obj.select = True
bpy.context.scene.collection.objects.link(mdl.obj)
mdl.obj.select_set(True)
bpy.context.view_layer.objects.active = mdl.obj
setup_skins(mdl, uvs)
if len(mdl.frames) > 1 or mdl.frames[0].type:
build_shape_keys(mdl)
merge_frames(mdl)
build_actions(mdl)
write_text(mdl)
set_properties(mdl)
#set_properties(mdl) #TODO: bring it back
mdl.mesh.update()
bpy.context.user_preferences.edit.use_global_undo = True
bpy.context.preferences.edit.use_global_undo = True
return {'FINISHED'}