diff --git a/__init__.py b/__init__.py index 0ec3d89c..5573162a 100644 --- a/__init__.py +++ b/__init__.py @@ -3232,6 +3232,7 @@ def draw(self, context): if hasattr(obj, prop) and not prop.startswith("Expressions_"): box_fast_creators.prop(obj, prop) box_fast_creators.operator("mbast.reset_categoryonly", icon="RECOVER_LAST") + #---------- box_fast_creators.separator(factor=0.5) box_fast_creators.label(text="Phenotype Creator", icon='SORT_ASC') body_type = morphcreator.get_body_type() @@ -3244,11 +3245,31 @@ def draw(self, context): box_fast_creators.label(text="Name : " + pheno_name, icon='INFO') if morphcreator.is_phenotype_exists(body_type, pheno_name): box_fast_creators.label(text="File already exists !", icon='ERROR') - else : - box_fast_creators.operator('mbcrea.button_save_phenotype', icon="FREEZE") + box_fast_creators.operator('mbcrea.button_save_phenotype', icon="FREEZE") + #---------- + box_fast_creators.separator(factor=0.5) + box_fast_creators.label(text="Preset Creator", icon='SORT_ASC') + preset_folder = mblab_humanoid.presets_data_folder + path = os.path.join("data", "presets", preset_folder) + box_fast_creators.label(text="File saved under " + path, icon='INFO') + box_fast_creators.label(text="(age, mass & tone are used here)", icon='FORWARD') + box_fast_creators.prop(scn, 'mbcrea_preset_name_filter') + if len(scn.mbcrea_preset_name_filter) > 0: + box_fast_creators.prop(scn, 'mbcrea_special_preset') # Common or Special ? + preset_name = "" + if scn.mbcrea_special_preset: + preset_name = "special" + tmp = algorithms.split_name(scn.mbcrea_preset_name_filter, '-²&=¨^$£%µ,?;!§+*/').lower() + if not tmp.startswith("type_"): + preset_name += "type_" + preset_name += tmp + box_fast_creators.label(text="Name : " + preset_name, icon='INFO') + if morphcreator.is_preset_exists(preset_folder, preset_name): + box_fast_creators.label(text="File already exists !", icon='ERROR') + box_fast_creators.operator('mbcrea.button_save_preset', icon="FREEZE") else: - box_combinexpression.label(text="! NO COMPATIBLE MODEL !", icon='ERROR') - box_combinexpression.enabled = False + box_fast_creators.label(text="! NO COMPATIBLE MODEL !", icon='ERROR') + box_fast_creators.enabled = False #---------------------------------- box_adaptation_tools.separator(factor=0.5) @@ -3548,7 +3569,17 @@ def morphs_items_minmax(box, items_str, minmax_str): maxlen=1024, subtype='FILE_NAME') +bpy.types.Scene.mbcrea_preset_name_filter = bpy.props.StringProperty( + name="Name", + description="The name for the file.\nStarting with type_ is automatic", + default="", + maxlen=1024, + subtype='FILE_NAME') +bpy.types.Scene.mbcrea_special_preset = bpy.props.BoolProperty( + name="Special", + description="If the preset is special or common") + class FinalizeExpression(bpy.types.Operator): """ Working like FinalizeMorph @@ -3649,17 +3680,35 @@ def execute(self, context): scn = bpy.context.scene #-------File name---------- pheno_name = algorithms.split_name(scn.mbcrea_phenotype_name_filter, '-²&=¨^$£%µ,?;!§+*/').lower() - #--expression path + name-- + #---phenotype path + name-- path = os.path.join(file_ops.get_data_path(), "phenotypes", morphcreator.get_body_type() + "_ptypes", pheno_name+".json") #--------Saving file------- morphcreator.save_phenotype(path, mblab_humanoid) return {'FINISHED'} - def ShowMessageBox(self, message = "", title = "Message Box", icon = 'INFO'): +class FinalizePreset(bpy.types.Operator): + """ + Working like Save character + """ + bl_label = 'Finalize the preset' + bl_idname = 'mbcrea.button_save_preset' + filename_ext = ".json" + bl_description = 'Finalize the preset' + bl_context = 'objectmode' + bl_options = {'REGISTER', 'INTERNAL'} + + def execute(self, context): + scn = bpy.context.scene + #-------File name---------- + preset_name = algorithms.split_name(scn.mbcrea_preset_name_filter, '-²&=¨^$£%µ,?;!§+*/').lower() + if not preset_name.startswith("type_"): + preset_name = "type_" + preset_name + #----preset path + name---- + path = os.path.join(file_ops.get_data_path(), "presets", mblab_humanoid.presets_data_folder, preset_name+".json") + #--------Saving file------- + morphcreator.save_preset(path, mblab_humanoid) + return {'FINISHED'} - def draw(self, context): - self.layout.label(text=message) - bpy.context.window_manager.popup_menu(draw, title = title, icon = icon) class ButtonCompatToolsDir(bpy.types.Operator): #just for quick tests @@ -4002,9 +4051,9 @@ def execute(self, context): return {'FINISHED'} class ButtonFastCreationsON(bpy.types.Operator): - bl_label = 'Fast Creation Tools' + bl_label = 'Character Library Creation' bl_idname = 'mbcrea.button_fastcreators_on' - bl_description = 'Quick tools to create :\n- Phenotypes\n- Presets' + bl_description = 'Quick tools to create :\n- Phenotypes\n- Presets\nfor Character Library' bl_context = 'objectmode' bl_options = {'REGISTER', 'INTERNAL'} @@ -4015,9 +4064,9 @@ def execute(self, context): return {'FINISHED'} class ButtonFastCreationsOFF(bpy.types.Operator): - bl_label = 'Fast Creation Tools' + bl_label = 'Character Library Creation' bl_idname = 'mbcrea.button_fastcreators_off' - bl_description = 'Quick tools to create :\n- Phenotypes\n- Presets' + bl_description = 'Quick tools to create :\n- Phenotypes\n- Presets\nfor Character Library' bl_context = 'objectmode' bl_options = {'REGISTER', 'INTERNAL'} @@ -4409,6 +4458,7 @@ def execute(self, context): FinalizeExpression, FinalizeCombExpression, FinalizePhenotype, + FinalizePreset, ButtonUpdateCombMorphs, FinalizeCombMorph, Reset_expression_category, diff --git a/expressionscreator.py b/expressionscreator.py index 131cea7f..234e6f74 100644 --- a/expressionscreator.py +++ b/expressionscreator.py @@ -362,10 +362,9 @@ def save_face_expression(self, filepath): for prop in self.humanoid.character_data.keys(): if self.humanoid.character_data[prop] != 0.5 and prop.startswith("Expressions_"): char_data["structural"][prop] = round(self.humanoid.character_data[prop], 4) - - output_file = open(filepath, 'w') - json.dump(char_data, output_file) - output_file.close() + with open(filepath, "w") as j_file: + json.dump(char_data, j_file, indent=2) + j_file.close() # data_source can be a filepath but also the data themselves. def load_face_expression(self, data_source, reset_unassigned=True): diff --git a/morphcreator.py b/morphcreator.py index 0b47c875..611997cb 100644 --- a/morphcreator.py +++ b/morphcreator.py @@ -29,6 +29,7 @@ import bpy import numpy from . import algorithms +from . import file_ops body_parts = [("AB", "Abdomen", ""), @@ -291,5 +292,39 @@ def is_phenotype_exists(body_type, name): return False return False +def save_phenotype(path, humanoid): + # Save all expression morphs as a new face expression + # in its dedicated file. + # If file already exists, it's replaced. + logger.info("Exporting character to {0}".format(file_ops.simple_path(path))) + obj = humanoid.get_object() + char_data = {"structural": dict()} + + if obj: + for prop in humanoid.character_data.keys(): + if humanoid.character_data[prop] != 0.5 and not prop.startswith("Expressions_"): + char_data["structural"][prop] = round(humanoid.character_data[prop], 2) + + with open(path, "w") as j_file: + json.dump(char_data, j_file, indent=2) + j_file.close() + +# ------------------------------------------------------------------------ +# All methods/classes to help creating presets +# ------------------------------------------------------------------------ + +def is_preset_exists(preset_folder, name): + if len(preset_folder) < 1 or len(name) < 1: + return False + try: + path = os.path.join(file_ops.get_data_path(), "presets", preset_folder) + for database_file in os.listdir(path): + the_item, extension = os.path.splitext(database_file) + if the_item == name: + return True + except: + return False + return False + def save_phenotype(path, humanoid): return None \ No newline at end of file