""" Contains Scene object for representing a .msh file and the function to create one from a Blender scene. """ from dataclasses import dataclass, field from typing import List, Dict from copy import copy import bpy from mathutils import Vector from .msh_model import Model from .msh_model_gather import gather_models from .msh_model_utilities import sort_by_parent, has_multiple_root_models, reparent_model_roots, get_model_world_matrix from .msh_model_triangle_strips import create_models_triangle_strips from .msh_material import * from .msh_material_gather import gather_materials from .msh_material_utilities import remove_unused_materials from .msh_utilities import * @dataclass class SceneAABB: """ Class representing an axis-aligned bounding box. """ AABB_INIT_MAX = -3.402823466e+38 AABB_INIT_MIN = 3.402823466e+38 max_: Vector = Vector((AABB_INIT_MAX, AABB_INIT_MAX, AABB_INIT_MAX)) min_: Vector = Vector((AABB_INIT_MIN, AABB_INIT_MIN, AABB_INIT_MIN)) def integrate_aabb(self, other): """ Merge another AABB with this AABB. """ self.max_ = max_vec(self.max_, other.max_) self.min_ = min_vec(self.min_, other.min_) def integrate_position(self, position): """ Integrate a position with the AABB, potentially expanding it. """ self.max_ = max_vec(self.max_, position) self.min_ = min_vec(self.min_, position) @dataclass class Scene: """ Class containing the scene data for a .msh """ name: str = "Scene" materials: Dict[str, Material] = field(default_factory=dict) models: List[Model] = field(default_factory=list) skeleton: List[int] = field(default_factory=list) def create_scene(generate_triangle_strips: bool, apply_modifiers: bool, export_target: str, skel_only: bool) -> Scene: """ Create a msh Scene from the active Blender scene. """ scene = Scene() scene.name = bpy.context.scene.name scene.materials = gather_materials() scene.models = gather_models(apply_modifiers=apply_modifiers, export_target=export_target, skeleton_only=skel_only) scene.models = sort_by_parent(scene.models) if generate_triangle_strips: scene.models = create_models_triangle_strips(scene.models) else: for model in scene.models: if model.geometry: for segment in model.geometry: segment.triangle_strips = segment.triangles if has_multiple_root_models(scene.models): scene.models = reparent_model_roots(scene.models) scene.materials = remove_unused_materials(scene.materials, scene.models) #creates a dummy basepose if no Action is selected if "Armature" in bpy.context.scene.objects.keys(): scene.anims = [extract_anim(bpy.context.scene.objects["Armature"])] root = scene.models[0] if skel_only and root.model_type == ModelType.NULL: inject_dummy_data(root) return scene def create_scene_aabb(scene: Scene) -> SceneAABB: """ Create a SceneAABB for a Scene. """ global_aabb = SceneAABB() for model in scene.models: if model.geometry is None or model.hidden: continue model_world_matrix = get_model_world_matrix(model, scene.models) model_aabb = SceneAABB() for segment in model.geometry: segment_aabb = SceneAABB() for pos in segment.positions: segment_aabb.integrate_position(model_world_matrix @ pos) model_aabb.integrate_aabb(segment_aabb) global_aabb.integrate_aabb(model_aabb) return global_aabb