Browse Source

Fix #137

Unfortunately, this does not prevent "DAG zero..." from appearing
period. Rather, it just overwrites any junk printed to the console
during the export. The ANSI version is rather limited compared to the
Windows version and completely untested...
pull/152/head
Adam Johnson 5 years ago
parent
commit
b5d3f87c66
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 16
      korman/exporter/logger.py
  2. 2
      korman/korlib/__init__.py
  3. 75
      korman/korlib/console.py

16
korman/exporter/logger.py

@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with Korman. If not, see <http://www.gnu.org/licenses/>.
from ..korlib import ConsoleToggler
from ..korlib import ConsoleCursor, ConsoleToggler
from .explosions import NonfatalExportError
from pathlib import Path
import threading
@ -142,6 +142,7 @@ class ExportProgressLogger(_ExportLogger):
# because it is difficult to inspect the progress of Blender's internal operators. The best
# solution here is to move printing into a thread that can detect long-running ops and display
# something visible such as a moving elipsis
self._cursor = ConsoleCursor()
self._thread = threading.Thread(target=self._progress_thread)
self._queued_lines = []
self._print_condition = threading.Condition()
@ -283,6 +284,8 @@ class ExportProgressLogger(_ExportLogger):
def _progress_thread(self):
num_dots = 0
self._cursor.update()
while self._progress_alive:
with self._print_condition:
signalled = self._print_condition.wait(timeout=1.0)
@ -290,12 +293,16 @@ class ExportProgressLogger(_ExportLogger):
# First, we need to print out any queued whole lines.
# NOTE: no need to lock anything here as Blender uses CPython (GIL)
if self._queued_lines:
print(*self._queued_lines, sep='\n')
self._queued_lines.clear()
with self._cursor:
if self._queued_lines:
print(*self._queued_lines, sep='\n')
self._queued_lines.clear()
# Now, we need to print out the current volatile line, if any.
if self._volatile_line:
# On Windows, if we clear the line, the volatile line is nuked as well.
# Probably a race condition in the Win32 console host.
self._cursor.reset()
print(self._volatile_line, end="")
# If the proc is long running, let us display some elipses so as to not alarm the user
@ -305,6 +312,7 @@ class ExportProgressLogger(_ExportLogger):
else:
num_dots = 0
print('.' * num_dots, end=" " * (_MAX_ELIPSES - num_dots))
self._cursor.update()
def _progress_get_current(self):
return self._step_progress

2
korman/korlib/__init__.py

@ -72,7 +72,7 @@ else:
from _korlib import *
finally:
from .console import ConsoleToggler
from .console import ConsoleCursor, ConsoleToggler
from .python import *
from .texture import TEX_DETAIL_ALPHA, TEX_DETAIL_ADD, TEX_DETAIL_MULTIPLY

75
korman/korlib/console.py

@ -18,6 +18,81 @@ import ctypes
import math
import sys
if sys.platform == "win32":
class _Coord(ctypes.Structure):
_fields_ = [("x", ctypes.c_short),
("y", ctypes.c_short)]
class _SmallRect(ctypes.Structure):
_fields_ = [("Left", ctypes.c_short),
("Top", ctypes.c_short),
("Right", ctypes.c_short),
("Bottom", ctypes.c_short),]
class _ConsoleScreenBufferInfo(ctypes.Structure):
_fields_ = [("dwSize", _Coord),
("dwCursorPosition", _Coord),
("wAttributes", ctypes.c_ushort),
("srWindow", _SmallRect),
("dwMaximumWindowSize", _Coord)]
class _ConsoleCursor:
def __init__(self):
self._handle = ctypes.windll.kernel32.GetStdHandle(-11)
self.position = _Coord(0, 0)
def __del__(self):
ctypes.windll.kernel32.CloseHandle(self._handle)
@property
def _screen_buffer_info(self):
info = _ConsoleScreenBufferInfo()
ctypes.windll.kernel32.GetConsoleScreenBufferInfo(self._handle, ctypes.pointer(info))
return info
def clear(self):
info = self._screen_buffer_info
curPos = info.dwCursorPosition
num_cols = curPos.y - self.position.y
num_rows = curPos.x - self.position.x
num_chars = (info.dwSize.x * num_cols) + num_rows
if num_chars:
nWrite = ctypes.c_ulong()
empty_char = ctypes.c_char(b' ')
ctypes.windll.kernel32.FillConsoleOutputCharacterA(self._handle, empty_char,
num_chars, self.position,
ctypes.pointer(nWrite))
def reset(self):
ctypes.windll.kernel32.SetConsoleCursorPosition(self._handle, self.position)
def update(self):
info = _ConsoleScreenBufferInfo()
ctypes.windll.kernel32.GetConsoleScreenBufferInfo(self._handle, ctypes.pointer(info))
self.position = info.dwCursorPosition
else:
class _ConsoleCursor:
def clear(self):
# Only clears the current line, unfortunately.
sys.stdout.write("\x1B[K")
def reset(self):
# Forcibly clears the line after resetting, just in case more
# than one junk line was printed from somewhere else.
sys.stdout.write("\x1B[u\x1B[K")
def update(self):
sys.stdout.write("\x1B[s")
class ConsoleCursor(_ConsoleCursor):
def __enter__(self):
self.clear()
self.reset()
return self
def __exit__(self, type, value, traceback):
self.update()
class ConsoleToggler:
_instance = None

Loading…
Cancel
Save