Files
Avatar-Toolkit/core/importers/importer.py
T
2024-12-16 13:12:33 +00:00

131 lines
5.6 KiB
Python

import bpy
import logging
import os
import typing
from typing import Optional, Callable, Dict, List, Union, Set
from ..common import clear_default_objects
from .import_pmx import import_pmx
from .import_pmd import import_pmd
# Configure logging
logging.basicConfig(level=logging.INFO)
logger: logging.Logger = logging.getLogger(__name__)
import importlib.util
if importlib.util.find_spec("io_scene_valvesource") is not None:
from io_scene_valvesource.import_smd import SmdImporter
class ImportProgress:
"""Tracks and logs the progress of multi-file imports"""
def __init__(self, total_files: int):
self.total: int = total_files
self.current: int = 0
def update(self, filename: str) -> None:
"""Update import progress and log current file"""
self.current += 1
logger.info(f"Importing {filename} ({self.current}/{self.total})")
def validate_file(filepath: str) -> bool:
"""
Validate if a file exists and is accessible
Returns: True if file is valid, False otherwise
"""
if not os.path.exists(filepath):
logger.error(f"File not found: {filepath}")
return False
if not os.path.isfile(filepath):
logger.error(f"Not a file: {filepath}")
return False
return True
def import_multi_files(
method: Optional[Callable] = None,
directory: Optional[str] = None,
files: Optional[List[Dict[str, str]]] = None,
filepath: str = "",
progress_callback: Optional[Callable[[str], None]] = None
) -> None:
"""
Import multiple files using the specified import method
Args:
method: Import method to use
directory: Directory containing files
files: List of files to import
filepath: Single file path to import
progress_callback: Callback for progress updates
"""
try:
if not method:
raise ValueError("Import method not specified")
if not files:
if not validate_file(filepath):
return
method(directory, filepath)
if progress_callback:
progress_callback(filepath)
else:
progress = ImportProgress(len(files))
for file in files:
fullpath: str = os.path.join(directory, os.path.basename(file["name"]))
if not validate_file(fullpath):
continue
logger.info(f"Importing file: {fullpath}")
method(directory, fullpath)
if progress_callback:
progress_callback(fullpath)
progress.update(file["name"])
except Exception as e:
logger.error(f"Import failed: {str(e)}", exc_info=True)
raise
ImportMethod = Callable[[str, List[Dict[str, str]], str], None]
import_types: Dict[str, ImportMethod] = {
"fbx": lambda directory, files, filepath: bpy.ops.import_scene.fbx(
files=files, directory=directory, filepath=filepath,
automatic_bone_orientation=False, use_prepost_rot=False, use_anim=False
),
"smd": lambda directory, files, filepath: eval("bpy."+SmdImporter.bl_idname+".(files=files, directory=directory, filepath=filepath)"),
"dmx": lambda directory, files, filepath: eval("bpy."+SmdImporter.bl_idname+".(files=files, directory=directory, filepath=filepath)"),
"gltf": lambda directory, files, filepath: bpy.ops.import_scene.gltf(files=files, filepath=filepath),
"glb": lambda directory, files, filepath: bpy.ops.import_scene.gltf(files=files, filepath=filepath),
"qc": lambda directory, files, filepath: eval("bpy."+SmdImporter.bl_idname+".(files=files, directory=directory, filepath=filepath)"),
"obj": lambda directory, files, filepath: bpy.ops.wm.obj_import(files=files, directory=directory, filepath=filepath),
"dae": lambda directory, files, filepath: import_multi_files(
directory=directory,
files=files,
filepath=filepath,
method=lambda directory, filepath: bpy.ops.wm.collada_import(
filepath=filepath, auto_connect=True, find_chains=True, fix_orientation=True
)
),
"3ds": lambda directory, files, filepath: bpy.ops.import_scene.max3ds(files=files, directory=directory, filepath=filepath),
"stl": lambda directory, files, filepath: bpy.ops.import_mesh.stl(files=files, directory=directory, filepath=filepath),
"mtl": lambda directory, files, filepath: bpy.ops.wm.obj_import(files=files, directory=directory, filepath=filepath),
"x3d": lambda directory, files, filepath: bpy.ops.import_scene.x3d(files=files, directory=directory, filepath=filepath),
"wrl": lambda directory, files, filepath: bpy.ops.import_scene.x3d(files=files, directory=directory, filepath=filepath),
"vmd": lambda directory, files, filepath: import_multi_files(
directory=directory,
files=files,
filepath=filepath,
method=lambda directory, filepath: bpy.ops.tuxedo.import_mmd_animation(directory=directory, filepath=filepath)
),
"vrm": lambda directory, files, filepath: bpy.ops.import_scene.vrm(filepath=filepath),
"pmx": lambda directory, files, filepath: import_pmx(filepath),
"pmd": lambda directory, files, filepath: import_pmd(filepath),
"animx": (lambda directory, files, filepath : bpy.ops.avatar_toolkit.animx_importer(directory=directory,files=files,filepath=filepath)),
}
def concat_imports_filter(imports: Dict[str, ImportMethod]) -> str:
"""Create a file filter string from import types"""
return "".join(f"*.{importer};" for importer in imports.keys())
imports: str = concat_imports_filter(import_types)