From 9b8f9b80770d708603df7e670e27bc7fa0facddb Mon Sep 17 00:00:00 2001 From: blubs Date: Sat, 21 Jan 2023 13:41:59 -0800 Subject: [PATCH] Adds first and final frame setting Adds preview of mdl mins / maxs bbox Adds author --- io_mesh_qfmdl_blubs/__init__.py | 144 ++++++++++++++++++++++++++++-- io_mesh_qfmdl_blubs/export_mdl.py | 16 +++- 2 files changed, 150 insertions(+), 10 deletions(-) diff --git a/io_mesh_qfmdl_blubs/__init__.py b/io_mesh_qfmdl_blubs/__init__.py index eed52a8..29795ae 100644 --- a/io_mesh_qfmdl_blubs/__init__.py +++ b/io_mesh_qfmdl_blubs/__init__.py @@ -23,7 +23,7 @@ bl_info = { "name": "Quake MDL format", - "author": "Bill Currie, Aleksander Marhall", + "author": "Bill Currie, Aleksander Marhall, Luis Gutierrez", "version": (0, 7, 0), "blender": (2, 80, 0), "api": 35622, @@ -47,7 +47,7 @@ if "bpy" in locals(): import bpy from bpy.props import BoolProperty, FloatProperty, StringProperty, EnumProperty -from bpy.props import FloatVectorProperty, PointerProperty +from bpy.props import FloatVectorProperty, PointerProperty, IntProperty, BoolProperty, PointerProperty from bpy_extras.io_utils import ExportHelper, ImportHelper, path_reference_mode, axis_conversion PALETTE=( @@ -72,6 +72,94 @@ EFFECTS=( ('EF_TRACER3', "Tracer 3", "Purple split trail"), ) + +import bgl +import gpu +import mathutils +from gpu_extras.batch import batch_for_shader + + +def mdl_draw_bbox_callback(self, context): + def draw_line(start, end, color): + shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') + batch = batch_for_shader(shader, 'LINES', {'pos': [start,end]}) + shader.bind() + shader.uniform_float('color', color) + batch.draw(shader) + + + bbox_mins = context.view_layer.objects.active.qfmdl.mdl_scale_mins + bbox_maxs = context.view_layer.objects.active.qfmdl.mdl_scale_maxs + if not context.view_layer.objects.active.qfmdl.mdl_draw_bbox: + return + + + + bbox_corners = { + 'left_front_lower': mathutils.Vector((bbox_mins[0], bbox_mins[1], bbox_mins[2])), + 'right_front_lower': mathutils.Vector((bbox_maxs[0], bbox_mins[1], bbox_mins[2])), + 'right_back_lower': mathutils.Vector((bbox_maxs[0], bbox_maxs[1], bbox_mins[2])), + 'left_back_lower': mathutils.Vector((bbox_mins[0], bbox_maxs[1], bbox_mins[2])), + 'left_front_upper': mathutils.Vector((bbox_mins[0], bbox_mins[1], bbox_maxs[2])), + 'right_front_upper': mathutils.Vector((bbox_maxs[0], bbox_mins[1], bbox_maxs[2])), + 'right_back_upper': mathutils.Vector((bbox_maxs[0], bbox_maxs[1], bbox_maxs[2])), + 'left_back_upper': mathutils.Vector((bbox_mins[0], bbox_maxs[1], bbox_maxs[2])), + } + color_red = (1.0, 0.0, 0.0, 0.7) + color_green = (0.0, 1.0, 0.0, 0.7) + color_blue = (0.0, 0.0, 1.0, 0.7) + + bgl.glEnable(bgl.GL_BLEND) + bgl.glEnable(bgl.GL_LINE_SMOOTH) + bgl.glDisable(bgl.GL_DEPTH_TEST) + + draw_line(bbox_corners['left_front_lower'], bbox_corners['right_front_lower'], color_red) + draw_line(bbox_corners['left_back_lower'], bbox_corners['right_back_lower'], color_red) + draw_line(bbox_corners['left_front_upper'], bbox_corners['right_front_upper'], color_red) + draw_line(bbox_corners['left_back_upper'], bbox_corners['right_back_upper'], color_red) + + draw_line(bbox_corners['left_front_lower'], bbox_corners['left_back_lower'], color_green) + draw_line(bbox_corners['right_front_lower'], bbox_corners['right_back_lower'], color_green) + draw_line(bbox_corners['left_front_upper'], bbox_corners['left_back_upper'], color_green) + draw_line(bbox_corners['right_front_upper'], bbox_corners['right_back_upper'], color_green) + + draw_line(bbox_corners['left_front_lower'], bbox_corners['left_front_upper'], color_blue) + draw_line(bbox_corners['right_front_lower'], bbox_corners['right_front_upper'], color_blue) + draw_line(bbox_corners['left_back_lower'], bbox_corners['left_back_upper'], color_blue) + draw_line(bbox_corners['right_back_lower'], bbox_corners['right_back_upper'], color_blue) + + # bgl.glEnd() + bgl.glLineWidth(1) + bgl.glDisable(bgl.GL_BLEND) + bgl.glDisable(bgl.GL_LINE_SMOOTH) + bgl.glEnable(bgl.GL_DEPTH_TEST) + + +# This dictionary is used to store bbox preview handlers +# Keys: object names +# Values: registered handlers +draw_bbox_handlers = { +} + + +def mdl_draw_bbox_updated(self, context): + global draw_bbox_handlers + + # Disable all existing handlers: + while len(draw_bbox_handlers) > 0: + k = list(draw_bbox_handlers.keys())[0] + v = draw_bbox_handlers.pop(k) + bpy.types.SpaceView3D.draw_handler_remove(v, 'WINDOW') + + # Add a new handler for this object name: + if self.mdl_draw_bbox: + obj_name = context.view_layer.objects.active.name + handler = bpy.types.SpaceView3D.draw_handler_add(mdl_draw_bbox_callback, (self,context), 'WINDOW', 'POST_VIEW') + # Store the handler to later remove it + draw_bbox_handlers[obj_name] = handler + + + class QFMDLSettings(bpy.types.PropertyGroup): palette : EnumProperty( items=PALETTE, @@ -79,7 +167,7 @@ class QFMDLSettings(bpy.types.PropertyGroup): description="Palette") eyeposition : FloatVectorProperty( name="Eye Position", - description="View possion relative to object origin") + description="View position relative to object origin") synctype : EnumProperty( items=SYNCTYPE, name="Sync Type", @@ -116,15 +204,31 @@ class QFMDLSettings(bpy.types.PropertyGroup): # name="Script", # description="Script for animating frames and skins") + mdl_first_frame : IntProperty( + name="First Frame", + default=0, + description="First animation frame to export." + ) + mdl_last_frame : IntProperty( + name="Last Frame", + default=0, + description="Final animation frame to export. (Inclusive)" + ) + mdl_scale_mins : FloatVectorProperty( name="MDL Mins", - default=(-400.0,-100.0,-100.0), + default=(-100.0,-100.0,-100.0), description="Minimum allowed vertex coordinates") mdl_scale_maxs : FloatVectorProperty( name="MDL Maxs", default=(100.0,100.0,100.0), description="Maximum allowed vertex coordinates") - + mdl_draw_bbox : BoolProperty( + name="Show MDL bounding box", + default=False, + description="Draw the specified MDL bounding box in the blender 3D viewport.", + update=mdl_draw_bbox_updated, + ) class ImportMDL6(bpy.types.Operator, ImportHelper): @@ -146,6 +250,9 @@ class ImportMDL6(bpy.types.Operator, ImportHelper): keywords = self.as_keywords (ignore=("filter_glob",)) return import_mdl.import_mdl(self, context, **keywords) + + + class ExportMDL6(bpy.types.Operator, ExportHelper): '''Save a Quake MDL (v6) File''' @@ -183,16 +290,32 @@ class ExportMDL6(bpy.types.Operator, ExportHelper): md16 : BoolProperty( name="16-bit", description="16 bit vertex coordinates: QuakeForge only") + + mdl_first_frame : IntProperty( + name="Start Frame", + default=0, + description="First animation frame to export." + ) + mdl_last_frame : IntProperty( + name="End Frame", + default=0, + description="Final animation frame to export. (Inclusive)" + ) + mdl_scale_mins : FloatVectorProperty( name="MDL Mins", default=(-100.0,-100.0,-100.0), - # default = bpy.context.active_object.qfmdl.mdl_scale_mins, description="Minimum allowed vertex coordinates") mdl_scale_maxs : FloatVectorProperty( name="MDL Maxs", default=(100.0,100.0,100.0), - # default = bpy.context.active_object.qfmdl.mdl_scale_maxs, description="Maximum allowed vertex coordinates") + mdl_draw_bbox : BoolProperty( + name="Show MDL bounding box", + default=False, + description="Draw the specified MDL bounding box in the blender 3D viewport.", + update=mdl_draw_bbox_updated, + ) @classmethod def poll(cls, context): @@ -208,6 +331,8 @@ class ExportMDL6(bpy.types.Operator, ExportHelper): # self.eyeposition = bpy.context.active_object.qfmdl.eyeposition self.mdl_scale_mins = bpy.context.active_object.qfmdl.mdl_scale_mins self.mdl_scale_maxs = bpy.context.active_object.qfmdl.mdl_scale_maxs + self.mdl_first_frame = bpy.context.active_object.qfmdl.mdl_first_frame + self.mdl_last_frame = bpy.context.active_object.qfmdl.mdl_last_frame return ExportHelper.invoke(self,context,event) # return {"RUNNING_MODAL"} # return {'FINISHED'} @@ -240,8 +365,13 @@ class OBJECT_PT_MDLPanel(bpy.types.Panel): # layout.prop(obj.qfmdl, "script") layout.prop(obj.qfmdl, "xform") layout.prop(obj.qfmdl, "md16") + layout.prop(obj.qfmdl, "mdl_first_frame") + layout.prop(obj.qfmdl, "mdl_last_frame") layout.prop(obj.qfmdl, "mdl_scale_mins") layout.prop(obj.qfmdl, "mdl_scale_maxs") + layout.prop(obj.qfmdl, "mdl_draw_bbox") + + def menu_func_import(self, context): self.layout.operator(ImportMDL6.bl_idname, text="Quake MDL (.mdl)") diff --git a/io_mesh_qfmdl_blubs/export_mdl.py b/io_mesh_qfmdl_blubs/export_mdl.py index 7bb2f4b..bdf3565 100644 --- a/io_mesh_qfmdl_blubs/export_mdl.py +++ b/io_mesh_qfmdl_blubs/export_mdl.py @@ -247,8 +247,11 @@ def get_properties( effects, xform, md16, + mdl_first_frame, + mdl_last_frame, mdl_scale_mins, - mdl_scale_maxs): + mdl_scale_maxs, + mdl_draw_bbox,): mdl.palette = MDL.PALETTE[palette] mdl.eyeposition = eyeposition mdl.synctype = MDL.SYNCTYPE[synctype] @@ -357,8 +360,11 @@ def export_mdl( effects = EFFECTS[1], xform = True, md16 = False, + mdl_first_frame=0, + mdl_last_frame=10, mdl_scale_mins=(-100,-100,-100), mdl_scale_maxs=(100,100,100), + mdl_draw_bbox=False, ): obj = context.active_object @@ -382,8 +388,11 @@ def export_mdl( effects, xform, md16, + mdl_first_frame, + mdl_last_frame, mdl_scale_mins, - mdl_scale_maxs): + mdl_scale_maxs, + mdl_draw_bbox,): return {'CANCELLED'} mdl.tris, mdl.stverts, vertmap = build_tris(mesh) @@ -401,7 +410,8 @@ def export_mdl( # Export up to the last scene frame: # for fno in range(context.scene.frame_start, context.scene.frame_end + 1): # Only export up to current frame: - for fno in range(context.scene.frame_start, context.scene.frame_current + 1): + # for fno in range(context.scene.frame_start, context.scene.frame_current + 1): + for fno in range(mdl_first_frame, mdl_last_frame + 1): context.scene.frame_set(fno) obj.update_from_editmode() depsgraph = context.evaluated_depsgraph_get()