131 lines
5.6 KiB
Python
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)
|