Simplified progress reports: Use simple module-level settings for
authorLukas Tönne <lukas.toenne@gmail.com>
Tue, 16 Dec 2014 09:21:56 +0000 (10:21 +0100)
committerLukas Tönne <lukas.toenne@gmail.com>
Tue, 16 Dec 2014 09:24:00 +0000 (10:24 +0100)
controlling output, and don't pass report types as extra args.

object_physics_meadow/hierarchical_dart_throw.py
object_physics_meadow/meadow.py
object_physics_meadow/patch.py
object_physics_meadow/progress.py [new file with mode: 0644]
object_physics_meadow/ui.py
object_physics_meadow/util.py

index 78f8ca7..b395896 100644 (file)
@@ -23,6 +23,7 @@ import bpy
 from math import *
 
 from object_physics_meadow.util import *
+from object_physics_meadow import progress
 
 # Implements Poisson Disk sampling according to
 # "Poisson Disk Point Sets by Hierarchical Dart Throwing"
@@ -62,7 +63,7 @@ class GridLevel():
         for k in range(kmin, kmax):
             for j in range(jmin, jmax):
                 for i in range(imin, imax):
-                    progress_add(1)
+                    progress.progress_add(1)
                     self.cells[c] = GridCell(i, j, k)
                     c += 1
 
@@ -150,7 +151,7 @@ class PointGrid():
         # modified range generator for progress reports
         def range_progress(tot):
             for i in range(tot):
-                progress_add(1)
+                progress.progress_add(1)
                 yield i
         # note: row-major, so we can address it with cells[i][j]
         self.cells = tuple(tuple(PointCell() for j in range_progress(self.nb)) for i in range(self.na))
@@ -236,8 +237,7 @@ def split_cell(radius2, b0, pgrid, child_level, cell, x0, x1, y0, y1, z0, z1):
             if not is_covered(radius2, b0, pgrid, child_level, ci, cj, cx0, cx1, cy0, cy1):
                 child_cell = child_level.activate(ci, cj, ck)
 
-def hierarchical_dart_throw_gen(radius, max_levels, xmin, xmax, ymin, ymax,
-                                progress_reporter=DummyProgressContext):
+def hierarchical_dart_throw_gen(radius, max_levels, xmin, xmax, ymin, ymax):
     radius2 = radius * radius
     gridmin = (xmin, ymin)
     gridmax = (xmax, ymax)
@@ -253,15 +253,15 @@ def hierarchical_dart_throw_gen(radius, max_levels, xmin, xmax, ymin, ymax,
         levels = [base_level] + [GridLevel(i, base_level.size / (2**i), radius) for i in range(1, max_levels)]
         epsilon = levels[-1].weight * 0.5
         
-        with progress_reporter("Activate Cells", 0, GridLevel.num_cells_in_range(imin, imax, jmin, jmax, 0, 1)):
+        with progress.ProgressContext("Activate Cells", 0, GridLevel.num_cells_in_range(imin, imax, jmin, jmax, 0, 1)):
             base_level.set_active_cells(imin, imax, jmin, jmax, 0, 1)
         
-        with progress_reporter("Init Spatial Grid", 0, PointGrid.num_cells(radius, gridmin, gridmax)):
+        with progress.ProgressContext("Init Spatial Grid", 0, PointGrid.num_cells(radius, gridmin, gridmax)):
             pgrid = PointGrid(radius, gridmin, gridmax)
         
-        with progress_reporter("Generate Samples", 0, num):
+        with progress.ProgressContext("Generate Samples", 0, num):
             for i in range(num):
-                progress_add(1)
+                progress.progress_add(1)
                 
                 if not any(level.cells for level in levels):
                     break
index 0e10bec..e3f2768 100644 (file)
@@ -45,7 +45,7 @@ def make_samples(context, gridob, groundob):
     
     # get a sample generator implementation
     #gen = best_candidate_gen(groundob.meadow.patch_radius, xmin, xmax, ymin, ymax)
-    gen = hierarchical_dart_throw_gen(groundob.meadow.patch_radius, groundob.meadow.sampling_levels, xmin, xmax, ymin, ymax, progress_reporter=make_progress_reporter(True, True))
+    gen = hierarchical_dart_throw_gen(groundob.meadow.patch_radius, groundob.meadow.sampling_levels, xmin, xmax, ymin, ymax)
     
     mat = groundob.matrix_world
     loc2D = [(mat * Vector(p[0:3] + (1.0,)))[0:2] for p in gen(groundob.meadow.seed, groundob.meadow.max_patches)]
index 1270a18..aa48565 100644 (file)
@@ -24,6 +24,7 @@ from bpy_extras import object_utils
 
 from object_physics_meadow import settings as _settings
 from object_physics_meadow.util import *
+from object_physics_meadow import progress
 
 #-----------------------------------------------------------------------
 
@@ -243,7 +244,7 @@ def count_bakeable(context):
             num += 1
     return num
 
-def bake_all(context, progress_reporter):
+def bake_all(context):
     settings = _settings.get(context)
     wm = context.window_manager
     
@@ -252,13 +253,13 @@ def bake_all(context, progress_reporter):
     
     total = count_bakeable(context)
     
-    with progress_reporter("Bake Blob", 0, total):
+    with progress.ProgressContext("Bake Blob", 0, total):
         for ob in patch_objects(context):
             for psys in ob.particle_systems:
-                progress_add(1)
+                progress.progress_add(1)
                 bake_psys(context, ob, psys)
 
-def patch_objects_rebake(context, progress_reporter=DummyProgressContext):
+def patch_objects_rebake(context):
     settings = _settings.get(context)
     wm = context.window_manager
     
@@ -270,6 +271,6 @@ def patch_objects_rebake(context, progress_reporter=DummyProgressContext):
         # XXX have to set this because bake operator only bakes up to the last frame ...
         scene.frame_current = scene.frame_end
         
-        bake_all(context, progress_reporter)
+        bake_all(context)
         
         scene.frame_set(curframe)
diff --git a/object_physics_meadow/progress.py b/object_physics_meadow/progress.py
new file mode 100644 (file)
index 0000000..16c5431
--- /dev/null
@@ -0,0 +1,134 @@
+### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program 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 2
+#  of the License, or (at your option) any later version.
+#
+#  This program 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 this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy, time, sys
+from math import *
+
+show_progress_bar = True
+show_stdout = False
+
+_progress_context = None
+
+def _get_time_string(x):
+    if x >= 0.0:
+        return time.strftime("%H:%M:%S", time.gmtime(x)) + ".%02d" % (int(x * 100.0) % 100)
+    else:
+        return "??:??:??.??"
+
+class ProgressContext():
+    def __init__(self, name, pmin, pmax):
+        self.name = name
+        self.pmin = pmin
+        self.pmax = pmax
+        self.tot = pmax - pmin
+        self.norm = 1.0 / float(self.tot) if self.tot > 0 else 0.0
+
+        self.pcur = pmin
+        self.perc_show = -2.0 # last displayed percentage, init to make sure we show the first time
+
+        self.duration = 0.0
+        self.start_time = 0.0
+
+    def __enter__(self):
+        global _progress_context, show_progress_bar, show_stdout
+
+        assert(_progress_context is None)
+        _progress_context = self
+        
+        self.start_time = time.time()
+
+        if show_progress_bar:
+            wm = bpy.context.window_manager
+            # always use 0..100 percentage on the progress counter,
+            # it does not display large numbers well
+            wm.progress_begin(0, 100)
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        global _progress_context, show_progress_bar, show_stdout
+
+        if show_progress_bar:
+            wm = bpy.context.window_manager
+            wm.progress_end()
+
+        if show_stdout:
+            # make a final report
+            done = self.pcur - self.pmin
+            sys.stdout.write("\r>> {}: {}/{}, {}".format(self.name,
+                                                                str(done).rjust(len(str(self.tot))), str(self.tot),
+                                                                _get_time_string(self.duration)))
+            # clean newline
+            sys.stdout.write("\n")
+            sys.stdout.flush()
+
+        assert(_progress_context is self)
+        _progress_context = None
+
+    def estimate_total_duration(self):
+        done = self.pcur - self.pmin
+        if done > 0:
+            return self.duration * self.tot / done
+        else:
+            return -1.0
+
+    def set_progress(self, value, message):
+        global _progress_context, show_progress_bar, show_stdout
+
+        self.pcur = value
+        done = value - self.pmin
+        perc = 100.0 * done * self.norm
+
+        # only write to progress indicator or stdout if the percentage actually changed
+        # avoids overhead for very frequent updates
+        if perc > self.perc_show + 1.0:
+            self.perc_show = perc
+            perc = min(max(perc, 0), 100)
+
+            self.duration = time.time() - self.start_time
+
+            if show_progress_bar:
+                wm = bpy.context.window_manager
+                wm.progress_update(perc)
+
+            if show_stdout:
+                bar = 50
+                filled = int(bar * done * self.norm)
+
+                eta = self.estimate_total_duration()
+
+                sys.stdout.write("\r>> {}: {}/{} [{}{}] {}/{} | {}".format(self.name,
+                                                                           str(done).rjust(len(str(self.tot))), str(self.tot),
+                                                                           '.' * filled, ' ' * (bar - filled),
+                                                                           _get_time_string(self.duration), _get_time_string(eta),
+                                                                           message))
+                sys.stdout.flush()
+
+def progress_set(value, message=""):
+    global _progress_context
+    
+    if not _progress_context:
+        return
+    _progress_context.set_progress(value, message)
+
+def progress_add(value, message=""):
+    global _progress_context
+
+    if not _progress_context:
+        return
+    _progress_context.set_progress(_progress_context.pcur + value, message)
index 9b616f3..ba5add2 100644 (file)
@@ -25,6 +25,17 @@ from bpy.props import *
 from object_physics_meadow import meadow, settings as _settings, patch, blob
 from object_physics_meadow.settings import find_meadow_object
 from object_physics_meadow.util import *
+from object_physics_meadow import progress
+
+# default progress reports
+def progress_default():
+    progress.show_progress_bar = True
+    progress.show_stdout = True
+# XXX baking: wm.progress updates are disabled for now,
+# because the bake operator overrides this with it's own progress numbers ...
+def progress_baking():
+    progress.show_progress_bar = False
+    progress.show_stdout = True
 
 class OBJECT_PT_Meadow(Panel):
     """Settings for meadow components"""
@@ -139,6 +150,7 @@ class MakeBlobsOperator(MeadowOperatorBase, Operator):
             return {'CANCELLED'}
         
         with ObjectSelection():
+            progress_default()
             meadow.make_blobs(context, blobgridob, groundob)
         
         return {'FINISHED'}
@@ -157,6 +169,7 @@ class DeleteBlobsOperator(MeadowOperatorBase, Operator):
         groundob = find_meadow_object(context, 'GROUND')
         
         with ObjectSelection():
+            progress_default()
             meadow.delete_blobs(context, groundob)
         
         return {'FINISHED'}
@@ -187,6 +200,7 @@ class MakePatchesOperator(MeadowOperatorBase, Operator):
             return {'CANCELLED'}
         
         with ObjectSelection():
+            progress_default()
             meadow.make_patches(context, blobgridob, groundob)
         
         return {'FINISHED'}
@@ -218,9 +232,8 @@ class RebakeMeadowOperator(MeadowOperatorBase, Operator):
     
     def execute(self, context):
         with ObjectSelection():
-            # XXX Note: wm.progress updates are disabled for now, because the bake
-            # operator overrides this with it's own progress numbers ...
-            patch.patch_objects_rebake(context, progress_reporter=make_progress_reporter(show_progress_bar=False, show_stdout=True))
+            progress_baking()
+            patch.patch_objects_rebake(context)
         return {'FINISHED'}
 
 
index 5f2127a..d7dafe1 100644 (file)
@@ -94,128 +94,3 @@ def set_object_parent(ob, parent):
     mat = ob.matrix_world
     ob.parent = parent
     ob.matrix_world = mat
-
-#-----------------------------------------------------------------------
-
-_progress_context = None
-
-def get_time_string(x):
-    if x >= 0.0:
-        return time.strftime("%H:%M:%S", time.gmtime(x)) + ".%02d" % (int(x * 100.0) % 100)
-    else:
-        return "??:??:??.??"
-
-def make_progress_reporter(show_progress_bar=True, show_stdout=False):
-
-    # internal class returned by the function, bound to output args
-    class ProgressContext():
-        def __init__(self, name, pmin, pmax):
-            self.name = name
-            self.pmin = pmin
-            self.pmax = pmax
-            self.tot = pmax - pmin
-            self.norm = 1.0 / float(self.tot) if self.tot > 0 else 0.0
-
-            self.pcur = pmin
-            self.perc_show = -2.0 # last displayed percentage, init to make sure we show the first time
-
-            self.duration = 0.0
-            self.start_time = 0.0
-
-        def __enter__(self):
-            global _progress_context
-
-            assert(_progress_context is None)
-            _progress_context = self
-            
-            self.start_time = time.time()
-
-            if show_progress_bar:
-                wm = bpy.context.window_manager
-                # always use 0..100 percentage on the progress counter,
-                # it does not display large numbers well
-                wm.progress_begin(0, 100)
-
-        def __exit__(self, exc_type, exc_value, traceback):
-            global _progress_context
-
-            if show_progress_bar:
-                wm = bpy.context.window_manager
-                wm.progress_end()
-
-            if show_stdout:
-                # make a final report
-                done = self.pcur - self.pmin
-                sys.stdout.write("\r>> {}: {}/{}, {}".format(self.name,
-                                                                    str(done).rjust(len(str(self.tot))), str(self.tot),
-                                                                    get_time_string(self.duration)))
-                # clean newline
-                sys.stdout.write("\n")
-                sys.stdout.flush()
-
-            assert(_progress_context is self)
-            _progress_context = None
-
-        def estimate_total_duration(self):
-            done = self.pcur - self.pmin
-            if done > 0:
-                return self.duration * self.tot / done
-            else:
-                return -1.0
-
-        def set_progress(self, value, message):
-            self.pcur = value
-            done = value - self.pmin
-            perc = 100.0 * done * self.norm
-
-            # only write to progress indicator or stdout if the percentage actually changed
-            # avoids overhead for very frequent updates
-            if perc > self.perc_show + 1.0:
-                self.perc_show = perc
-                perc = min(max(perc, 0), 100)
-
-                self.duration = time.time() - self.start_time
-
-                if show_progress_bar:
-                    wm = bpy.context.window_manager
-                    wm.progress_update(perc)
-
-                if show_stdout:
-                    bar = 50
-                    filled = int(bar * done * self.norm)
-
-                    eta = self.estimate_total_duration()
-
-                    sys.stdout.write("\r>> {}: {}/{} [{}{}] {}/{} | {}".format(self.name,
-                                                                               str(done).rjust(len(str(self.tot))), str(self.tot),
-                                                                               '.' * filled, ' ' * (bar - filled),
-                                                                               get_time_string(self.duration), get_time_string(eta),
-                                                                               message))
-                    sys.stdout.flush()
-
-    return ProgressContext
-
-# dummy context manager class to avoid clumsy conditionals when passing None
-class DummyProgressContext():
-    def __init__(self, name, pmin, pmax):
-        pass
-
-    def __enter__(self):
-        pass
-
-    def __exit__(self, exc_type, exc_value, traceback):
-        pass
-
-def progress_set(value, message=""):
-    global _progress_context
-    
-    if not _progress_context:
-        return
-    _progress_context.set_progress(value, message)
-
-def progress_add(value, message=""):
-    global _progress_context
-
-    if not _progress_context:
-        return
-    _progress_context.set_progress(_progress_context.pcur + value, message)