diff --git a/korman/exporter/convert.py b/korman/exporter/convert.py
index 3e87bea..842f0a7 100644
--- a/korman/exporter/convert.py
+++ b/korman/exporter/convert.py
@@ -14,6 +14,7 @@
# along with Korman. If not, see .
import bpy
+from ..korlib import ConsoleToggler
from pathlib import Path
from PyHSPlasma import *
import time
@@ -43,7 +44,7 @@ class Exporter:
def run(self):
log = logger.ExportVerboseLogger if self._op.verbose else logger.ExportProgressLogger
- with log(self._op.filepath) as self.report:
+ 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)
diff --git a/korman/exporter/logger.py b/korman/exporter/logger.py
index 656819e..059e04b 100644
--- a/korman/exporter/logger.py
+++ b/korman/exporter/logger.py
@@ -13,6 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with Korman. If not, see .
+from ..korlib import ConsoleToggler
from pathlib import Path
import threading
import time
@@ -40,6 +41,8 @@ class _ExportLogger:
return self
def __exit__(self, type, value, traceback):
+ if value is not None:
+ ConsoleToggler().keep_console = True
self._file.close()
return False
diff --git a/korman/korlib/__init__.py b/korman/korlib/__init__.py
index 77b9457..7d1cfcc 100644
--- a/korman/korlib/__init__.py
+++ b/korman/korlib/__init__.py
@@ -71,4 +71,5 @@ except ImportError:
size = stream.readInt()
return (header, size)
else:
+ from .console import ConsoleToggler
from .texture import TEX_DETAIL_ALPHA, TEX_DETAIL_ADD, TEX_DETAIL_MULTIPLY
diff --git a/korman/korlib/console.py b/korman/korlib/console.py
new file mode 100644
index 0000000..d84106e
--- /dev/null
+++ b/korman/korlib/console.py
@@ -0,0 +1,83 @@
+# This file is part of Korman.
+#
+# Korman is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Korman is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Korman. If not, see .
+
+import bpy
+import ctypes
+import math
+import sys
+
+class ConsoleToggler:
+ _instance = None
+
+ def __init__(self, want_console=None):
+ if want_console is not None:
+ self._console_wanted = want_console
+
+ def __new__(cls, want_console=None):
+ if cls._instance is None:
+ assert want_console is not None
+ cls._instance = object.__new__(cls)
+ cls._instance._console_was_visible = cls.is_console_visible()
+ cls._instance._console_wanted = want_console
+ cls._instance._context_active = False
+ cls._instance.keep_console = False
+ return cls._instance
+
+ def __enter__(self):
+ if self._context_active:
+ raise RuntimeError("ConsoleToggler context manager is not reentrant")
+ self._console_visible = self.is_console_visible()
+ self._context_active = True
+ self.activate_console()
+ return self
+
+ def __exit__(self, type, value, traceback):
+ if not self._console_was_visible and self._console_wanted:
+ if self.keep_console:
+ # Blender thinks the console is currently not visible. However, it actually is.
+ # So, we will fire off the toggle operator to keep Blender's internal state valid
+ bpy.ops.wm.console_toggle()
+ else:
+ self.hide_console()
+ self._context_active = False
+ self.keep_console = False
+ return False
+
+ def activate_console(self):
+ if sys.platform == "win32":
+ hwnd = ctypes.windll.kernel32.GetConsoleWindow()
+ if self._console_wanted:
+ ctypes.windll.user32.ShowWindow(hwnd, 1)
+ if self._console_was_visible or self._console_wanted:
+ ctypes.windll.user32.BringWindowToTop(hwnd)
+
+ @staticmethod
+ def hide_console():
+ if sys.platform == "win32":
+ hwnd = ctypes.windll.kernel32.GetConsoleWindow()
+ ctypes.windll.user32.ShowWindow(hwnd, 0)
+
+ @staticmethod
+ def is_console_visible():
+ if sys.platform == "win32":
+ hwnd = ctypes.windll.kernel32.GetConsoleWindow()
+ return bool(ctypes.windll.user32.IsWindowVisible(hwnd))
+
+ @staticmethod
+ def is_platform_supported():
+ # If you read Blender's source code, GHOST_toggleConsole (the "Toggle System Console" menu
+ # item) is only implemented on Windows. The majority of our audience is on Windows as well,
+ # so I honestly don't see this as an issue...
+ return sys.platform == "win32"
diff --git a/korman/operators/op_export.py b/korman/operators/op_export.py
index a1de7b9..d65ee5c 100644
--- a/korman/operators/op_export.py
+++ b/korman/operators/op_export.py
@@ -22,6 +22,7 @@ import pstats
from .. import exporter
from ..properties.prop_world import PlasmaAge
from ..properties.modifiers.logic import game_versions
+from ..korlib import ConsoleToggler
class ExportOperator(bpy.types.Operator):
"""Exports ages for Cyan Worlds' Plasma Engine"""
@@ -49,6 +50,10 @@ class ExportOperator(bpy.types.Operator):
"verbose": (BoolProperty, {"name": "Display Verbose Log",
"description": "Shows the verbose export log in the console",
"default": False}),
+
+ "show_console": (BoolProperty, {"name": "Display Log Console",
+ "description": "Forces the Blender System Console open during the export",
+ "default": True}),
}
# This wigs out and very bad things happen if it's not directly on the operator...
@@ -62,6 +67,9 @@ class ExportOperator(bpy.types.Operator):
# The crazy mess we're doing with props on the fly means we have to explicitly draw them :(
layout.prop(age, "version")
layout.prop(age, "bake_lighting")
+ row = layout.row()
+ row.enabled = ConsoleToggler.is_platform_supported()
+ row.prop(age, "show_console")
layout.prop(age, "verbose")
layout.prop(age, "profile_export")