From 15bbcc3d89be653802593a8cdc07c80ee4a9926e Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Tue, 3 Aug 2021 15:08:33 -0400 Subject: [PATCH] Fix #266. This ensures that autocolor layers are disposed before their temporary mesh objects are disposed. --- korman/exporter/convert.py | 5 ++--- korman/exporter/etlight.py | 7 +++---- korman/exporter/mesh.py | 41 ++++++++++++++++++++++---------------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/korman/exporter/convert.py b/korman/exporter/convert.py index 2f40500..bded50d 100644 --- a/korman/exporter/convert.py +++ b/korman/exporter/convert.py @@ -16,7 +16,6 @@ import bpy from pathlib import Path -from contextlib import ExitStack from ..korlib import ConsoleToggler @@ -47,7 +46,7 @@ class Exporter: def run(self): log = logger.ExportVerboseLogger if self._op.verbose else logger.ExportProgressLogger - with ConsoleToggler(self._op.show_console), log(self._op.filepath) as self.report, ExitStack() as self.context_stack: + with ConsoleToggler(self._op.show_console), log(self._op.filepath) as self.report: # Step 0: Init export resmgr and stuff self.mgr = manager.ExportManager(self) self.mesh = mesh.MeshConverter(self) @@ -59,7 +58,7 @@ class Exporter: self.image = image.ImageCache(self) self.locman = locman.LocalizationConverter(self) self.decal = decal.DecalConverter(self) - self.oven = etlight.LightBaker(self.report, stack=self.context_stack) + self.oven = etlight.LightBaker(self.report) # Step 0.8: Init the progress mgr self.mesh.add_progress_presteps(self.report) diff --git a/korman/exporter/etlight.py b/korman/exporter/etlight.py index f1ce2ad..94d90c9 100644 --- a/korman/exporter/etlight.py +++ b/korman/exporter/etlight.py @@ -28,7 +28,7 @@ _NUM_RENDER_LAYERS = 20 class LightBaker(_MeshManager): """ExportTime Lighting""" - def __init__(self, report=None, stack=None, *, verbose=False): + def __init__(self, report=None, *, verbose=False): self._lightgroups = {} if report is None: self._report = ExportVerboseLogger() if verbose else ExportProgressLogger() @@ -40,7 +40,6 @@ class LightBaker(_MeshManager): self._own_report = False super().__init__(self._report) - self._context_stack = stack self.vcol_layer_name = "autocolor" self.lightmap_name = "{}_LIGHTMAPGEN.png" self.lightmap_uvtex_name = "LIGHTMAPGEN" @@ -445,8 +444,8 @@ class LightBaker(_MeshManager): # nukage. If we're in the lightmap operators, we clearly want this to persist for # future exports as an optimization. We won't reach this point if there is already an # autocolor layer (gulp). - if self._context_stack is not None and needs_vcol_layer: - self._context_stack.enter_context(TemporaryObject(vcol_layer, vcols.remove)) + if not self.force and needs_vcol_layer: + self.context_stack.enter_context(TemporaryObject(vcol_layer, vcols.remove)) # Indicate we should bake return True diff --git a/korman/exporter/mesh.py b/korman/exporter/mesh.py index fb2127e..fef6d9a 100644 --- a/korman/exporter/mesh.py +++ b/korman/exporter/mesh.py @@ -14,6 +14,7 @@ # along with Korman. If not, see . import bpy +from contextlib import ExitStack import itertools from PyHSPlasma import * from math import fabs @@ -163,6 +164,7 @@ class _GeoData: class _MeshManager: def __init__(self, report=None): + self.context_stack = ExitStack() if report is not None: self._report = report self._overrides = {} @@ -181,6 +183,8 @@ class _MeshManager: return props def __enter__(self): + self.context_stack.__enter__() + scene = bpy.context.scene self._report.progress_advance() self._report.progress_range = len(scene.objects) @@ -207,23 +211,26 @@ class _MeshManager: self._report.progress_increment() return self - def __exit__(self, type, value, traceback): - data_bos, data_meshes = bpy.data.objects, bpy.data.meshes - for obj_name, override in self._overrides.items(): - bo = data_bos.get(obj_name) - - # Reapply the old mesh - trash_mesh, bo.data = bo.data, data_meshes.get(override["mesh"]) - data_meshes.remove(trash_mesh) - - # If modifiers were removed, reapply them now unless they're read-only. - readonly_attributes = {("DECIMATE", "face_count"),} - for cached_mod in override["modifiers"]: - mod = bo.modifiers.new(cached_mod["name"], cached_mod["type"]) - for key, value in cached_mod.items(): - if key in {"name", "type"} or (cached_mod["type"], key) in readonly_attributes: - continue - setattr(mod, key, value) + def __exit__(self, *exc_info): + try: + self.context_stack.__exit__(*exc_info) + finally: + data_bos, data_meshes = bpy.data.objects, bpy.data.meshes + for obj_name, override in self._overrides.items(): + bo = data_bos.get(obj_name) + + # Reapply the old mesh + trash_mesh, bo.data = bo.data, data_meshes.get(override["mesh"]) + data_meshes.remove(trash_mesh) + + # If modifiers were removed, reapply them now unless they're read-only. + readonly_attributes = {("DECIMATE", "face_count"),} + for cached_mod in override["modifiers"]: + mod = bo.modifiers.new(cached_mod["name"], cached_mod["type"]) + for key, value in cached_mod.items(): + if key in {"name", "type"} or (cached_mod["type"], key) in readonly_attributes: + continue + setattr(mod, key, value) class MeshConverter(_MeshManager):