From 70f500a087cc8334c456c20ce726d2308277700f Mon Sep 17 00:00:00 2001
From: Bill Currie <bill@taniwha.org>
Date: Sun, 15 Apr 2012 21:55:23 +0900
Subject: [PATCH] Use custom properties for model flags etc.

Eye position, auto rotation, sync type and particle effects can now all be
edited in blender: both import and export do the right thing. The settings
can be found in the "QF MDL" panel of the "Object" tab of the properties
view.
---
 tools/io_mesh_qfmdl/__init__.py   | 56 +++++++++++++++++++++++++++++--
 tools/io_mesh_qfmdl/export_mdl.py |  7 ++++
 tools/io_mesh_qfmdl/import_mdl.py | 34 +++++++++++++++++--
 tools/io_mesh_qfmdl/mdl.py        | 18 +++++++++-
 4 files changed, 110 insertions(+), 5 deletions(-)

diff --git a/tools/io_mesh_qfmdl/__init__.py b/tools/io_mesh_qfmdl/__init__.py
index 01e6c8c77..5ba5cf58c 100644
--- a/tools/io_mesh_qfmdl/__init__.py
+++ b/tools/io_mesh_qfmdl/__init__.py
@@ -40,14 +40,46 @@ if "bpy" in locals():
     import imp
     if "import_mdl" in locals():
         imp.reload(import_mdl)
-    #if "export_mdl" in locals():
-    #    imp.reload(export_mdl)
+    if "export_mdl" in locals():
+        imp.reload(export_mdl)
 
 
 import bpy
 from bpy.props import BoolProperty, FloatProperty, StringProperty, EnumProperty
+from bpy.props import FloatVectorProperty
 from bpy_extras.io_utils import ExportHelper, ImportHelper, path_reference_mode, axis_conversion
 
+SYNCTYPE=(
+    ('ST_SYNC', "Syncronized", "Automatic animations are all together"),
+    ('ST_RAND', "Random", "Automatic animations have random offsets"),
+)
+
+EFFECTS=(
+    ('EF_NONE', "None", "No effects"),
+    ('EF_ROCKET', "Rocket", "Leave a rocket trail"),
+    ('EF_GRENADE', "Grenade", "Leave a grenade trail"),
+    ('EF_GIB', "Gib", "Leave a trail of blood"),
+    ('EF_TRACER', "Tracer", "Green split trail"),
+    ('EF_ZOMGIB', "Zombie Gib", "Leave a smaller blood trail"),
+    ('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")
 
 class ImportMDL6(bpy.types.Operator, ImportHelper):
     '''Load a Quake MDL (v6) File'''
@@ -81,6 +113,24 @@ class ExportMDL6(bpy.types.Operator, ExportHelper):
         keywords = self.as_keywords (ignore=("check_existing", "filter_glob"))
         return export_mdl.export_mdl(self, context, **keywords)
 
+class MDLPanel(bpy.types.Panel):
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = 'object'
+    bl_label = 'QF MDL'
+
+    @classmethod
+    def poll(cls, context):
+        obj = context.active_object
+        return obj and obj.type == 'MESH'
+
+    def draw(self, context):
+        layout = self.layout
+        obj = context.active_object
+        layout.prop(obj.qfmdl, "eyeposition")
+        layout.prop(obj.qfmdl, "synctype")
+        layout.prop(obj.qfmdl, "rotate")
+        layout.prop(obj.qfmdl, "effects")
 
 def menu_func_import(self, context):
     self.layout.operator(ImportMDL6.bl_idname, text="Quake MDL (.mdl)")
@@ -93,6 +143,8 @@ def menu_func_export(self, context):
 def register():
     bpy.utils.register_module(__name__)
 
+    bpy.types.Object.qfmdl = bpy.props.PointerProperty(type=QFMDLSettings)
+
     bpy.types.INFO_MT_file_import.append(menu_func_import)
     bpy.types.INFO_MT_file_export.append(menu_func_export)
 
diff --git a/tools/io_mesh_qfmdl/export_mdl.py b/tools/io_mesh_qfmdl/export_mdl.py
index 0cd0b6fac..f75c17012 100644
--- a/tools/io_mesh_qfmdl/export_mdl.py
+++ b/tools/io_mesh_qfmdl/export_mdl.py
@@ -161,6 +161,12 @@ def calc_average_area(mdl):
         totalarea += (c * c) ** 0.5 / 2.0
     return totalarea / len(mdl.tris)
 
+def get_properties(mdl, obj):
+    mdl.eyeposition = tuple (obj.qfmdl.eyeposition)
+    mdl.synctype = MDL.SYNCTYPE[obj.qfmdl.synctype]
+    mdl.flags = ((obj.qfmdl.synctype and MDL.EF_ROTATE or 0)
+                 | MDL.EFFECTS[obj.qfmdl.effects])
+
 def export_mdl(operator, context, filepath):
     obj = context.active_object
     mesh = obj.to_mesh (context.scene, True, 'PREVIEW') #wysiwyg?
@@ -179,5 +185,6 @@ def export_mdl(operator, context, filepath):
     mdl.frames.append(make_frame(mesh, vertmap))
     mdl.size = calc_average_area(mdl)
     scale_verts(mdl)
+    get_properties(mdl, obj)
     mdl.write(filepath)
     return {'FINISHED'}
diff --git a/tools/io_mesh_qfmdl/import_mdl.py b/tools/io_mesh_qfmdl/import_mdl.py
index 303a0e8c6..4dbd96d50 100644
--- a/tools/io_mesh_qfmdl/import_mdl.py
+++ b/tools/io_mesh_qfmdl/import_mdl.py
@@ -235,6 +235,35 @@ def write_text(mdl):
     txt.from_string(string)
     return txt.name
 
+def parse_flags(flags):
+    #NOTE these are in QuakeForge priority order; a little different to id.
+    # id has rocket and grenate between tracer2 and tracer3
+    if flags & MDL.EF_ROCKET:
+        return 'EF_ROCKET'
+    elif flags & MDL.EF_GRENADE:
+        return 'EF_GRENADE'
+    elif flags & MDL.EF_GIB:
+        return 'EF_GIB'
+    elif flags & MDL.EF_ZOMGIB:
+        return 'EF_ZOMGIB'
+    elif flags & MDL.EF_TRACER:
+        return 'EF_TRACER'
+    elif flags & MDL.EF_TRACER2:
+        return 'EF_TRACER2'
+    elif flags & MDL.EF_TRACER3:
+        return 'EF_TRACER3'
+    else:
+        return 'EF_NONE'
+
+def set_properties(mdl):
+    mdl.obj.qfmdl.eyeposition = mdl.eyeposition
+    try:
+        mdl.obj.qfmdl.synctype = MDL.SYNCTYPE[mdl.synctype]
+    except IndexError:
+        mdl.obj.qfmdl.synctype = 'ST_SYNC'
+    mdl.obj.qfmdl.rotate = (mdl.flags & MDL.EF_ROTATE) and True or False
+    mdl.obj.qfmdl.effects = parse_flags(mdl.flags)
+
 def import_mdl(operator, context, filepath):
     bpy.context.user_preferences.edit.use_global_undo = False
 
@@ -264,8 +293,9 @@ def import_mdl(operator, context, filepath):
         merge_frames(mdl)
         build_actions(mdl)
 
-    operator.report({'INFO'},
-        "Extra settings saved in the %s text block." % write_text(mdl))
+    #operator.report({'INFO'},
+    #    "Extra settings saved in the %s text block." % write_text(mdl))
+    set_properties(mdl)
 
     mdl.mesh.update()
 
diff --git a/tools/io_mesh_qfmdl/mdl.py b/tools/io_mesh_qfmdl/mdl.py
index 6526fd462..521b6bf03 100644
--- a/tools/io_mesh_qfmdl/mdl.py
+++ b/tools/io_mesh_qfmdl/mdl.py
@@ -22,6 +22,22 @@
 from struct import unpack, pack
 
 class MDL:
+    ST_SYNC = 0
+    ST_RAND = 1
+    SYNCTYPE={'ST_SYNC':ST_SYNC, 'ST_RAND':ST_RAND,
+              ST_SYNC:'ST_SYNC', ST_RAND:'ST_RAND'}
+    EF_ROCKET = 1
+    EF_GRENADE = 2
+    EF_GIB = 4
+    EF_ROTATE = 8
+    EF_TRACER = 16
+    EF_ZOMGIB = 32
+    EF_TRACER2 = 64
+    EF_TRACER3 = 128
+    EFFECTS={'EF_NONE':0, 'EF_ROCKET':EF_ROCKET, 'EF_GRENADE':EF_GRENADE,
+             'EF_GIB':EF_GIB, 'EF_TRACER':EF_TRACER, 'EF_ZOMGIB':EF_ZOMGIB,
+             'EF_TRACER2':EF_TRACER2, 'EF_TRACER3':EF_TRACER3}
+
     class Skin:
         def __init__(self):
             pass
@@ -271,7 +287,7 @@ class MDL:
         self.scale_origin = (0.0, 0.0, 0.0) #FIXME
         self.boundingradius = 1.0           #FIXME
         self.eyeposition = (0.0, 0.0, 0.0)  #FIXME
-        self.synctype = 0       #FIXME config (right default?)
+        self.synctype = MDL.ST_SYNC
         self.flags = 0          #FIXME config
         self.size = 0           #FIXME ???
         self.skins = []