Exporter with live camera selection problem

Hi everybody, I just came back to Blender after a while away, and I seem to really be missing something when trying to understand the new bpy 2.5x API.

I am doing a project in which I export a projected scene to a custom XML format from different camera views. However I just can’t seem to get a good way to let the user choose which camera.

Here is my attempt, but although CamData.name gets updated when you change a selection the result does not mirror to ExportMPL.cam_name, in fact that property does not change regardless action after running the fileselector.

If anybody has any idea on how to fix this I appreciate your time. Also any better ideas are also kindly welcomed. Thanks!


import bpy, io_utils

class CamData(bpy.types.Operator):
    name = bpy.props.StringProperty(default="", options={'HIDDEN'})
    bl_idname = "morphplate.camera"
    bl_label = "Hold Camera Name"

    def execute(self, context):
        bpy.ops.morphplate.export.cam_name = self.name
        return {'FINISHED'}

class CamMenu(bpy.types.Menu):
    bl_idname = "morphplate.menu"
    bl_label = "Select Camera"

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        cameras = [ob for ob in scene.objects if ob.is_visible(scene) and ob.type == 'CAMERA' and ob.dupli_type == 'NONE']
        for camera in cameras: layout.operator("morphplate.camera", text=camera.name).name = camera.name

class ExportMPL(bpy.types.Operator, io_utils.ExportHelper):
    filter_glob = bpy.props.StringProperty(default="*.mpl", options={'HIDDEN'})
    cam_name = bpy.props.StringProperty(default="")
    bl_idname = "morphplate.export"
    bl_label = "XML MorphPlate"
    filename_ext = ".mpl"

    @classmethod
    def poll(self, context):
        scene = context.scene
        self.meshes = [ob for ob in scene.objects if ob.is_visible(scene) and ob.type == 'MESH' and ob.dupli_type == 'NONE']
        return ( len(self.meshes) > 0 )

    def execute(self, context):
        if "export_mpl" not in locals(): from . import export_mpl
        print(self.cam_name)
        scene = context.scene
        for obj in scene.objects:
            if obj.name == self.cam_name: return export_mpl.save( self.filepath, obj, self.meshes, scene)
        return {'FINISHED'}

    def draw(self, context):
        layout = self.layout
        row = layout.row()
        row.label(icon='CAMERA_DATA')
        row.prop(self, "cam_name")
        layout.row().menu("morphplate.menu")


menu_func = lambda self, context: self.layout.operator(ExportMPL.bl_idname, text="XML MorphPlate (.mpl)")
def register():
    bpy.utils.register_class(CamData)
    bpy.utils.register_class(CamMenu)
    bpy.utils.register_class(ExportMPL)
    bpy.types.INFO_MT_file_export.append(menu_func)

def unregister():
    bpy.utils.unregister_class(ExportMPL)
    bpy.types.INFO_MT_file_export.remove(menu_func)

if __name__ == "__main__":
    register() 

I give up, it seems to be a bpy bug (or design limitation)… In the case of more than one camera I am just going to make the script export a number of files for each of the visible cameras in the scene, since I would have probably repeated the action for each view anyway. Although this is a potential annoyance in the animation pipeline, where one file may be accidentally overwritten, is probably going to be such a limited occurrence that it doesn’t matter.

:o So Blender 2.8 fixes the dynamic enum list issue, wow, I wish that I had known that it yesterday before wasting 6 hours on various things that did not work, amazing how bad my timing can actually be…

I thought that I would post the revised code from above using the new dynamic EnumProperty for a camera selection. I hope it helps someone else from loosing a day because its still a bit tricky, it seems that the self passed is of a derived class not the original container of the Enum, so here is my workaround.


cam_list = lambda self, context: ExportMPL.cams(context)
class ExportMPL(bpy.types.Operator, ExportHelper):
    cam_select = EnumProperty(items=cam_list, name="Use Camera :", description="Choose which view is used for exporting.")
    filter_glob = StringProperty(default="*.mpl", options={'HIDDEN'})
    bl_idname = "export_scene.mpl"
    bl_label = "XML MorphPlate"
    filename_ext = ".mpl"
    cameras = []
    meshes = []

    @classmethod
    def cams(self, context):
        return [ (str(idx), cam.name, "Use camera " + cam.name +".") for idx, cam in enumerate(self.cameras) ]

    @classmethod
    def poll(self, context):
        scene = context.scene
        self.cameras = [ob for ob in scene.objects if ob.is_visible(scene) and ob.type == 'CAMERA' and ob.dupli_type == 'NONE']
        self.meshes = [ob for ob in scene.objects if ob.is_visible(scene) and ob.type == 'MESH' and ob.dupli_type == 'NONE']
        return ( len(self.cameras) > 0 and len(self.meshes) > 0 )

    def execute(self, context):
        if "export_mpl" not in locals(): from . import export_mpl
        return export_mpl.save( self.filepath, scene, self.cameras[int(self.cam_select)], self.meshes)