Files
Avatar-Toolkit/core/importers/importer.py
T
Yusarina ff23d23cfc Start of the Major Overhaul
I decided to go through each function and UI section one by one, improving and overhauling things. Each function and section is going to be fully tested and not rushed out.

This is the best way to catch things, but also include the code base as much as possible.
2024-12-03 22:58:17 +00:00

130 lines
5.4 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),
}
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)