From 589aa0c293ed4f6bc09211ee80ff35e872f7d983 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 13:32:53 +0200 Subject: [PATCH 01/24] set always mark in to 0 and mark out to mark in + duration - 1 --- pype/hosts/tvpaint/lib.py | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/pype/hosts/tvpaint/lib.py b/pype/hosts/tvpaint/lib.py index 654773b0f2e..405c90191f2 100644 --- a/pype/hosts/tvpaint/lib.py +++ b/pype/hosts/tvpaint/lib.py @@ -48,24 +48,19 @@ def set_context_settings(asset): frame_start = asset["data"].get("frameStart") frame_end = asset["data"].get("frameEnd") - if frame_start and frame_end: - handles = asset["data"].get("handles") or 0 - handle_start = asset["data"].get("handleStart") - if handle_start is None: - handle_start = handles + if frame_start is None or frame_end is None: + print("Frame range was not found!") + return - handle_end = asset["data"].get("handleEnd") - if handle_end is None: - handle_end = handles + handles = asset["data"].get("handles") or 0 + handle_start = asset["data"].get("handleStart") + handle_end = asset["data"].get("handleEnd") + if handle_start is None or handle_end is None: + handle_start = handle_end = handles - frame_start -= int(handle_start) - frame_end += int(handle_end) + # Always start from 0 Mark In and set only Mark Out + mark_in = 0 + mark_out = mark_in + (frame_end - frame_start) + handle_start + handle_end - avalon.tvpaint.lib.execute_george( - "tv_markin {} set".format(frame_start - 1) - ) - avalon.tvpaint.lib.execute_george( - "tv_markout {} set".format(frame_end - 1) - ) - else: - print("Frame range was not found!") + avalon.tvpaint.lib.execute_george("tv_markin {} set".format(mark_in)) + avalon.tvpaint.lib.execute_george("tv_markout {} set".format(mark_out)) From f00e18d404bad6a83b61d034acbe35a754d1e1c0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 13:33:20 +0200 Subject: [PATCH 02/24] set frameStart and frameEnd on instance to context frameStart and frameEnd --- pype/plugins/tvpaint/publish/collect_instances.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/plugins/tvpaint/publish/collect_instances.py b/pype/plugins/tvpaint/publish/collect_instances.py index cc236734e5f..cf0949debe8 100644 --- a/pype/plugins/tvpaint/publish/collect_instances.py +++ b/pype/plugins/tvpaint/publish/collect_instances.py @@ -86,8 +86,9 @@ def process(self, context): instance.data["publish"] = any_visible - instance.data["frameStart"] = context.data["sceneMarkIn"] + 1 - instance.data["frameEnd"] = context.data["sceneMarkOut"] + 1 + # Output frame range X not rendered output from TVPaint + instance.data["frameStart"] = context.data["sceneFrameStart"] + instance.data["frameEnd"] = context.data["sceneFrameEnd"] self.log.debug("Created instance: {}\n{}".format( instance, json.dumps(instance.data, indent=4) From 5bb42803741d103023dc1683824c89292b2a79b8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 13:34:42 +0200 Subject: [PATCH 03/24] validate only duration in validate marks and repair does not change Mark In value --- .../plugins/tvpaint/publish/validate_marks.py | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/pype/plugins/tvpaint/publish/validate_marks.py b/pype/plugins/tvpaint/publish/validate_marks.py index 73486d10059..f8974f19bba 100644 --- a/pype/plugins/tvpaint/publish/validate_marks.py +++ b/pype/plugins/tvpaint/publish/validate_marks.py @@ -14,10 +14,9 @@ class ValidateMarksRepair(pyblish.api.Action): def process(self, context, plugin): expected_data = ValidateMarks.get_expected_data(context) - expected_data["markIn"] -= 1 - expected_data["markOut"] -= 1 - - lib.execute_george("tv_markin {} set".format(expected_data["markIn"])) + lib.execute_george( + "tv_markin {} set".format(expected_data["markIn"]) + ) lib.execute_george( "tv_markout {} set".format(expected_data["markOut"]) ) @@ -33,18 +32,32 @@ class ValidateMarks(pyblish.api.ContextPlugin): @staticmethod def get_expected_data(context): + scene_mark_in = context.data["sceneMarkIn"] + + # Data collected in `CollectAvalonEntities` + frame_end = context.data["frameEnd"] + frame_start = context.data["frameStart"] + handle_start = context.data["handleStart"] + handle_end = context.data["handleEnd"] + + # Calculate expeted Mark out (Mark In + duration - 1) + expected_mark_out = ( + scene_mark_in + + (frame_end - frame_start) + + handle_start + handle_end + ) return { - "markIn": int(context.data["frameStart"]), + "markIn": scene_mark_in, "markInState": True, - "markOut": int(context.data["frameEnd"]), + "markOut": expected_mark_out, "markOutState": True } def process(self, context): current_data = { - "markIn": context.data["sceneMarkIn"] + 1, + "markIn": context.data["sceneMarkIn"], "markInState": context.data["sceneMarkInState"], - "markOut": context.data["sceneMarkOut"] + 1, + "markOut": context.data["sceneMarkOut"], "markOutState": context.data["sceneMarkOutState"] } expected_data = self.get_expected_data(context) From 44bc83b32d74e62de0271c870c43e7582253c66a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 13:34:54 +0200 Subject: [PATCH 04/24] changed label of validator --- pype/plugins/tvpaint/publish/validate_marks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/tvpaint/publish/validate_marks.py b/pype/plugins/tvpaint/publish/validate_marks.py index f8974f19bba..853ca973ce0 100644 --- a/pype/plugins/tvpaint/publish/validate_marks.py +++ b/pype/plugins/tvpaint/publish/validate_marks.py @@ -25,7 +25,7 @@ def process(self, context, plugin): class ValidateMarks(pyblish.api.ContextPlugin): """Validate mark in and out are enabled.""" - label = "Validate Marks" + label = "Validate Mark In/Out" order = pyblish.api.ValidatorOrder optional = True actions = [ValidateMarksRepair] From 49e70b77d0efc49cd9bdf0619a8e66f0296d9442 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 13:35:00 +0200 Subject: [PATCH 05/24] added small docstring --- pype/plugins/tvpaint/publish/validate_marks.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pype/plugins/tvpaint/publish/validate_marks.py b/pype/plugins/tvpaint/publish/validate_marks.py index 853ca973ce0..e2ef81e4a44 100644 --- a/pype/plugins/tvpaint/publish/validate_marks.py +++ b/pype/plugins/tvpaint/publish/validate_marks.py @@ -23,7 +23,11 @@ def process(self, context, plugin): class ValidateMarks(pyblish.api.ContextPlugin): - """Validate mark in and out are enabled.""" + """Validate mark in and out are enabled and it's duration. + + Mark In/Out does not have to match frameStart and frameEnd but duration is + important. + """ label = "Validate Mark In/Out" order = pyblish.api.ValidatorOrder From 8530ad779542ea9efc9a25dde7484f4052e0d42f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 13:50:33 +0200 Subject: [PATCH 06/24] pass mark in/out to render methods --- .../plugins/tvpaint/publish/extract_sequence.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index cec3e2edbca..1489fa67aec 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -48,6 +48,9 @@ def process(self, instance): frame_start = instance.data["frameStart"] frame_end = instance.data["frameEnd"] + mark_in = instance.context.data["sceneMarkIn"] + mark_out = instance.data["sceneMarkOut"] + filename_template = self._get_filename_template(frame_end) ext = os.path.splitext(filename_template)[1].replace(".", "") @@ -66,12 +69,16 @@ def process(self, instance): if instance.data["family"] == "review": repre_files, thumbnail_fullpath = self.render_review( - filename_template, output_dir, frame_start, frame_end + filename_template, output_dir, + frame_start, frame_end, + mark_in, mark_out ) else: # Render output repre_files, thumbnail_fullpath = self.render( - filename_template, output_dir, frame_start, frame_end, + filename_template, output_dir, + frame_start, frame_end, + mark_in, mark_out, filtered_layers ) @@ -134,7 +141,8 @@ def _get_filename_template(self, frame_end): return "{{frame:0>{}}}".format(frame_padding) + ".png" def render_review( - self, filename_template, output_dir, frame_start, frame_end + self, filename_template, output_dir, + frame_start, frame_end, mark_in, mark_out ): """ Export images from TVPaint using `tv_savesequence` command. @@ -187,7 +195,8 @@ def render_review( return output, thumbnail_filepath def render( - self, filename_template, output_dir, frame_start, frame_end, layers + self, filename_template, output_dir, + frame_start, frame_end, mark_in, mark_out, layers ): """ Export images from TVPaint. From c314d600eaedb3376f22046f41a92e756571b7e8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 13:53:02 +0200 Subject: [PATCH 07/24] use proper mark in/out --- pype/plugins/tvpaint/publish/extract_sequence.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index 1489fa67aec..c0d0b4be738 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -164,8 +164,6 @@ def render_review( output_dir, filename_template.format(frame=frame_start) ) - mark_in = frame_start - 1 - mark_out = frame_end - 1 george_script_lines = [ "tv_SaveMode \"PNG\"", @@ -233,9 +231,6 @@ def render( self.log.debug("Collecting pre/post behavior of individual layers.") behavior_by_layer_id = lib.get_layers_pre_post_behavior(layer_ids) - mark_in_index = frame_start - 1 - mark_out_index = frame_end - 1 - tmp_filename_template = "pos_{pos}." + filename_template files_by_position = {} @@ -248,15 +243,15 @@ def render( tmp_filename_template, output_dir, behavior, - mark_in_index, - mark_out_index + mark_in, + mark_out ) files_by_position[position] = files_by_frames output_filepaths = self._composite_files( files_by_position, - mark_in_index, - mark_out_index, + mark_in, + mark_out, filename_template, output_dir ) From 1917504e4e190f2ba0578aa50c00ae0fa40e4d5e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 14:08:25 +0200 Subject: [PATCH 08/24] don't use frame start/end --- pype/plugins/tvpaint/publish/extract_sequence.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index c0d0b4be738..5720c25071a 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -45,13 +45,10 @@ def process(self, instance): ) family_lowered = instance.data["family"].lower() - frame_start = instance.data["frameStart"] - frame_end = instance.data["frameEnd"] - mark_in = instance.context.data["sceneMarkIn"] mark_out = instance.data["sceneMarkOut"] - filename_template = self._get_filename_template(frame_end) + filename_template = self._get_filename_template(mark_out) ext = os.path.splitext(filename_template)[1].replace(".", "") self.log.debug("Using file template \"{}\"".format(filename_template)) @@ -70,14 +67,12 @@ def process(self, instance): if instance.data["family"] == "review": repre_files, thumbnail_fullpath = self.render_review( filename_template, output_dir, - frame_start, frame_end, mark_in, mark_out ) else: # Render output repre_files, thumbnail_fullpath = self.render( filename_template, output_dir, - frame_start, frame_end, mark_in, mark_out, filtered_layers ) @@ -141,8 +136,7 @@ def _get_filename_template(self, frame_end): return "{{frame:0>{}}}".format(frame_padding) + ".png" def render_review( - self, filename_template, output_dir, - frame_start, frame_end, mark_in, mark_out + self, filename_template, output_dir, mark_in, mark_out ): """ Export images from TVPaint using `tv_savesequence` command. @@ -162,7 +156,7 @@ def render_review( self.log.debug("Preparing data for rendering.") first_frame_filepath = os.path.join( output_dir, - filename_template.format(frame=frame_start) + filename_template.format(frame=mark_in) ) george_script_lines = [ @@ -178,7 +172,7 @@ def render_review( output = [] first_frame_filepath = None - for frame in range(frame_start, frame_end + 1): + for frame in range(mark_in, mark_out + 1): filename = filename_template.format(frame=frame) output.append(filename) if first_frame_filepath is None: @@ -194,7 +188,7 @@ def render_review( def render( self, filename_template, output_dir, - frame_start, frame_end, mark_in, mark_out, layers + mark_in, mark_out, layers ): """ Export images from TVPaint. From 55c3e370527be906b04150d5e5fdbfd1d891fbb5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 14:08:46 +0200 Subject: [PATCH 09/24] add frameStart and frameEnd only if representation is sequence --- pype/plugins/tvpaint/publish/extract_sequence.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index 5720c25071a..2c87e94e799 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -83,7 +83,8 @@ def process(self, instance): tags.append("review") # Sequence of one frame - if len(repre_files) == 1: + single_file = len(repre_files) == 1 + if single_file: repre_files = repre_files[0] new_repre = { @@ -91,10 +92,15 @@ def process(self, instance): "ext": ext, "files": repre_files, "stagingDir": output_dir, - "frameStart": frame_start, - "frameEnd": frame_end, "tags": tags } + + if not single_file: + frame_start = instance.data["frameStart"] + frame_end = instance.data["frameEnd"] + new_repre["frameStart"] = frame_start + new_repre["frameEnd"] = frame_end + self.log.debug("Creating new representation: {}".format(new_repre)) instance.data["representations"].append(new_repre) From d79bb829615d21a144a5f638ff9eeb5967e0c288 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 14:09:01 +0200 Subject: [PATCH 10/24] skipe representation creation if nothing was rendered --- pype/plugins/tvpaint/publish/extract_sequence.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index 2c87e94e799..c89e0dc48a5 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -77,6 +77,11 @@ def process(self, instance): filtered_layers ) + # Sequence of one frame + if not repre_files: + self.log.warning("Extractor did not create any output.") + return + # Fill tags and new families tags = [] if family_lowered in ("review", "renderlayer"): From 5cfa9c63fe7199bf6ce0dd03d225674ec9e9b698 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 14:09:15 +0200 Subject: [PATCH 11/24] fix return value --- pype/plugins/tvpaint/publish/extract_sequence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index c89e0dc48a5..dace9c66100 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -231,7 +231,7 @@ def render( # Sort layer positions in reverse order sorted_positions = list(reversed(sorted(layers_by_position.keys()))) if not sorted_positions: - return + return [], None self.log.debug("Collecting pre/post behavior of individual layers.") behavior_by_layer_id = lib.get_layers_pre_post_behavior(layer_ids) From c0951d984999005b82b551b6dd176161bc279ec5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 14:09:49 +0200 Subject: [PATCH 12/24] add more check for rendered output --- .../tvpaint/publish/extract_sequence.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index dace9c66100..1be20f8e108 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -251,7 +251,24 @@ def render( mark_in, mark_out ) - files_by_position[position] = files_by_frames + if files_by_frames: + files_by_position[position] = files_by_frames + else: + self.log.warning(( + "Skipped layer \"{}\". Probably out of Mark In/Out range." + ).format(layer["name"])) + + if not files_by_position: + layer_names = set(layer["name"] for layer in layers) + joined_names = ", ".join( + ["\"{}\"".format(name) for name in layer_names] + ) + self.log.warning( + "Layers {} do not have content in range {} - {}".format( + joined_names, mark_in, mark_out + ) + ) + return [], None output_filepaths = self._composite_files( files_by_position, From 45ec2eaec5e43370e3ef046a882c2972b0220ab4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 14:10:42 +0200 Subject: [PATCH 13/24] skip layers without content in mark in/out range --- .../tvpaint/publish/extract_sequence.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index 1be20f8e108..7929334f1fb 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -309,6 +309,22 @@ def _render_layer( layer_id = layer["layer_id"] frame_start_index = layer["frame_start"] frame_end_index = layer["frame_end"] + + pre_behavior = behavior["pre"] + post_behavior = behavior["post"] + + # Check if layer is before mark in + if frame_end_index < mark_in_index: + # Skip layer if post behavior is "none" + if post_behavior == "none": + return {} + + # Check if layer is after mark out + elif frame_start_index > mark_out_index: + # Skip layer if pre behavior is "none" + if pre_behavior == "none": + return {} + exposure_frames = lib.get_exposure_frames( layer_id, frame_start_index, frame_end_index ) @@ -367,8 +383,6 @@ def _render_layer( self.log.debug("Filled frames {}".format(str(_debug_filled_frames))) # Fill frames by pre/post behavior of layer - pre_behavior = behavior["pre"] - post_behavior = behavior["post"] self.log.debug(( "Completing image sequence of layer by pre/post behavior." " PRE: {} | POST: {}" From 4516c694a4c5a07c8e1f2314c09c8ad06c123371 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 14:13:54 +0200 Subject: [PATCH 14/24] formatting changes --- pype/plugins/tvpaint/publish/extract_sequence.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index 7929334f1fb..16452882ff6 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -66,8 +66,7 @@ def process(self, instance): if instance.data["family"] == "review": repre_files, thumbnail_fullpath = self.render_review( - filename_template, output_dir, - mark_in, mark_out + filename_template, output_dir, mark_in, mark_out ) else: # Render output @@ -198,8 +197,7 @@ def render_review( return output, thumbnail_filepath def render( - self, filename_template, output_dir, - mark_in, mark_out, layers + self, filename_template, output_dir, mark_in, mark_out, layers ): """ Export images from TVPaint. From d0eab719e4b5a0b691bc76aea96df402fc5604b2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 14:55:42 +0200 Subject: [PATCH 15/24] fixed keys used for frame start/end --- pype/plugins/tvpaint/publish/collect_instances.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/plugins/tvpaint/publish/collect_instances.py b/pype/plugins/tvpaint/publish/collect_instances.py index cf0949debe8..d27246a9935 100644 --- a/pype/plugins/tvpaint/publish/collect_instances.py +++ b/pype/plugins/tvpaint/publish/collect_instances.py @@ -87,8 +87,8 @@ def process(self, context): instance.data["publish"] = any_visible # Output frame range X not rendered output from TVPaint - instance.data["frameStart"] = context.data["sceneFrameStart"] - instance.data["frameEnd"] = context.data["sceneFrameEnd"] + instance.data["frameStart"] = context.data["frameStart"] + instance.data["frameEnd"] = context.data["frameEnd"] self.log.debug("Created instance: {}\n{}".format( instance, json.dumps(instance.data, indent=4) From 6e1d3fd48b5778e53eadd6cd66637b4e31a725d9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 15:49:04 +0200 Subject: [PATCH 16/24] added frame collector which happens after avalon context collector --- .../publish/collect_instance_frames.py | 31 +++++++++++++++++++ .../tvpaint/publish/collect_instances.py | 4 --- 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 pype/plugins/tvpaint/publish/collect_instance_frames.py diff --git a/pype/plugins/tvpaint/publish/collect_instance_frames.py b/pype/plugins/tvpaint/publish/collect_instance_frames.py new file mode 100644 index 00000000000..b3488c29fee --- /dev/null +++ b/pype/plugins/tvpaint/publish/collect_instance_frames.py @@ -0,0 +1,31 @@ +import pyblish.api + + +class CollectOutputFrameRange(pyblish.api.ContextPlugin): + label = "Collect output frame range" + order = pyblish.api.CollectorOrder + hosts = ["tvpaint"] + + def process(self, context): + for instance in context: + frame_start = instance.data.get("frameStart") + frame_end = instance.data.get("frameEnd") + if frame_start is not None and frame_end is not None: + self.log.debug( + "Instance {} already has set frames {}-{}".format( + str(instance), frame_start, frame_end + ) + ) + return + + frame_start = context.data.get("frameStart") + frame_end = context.data.get("frameEnd") + + instance.data["frameStart"] = frame_start + instance.data["frameEnd"] = frame_end + + self.log.info( + "Set frames {}-{} on instance {} ".format( + frame_start, frame_end, str(instance) + ) + ) diff --git a/pype/plugins/tvpaint/publish/collect_instances.py b/pype/plugins/tvpaint/publish/collect_instances.py index d27246a9935..27bd8e9edef 100644 --- a/pype/plugins/tvpaint/publish/collect_instances.py +++ b/pype/plugins/tvpaint/publish/collect_instances.py @@ -86,10 +86,6 @@ def process(self, context): instance.data["publish"] = any_visible - # Output frame range X not rendered output from TVPaint - instance.data["frameStart"] = context.data["frameStart"] - instance.data["frameEnd"] = context.data["frameEnd"] - self.log.debug("Created instance: {}\n{}".format( instance, json.dumps(instance.data, indent=4) )) From 217106d3c4d564ce26736e3d50a6a5e4657b5bdc Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 15:49:40 +0200 Subject: [PATCH 17/24] rendered frames are renamed to right sequence frames --- .../tvpaint/publish/extract_sequence.py | 85 +++++++++++++------ 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index 16452882ff6..5949288e3e0 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -46,7 +46,10 @@ def process(self, instance): family_lowered = instance.data["family"].lower() mark_in = instance.context.data["sceneMarkIn"] - mark_out = instance.data["sceneMarkOut"] + mark_out = instance.context.data["sceneMarkOut"] + # Frame start/end may be stored as float + frame_start = int(instance.data["frameStart"]) + frame_end = int(instance.data["frameEnd"]) filename_template = self._get_filename_template(mark_out) ext = os.path.splitext(filename_template)[1].replace(".", "") @@ -66,13 +69,16 @@ def process(self, instance): if instance.data["family"] == "review": repre_files, thumbnail_fullpath = self.render_review( - filename_template, output_dir, mark_in, mark_out + filename_template, output_dir, + mark_in, mark_out, + frame_start, frame_end ) else: # Render output repre_files, thumbnail_fullpath = self.render( filename_template, output_dir, mark_in, mark_out, + frame_start, frame_end, filtered_layers ) @@ -100,8 +106,6 @@ def process(self, instance): } if not single_file: - frame_start = instance.data["frameStart"] - frame_end = instance.data["frameEnd"] new_repre["frameStart"] = frame_start new_repre["frameEnd"] = frame_end @@ -146,7 +150,8 @@ def _get_filename_template(self, frame_end): return "{{frame:0>{}}}".format(frame_padding) + ".png" def render_review( - self, filename_template, output_dir, mark_in, mark_out + self, filename_template, output_dir, mark_in, mark_out, + frame_start, frame_end ): """ Export images from TVPaint using `tv_savesequence` command. @@ -180,13 +185,28 @@ def render_review( ] lib.execute_george_through_file("\n".join(george_script_lines)) - output = [] + reversed_repre_filepaths = [] + marks_range = range(mark_out, mark_in - 1, -1) + frames_range = range(frame_end, frame_start - 1, -1) + for mark, frame in zip(marks_range, frames_range): + new_filename = filename_template.format(frame=frame) + new_filepath = os.path.join(output_dir, new_filename) + reversed_repre_filepaths.append(new_filepath) + + if mark != frame: + old_filename = filename_template.format(frame=mark) + old_filepath = os.path.join(output_dir, old_filename) + os.rename(old_filepath, new_filepath) + + repre_filepaths = list(reversed(reversed_repre_filepaths)) + repre_files = [ + os.path.basename(path) + for path in repre_filepaths + ] + first_frame_filepath = None - for frame in range(mark_in, mark_out + 1): - filename = filename_template.format(frame=frame) - output.append(filename) - if first_frame_filepath is None: - first_frame_filepath = os.path.join(output_dir, filename) + if repre_filepaths: + first_frame_filepath = repre_filepaths[0] thumbnail_filepath = os.path.join(output_dir, "thumbnail.jpg") if first_frame_filepath and os.path.exists(first_frame_filepath): @@ -194,10 +214,11 @@ def render_review( thumbnail_obj = Image.new("RGB", source_img.size, (255, 255, 255)) thumbnail_obj.paste(source_img) thumbnail_obj.save(thumbnail_filepath) - return output, thumbnail_filepath + return repre_files, thumbnail_filepath def render( - self, filename_template, output_dir, mark_in, mark_out, layers + self, filename_template, output_dir, mark_in, mark_out, + frame_start, frame_end, layers ): """ Export images from TVPaint. @@ -268,7 +289,7 @@ def render( ) return [], None - output_filepaths = self._composite_files( + output_filepaths_by_frame = self._composite_files( files_by_position, mark_in, mark_out, @@ -277,11 +298,29 @@ def render( ) self._cleanup_tmp_files(files_by_position) + reversed_repre_filepaths = [] + marks_range = range(mark_out, mark_in - 1, -1) + frames_range = range(frame_end, frame_start - 1, -1) + for mark, frame in zip(marks_range, frames_range): + new_filename = filename_template.format(frame=frame) + new_filepath = os.path.join(output_dir, new_filename) + reversed_repre_filepaths.append(new_filepath) + + if mark != frame: + old_filepath = output_filepaths_by_frame[mark] + os.rename(old_filepath, new_filepath) + + repre_filepaths = list(reversed(reversed_repre_filepaths)) + repre_files = [ + os.path.basename(path) + for path in repre_filepaths + ] + thumbnail_src_filepath = None - thumbnail_filepath = None - if output_filepaths: - thumbnail_src_filepath = tuple(sorted(output_filepaths))[0] + if repre_filepaths: + thumbnail_src_filepath = repre_filepaths[0] + thumbnail_filepath = None if thumbnail_src_filepath and os.path.exists(thumbnail_src_filepath): source_img = Image.open(thumbnail_src_filepath) thumbnail_filepath = os.path.join(output_dir, "thumbnail.jpg") @@ -289,10 +328,6 @@ def render( thumbnail_obj.paste(source_img) thumbnail_obj.save(thumbnail_filepath) - repre_files = [ - os.path.basename(path) - for path in output_filepaths - ] return repre_files, thumbnail_filepath def _render_layer( @@ -573,14 +608,14 @@ def _composite_files( process_count -= 1 processes = {} - output_filepaths = [] + output_filepaths_by_frame = {} missing_frame_paths = [] random_frame_path = None for frame_idx in sorted(images_by_frame.keys()): image_filepaths = images_by_frame[frame_idx] output_filename = filename_template.format(frame=frame_idx + 1) output_filepath = os.path.join(output_dir, output_filename) - output_filepaths.append(output_filepath) + output_filepaths_by_frame[frame_idx] = output_filepath # Store information about missing frame and skip if not image_filepaths: @@ -604,7 +639,7 @@ def _composite_files( random_frame_path = output_filepath self.log.info( - "Running {} compositing processes - this mey take a while.".format( + "Running {} compositing processes - this may take a while.".format( len(processes) ) ) @@ -646,7 +681,7 @@ def _composite_files( transparent_filepath = filepath else: self._copy_image(transparent_filepath, filepath) - return output_filepaths + return output_filepaths_by_frame def _cleanup_tmp_files(self, files_by_position): """Remove temporary files that were used for compositing.""" From 74f763da70d3c43f49d937002aa9b816d88de4c7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 15:52:02 +0200 Subject: [PATCH 18/24] use bigger value of mark out of frame end to prepare template --- pype/plugins/tvpaint/publish/extract_sequence.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index 5949288e3e0..fa4aebbbe7d 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -51,7 +51,10 @@ def process(self, instance): frame_start = int(instance.data["frameStart"]) frame_end = int(instance.data["frameEnd"]) - filename_template = self._get_filename_template(mark_out) + filename_template = self._get_filename_template( + # Use the biggest number + max(mark_out, frame_end) + ) ext = os.path.splitext(filename_template)[1].replace(".", "") self.log.debug("Using file template \"{}\"".format(filename_template)) From 2d2fb573ec81c9e8e7781ab402cf3afb0e109c3a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Apr 2021 16:00:30 +0200 Subject: [PATCH 19/24] added docstring to new collector --- pype/plugins/tvpaint/publish/collect_instance_frames.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/plugins/tvpaint/publish/collect_instance_frames.py b/pype/plugins/tvpaint/publish/collect_instance_frames.py index b3488c29fee..f291c363b8e 100644 --- a/pype/plugins/tvpaint/publish/collect_instance_frames.py +++ b/pype/plugins/tvpaint/publish/collect_instance_frames.py @@ -2,6 +2,12 @@ class CollectOutputFrameRange(pyblish.api.ContextPlugin): + """Collect frame start/end from context. + + When instances are collected context does not contain `frameStart` and + `frameEnd` keys yet. They are collected in global plugin + `CollectAvalonEntities`. + """ label = "Collect output frame range" order = pyblish.api.CollectorOrder hosts = ["tvpaint"] From 8edd552f4db8f4cbbd7f6224e4b1d9f244185ca9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 29 Apr 2021 11:56:26 +0200 Subject: [PATCH 20/24] render methods do not rename output filenames only render mark in->out --- .../tvpaint/publish/extract_sequence.py | 101 +++++++----------- 1 file changed, 37 insertions(+), 64 deletions(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index fa4aebbbe7d..c2fcf771cb7 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -71,22 +71,19 @@ def process(self, instance): ) if instance.data["family"] == "review": - repre_files, thumbnail_fullpath = self.render_review( - filename_template, output_dir, - mark_in, mark_out, - frame_start, frame_end + output_filenames, thumbnail_fullpath = self.render_review( + filename_template, output_dir, mark_in, mark_out ) else: # Render output - repre_files, thumbnail_fullpath = self.render( + output_filenames, thumbnail_fullpath = self.render( filename_template, output_dir, mark_in, mark_out, - frame_start, frame_end, filtered_layers ) # Sequence of one frame - if not repre_files: + if not output_filenames: self.log.warning("Extractor did not create any output.") return @@ -152,10 +149,7 @@ def _get_filename_template(self, frame_end): return "{{frame:0>{}}}".format(frame_padding) + ".png" - def render_review( - self, filename_template, output_dir, mark_in, mark_out, - frame_start, frame_end - ): + def render_review(self, filename_template, output_dir, mark_in, mark_out): """ Export images from TVPaint using `tv_savesequence` command. Args: @@ -164,8 +158,8 @@ def render_review( keyword argument `{frame}` or index argument (for same value). Extension in template must match `save_mode`. output_dir (str): Directory where files will be stored. - first_frame (int): Starting frame from which export will begin. - last_frame (int): On which frame export will end. + mark_in (int): Starting frame index from which export will begin. + mark_out (int): On which frame index export will end. Retruns: tuple: With 2 items first is list of filenames second is path to @@ -188,28 +182,22 @@ def render_review( ] lib.execute_george_through_file("\n".join(george_script_lines)) - reversed_repre_filepaths = [] - marks_range = range(mark_out, mark_in - 1, -1) - frames_range = range(frame_end, frame_start - 1, -1) - for mark, frame in zip(marks_range, frames_range): - new_filename = filename_template.format(frame=frame) - new_filepath = os.path.join(output_dir, new_filename) - reversed_repre_filepaths.append(new_filepath) - - if mark != frame: - old_filename = filename_template.format(frame=mark) - old_filepath = os.path.join(output_dir, old_filename) - os.rename(old_filepath, new_filepath) - - repre_filepaths = list(reversed(reversed_repre_filepaths)) - repre_files = [ - os.path.basename(path) - for path in repre_filepaths - ] - first_frame_filepath = None - if repre_filepaths: - first_frame_filepath = repre_filepaths[0] + output_filenames = [] + for frame in range(mark_in, mark_out + 1): + filename = filename_template.format(frame=frame) + output_filenames.append(filename) + + filepath = os.path.join(output_dir, filename) + if not os.path.exists(filepath): + raise AssertionError( + "Output was not rendered. File was not found {}".format( + filepath + ) + ) + + if first_frame_filepath is None: + first_frame_filepath = filepath thumbnail_filepath = os.path.join(output_dir, "thumbnail.jpg") if first_frame_filepath and os.path.exists(first_frame_filepath): @@ -217,12 +205,10 @@ def render_review( thumbnail_obj = Image.new("RGB", source_img.size, (255, 255, 255)) thumbnail_obj.paste(source_img) thumbnail_obj.save(thumbnail_filepath) - return repre_files, thumbnail_filepath - def render( - self, filename_template, output_dir, mark_in, mark_out, - frame_start, frame_end, layers - ): + return output_filenames, thumbnail_filepath + + def render(self, filename_template, output_dir, mark_in, mark_out, layers): """ Export images from TVPaint. Args: @@ -231,8 +217,8 @@ def render( keyword argument `{frame}` or index argument (for same value). Extension in template must match `save_mode`. output_dir (str): Directory where files will be stored. - first_frame (int): Starting frame from which export will begin. - last_frame (int): On which frame export will end. + mark_in (int): Starting frame index from which export will begin. + mark_out (int): On which frame index export will end. layers (list): List of layers to be exported. Retruns: @@ -292,7 +278,7 @@ def render( ) return [], None - output_filepaths_by_frame = self._composite_files( + output_filepaths = self._composite_files( files_by_position, mark_in, mark_out, @@ -301,27 +287,14 @@ def render( ) self._cleanup_tmp_files(files_by_position) - reversed_repre_filepaths = [] - marks_range = range(mark_out, mark_in - 1, -1) - frames_range = range(frame_end, frame_start - 1, -1) - for mark, frame in zip(marks_range, frames_range): - new_filename = filename_template.format(frame=frame) - new_filepath = os.path.join(output_dir, new_filename) - reversed_repre_filepaths.append(new_filepath) - - if mark != frame: - old_filepath = output_filepaths_by_frame[mark] - os.rename(old_filepath, new_filepath) - - repre_filepaths = list(reversed(reversed_repre_filepaths)) - repre_files = [ - os.path.basename(path) - for path in repre_filepaths + output_filenames = [ + os.path.basename(filepath) + for filepath in output_filepaths ] thumbnail_src_filepath = None - if repre_filepaths: - thumbnail_src_filepath = repre_filepaths[0] + if output_filepaths: + thumbnail_src_filepath = output_filepaths[0] thumbnail_filepath = None if thumbnail_src_filepath and os.path.exists(thumbnail_src_filepath): @@ -331,7 +304,7 @@ def render( thumbnail_obj.paste(source_img) thumbnail_obj.save(thumbnail_filepath) - return repre_files, thumbnail_filepath + return output_filenames, thumbnail_filepath def _render_layer( self, @@ -611,14 +584,14 @@ def _composite_files( process_count -= 1 processes = {} - output_filepaths_by_frame = {} + output_filepaths = [] missing_frame_paths = [] random_frame_path = None for frame_idx in sorted(images_by_frame.keys()): image_filepaths = images_by_frame[frame_idx] output_filename = filename_template.format(frame=frame_idx + 1) output_filepath = os.path.join(output_dir, output_filename) - output_filepaths_by_frame[frame_idx] = output_filepath + output_filepaths.append(output_filepath) # Store information about missing frame and skip if not image_filepaths: @@ -684,7 +657,7 @@ def _composite_files( transparent_filepath = filepath else: self._copy_image(transparent_filepath, filepath) - return output_filepaths_by_frame + return output_filepaths def _cleanup_tmp_files(self, files_by_position): """Remove temporary files that were used for compositing.""" From f213372e821c0b8867081d93aae56b393121b3e2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 29 Apr 2021 11:56:58 +0200 Subject: [PATCH 21/24] prepare and check all frames before rendering --- .../tvpaint/publish/extract_sequence.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index c2fcf771cb7..719c88dab65 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -51,6 +51,54 @@ def process(self, instance): frame_start = int(instance.data["frameStart"]) frame_end = int(instance.data["frameEnd"]) + # Handles are not stored per instance but on Context + handle_start = instance.context.data["handleStart"] + handle_end = instance.context.data["handleEnd"] + + # --- Fallbacks ---------------------------------------------------- + # This is required if validations of ranges are ignored. + # - all of this code won't change processing if range to render + # match to range of expected output + + # Prepare output frames + output_frame_start = frame_start - handle_start + output_frame_end = frame_end + handle_end + + # Change output frame start to 0 if handles cause it's negative number + if output_frame_start < 0: + self.log.warning(( + "Frame start with handles has negative value." + " Changed to \"0\". Frames start: {}, Handle Start: {}" + ).format(frame_start, handle_start)) + output_frame_start = 0 + + # Check Marks range and output range + output_range = output_frame_end - output_frame_start + marks_range = mark_out - mark_in + + # Lower Mark Out if mark range is bigger than output + # - do not rendered not used frames + if output_range < marks_range: + new_mark_out = mark_out - (marks_range - output_range) + self.log.warning(( + "Lowering render range to {} frames. Changed Mark Out {} -> {}" + ).format(marks_range + 1, mark_out, new_mark_out)) + # Assign new mark out to variable + mark_out = new_mark_out + + # Lower output frame end so representation has right `frameEnd` value + elif output_range > marks_range: + new_output_frame_end = ( + output_frame_end - (output_range - marks_range) + ) + self.log.warning(( + "Lowering representation range to {} frames." + " Changed frame end {} -> {}" + ).format(output_range + 1, mark_out, new_mark_out)) + output_frame_end = new_output_frame_end + + # ------------------------------------------------------------------- + filename_template = self._get_filename_template( # Use the biggest number max(mark_out, frame_end) From 3806166c269b4ea3703120e3cae82afa732c7899 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 29 Apr 2021 11:58:40 +0200 Subject: [PATCH 22/24] rendered frames are renamed to proper sequence frames in single method --- .../tvpaint/publish/extract_sequence.py | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index 719c88dab65..e00ff7e8520 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -135,6 +135,12 @@ def process(self, instance): self.log.warning("Extractor did not create any output.") return + repre_files = self._rename_output_files( + filename_template, output_dir, + mark_in, mark_out, + output_frame_start, output_frame_end + ) + # Fill tags and new families tags = [] if family_lowered in ("review", "renderlayer"): @@ -154,8 +160,8 @@ def process(self, instance): } if not single_file: - new_repre["frameStart"] = frame_start - new_repre["frameEnd"] = frame_end + new_repre["frameStart"] = output_frame_start + new_repre["frameEnd"] = output_frame_end self.log.debug("Creating new representation: {}".format(new_repre)) @@ -197,6 +203,44 @@ def _get_filename_template(self, frame_end): return "{{frame:0>{}}}".format(frame_padding) + ".png" + def _rename_output_files( + self, filename_template, output_dir, + mark_in, mark_out, output_frame_start, output_frame_end + ): + # Use differnet ranges based on Mark In and output Frame Start values + # - this is to make sure that filename renaming won't affect files that + # are not renamed yet + mark_start_is_less = bool(mark_in < output_frame_start) + if mark_start_is_less: + marks_range = range(mark_out, mark_in - 1, -1) + frames_range = range(output_frame_end, output_frame_start - 1, -1) + else: + # This is less possible situation as frame start will be in most + # cases higher than Mark In. + marks_range = range(mark_in, mark_out + 1) + frames_range = range(output_frame_start, output_frame_end + 1) + + repre_filepaths = [] + for mark, frame in zip(marks_range, frames_range): + new_filename = filename_template.format(frame=frame) + new_filepath = os.path.join(output_dir, new_filename) + + repre_filepaths.append(new_filepath) + + if mark != frame: + old_filename = filename_template.format(frame=frame) + old_filepath = os.path.join(output_dir, old_filename) + os.rename(old_filepath, new_filepath) + + # Reverse repre files order if output + if mark_start_is_less: + repre_filepaths = list(reversed(repre_filepaths)) + + return [ + os.path.basename(path) + for path in repre_filepaths + ] + def render_review(self, filename_template, output_dir, mark_in, mark_out): """ Export images from TVPaint using `tv_savesequence` command. From 17406ac2dc4a6d60be13fcb0804145986c34bea4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 29 Apr 2021 12:24:49 +0200 Subject: [PATCH 23/24] fix used frames --- pype/plugins/tvpaint/publish/extract_sequence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index e00ff7e8520..ac8be0e64e6 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -228,7 +228,7 @@ def _rename_output_files( repre_filepaths.append(new_filepath) if mark != frame: - old_filename = filename_template.format(frame=frame) + old_filename = filename_template.format(frame=mark) old_filepath = os.path.join(output_dir, old_filename) os.rename(old_filepath, new_filepath) @@ -681,7 +681,7 @@ def _composite_files( random_frame_path = None for frame_idx in sorted(images_by_frame.keys()): image_filepaths = images_by_frame[frame_idx] - output_filename = filename_template.format(frame=frame_idx + 1) + output_filename = filename_template.format(frame=frame_idx) output_filepath = os.path.join(output_dir, output_filename) output_filepaths.append(output_filepath) From 09b86bda531ba47cd69037ff4ca0722e5acc168a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 29 Apr 2021 12:25:04 +0200 Subject: [PATCH 24/24] added prefix to temp directory --- pype/plugins/tvpaint/publish/extract_sequence.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/plugins/tvpaint/publish/extract_sequence.py b/pype/plugins/tvpaint/publish/extract_sequence.py index ac8be0e64e6..a50f1a91f21 100644 --- a/pype/plugins/tvpaint/publish/extract_sequence.py +++ b/pype/plugins/tvpaint/publish/extract_sequence.py @@ -111,7 +111,9 @@ def process(self, instance): output_dir = instance.data.get("stagingDir") if not output_dir: # Create temp folder if staging dir is not set - output_dir = tempfile.mkdtemp().replace("\\", "/") + output_dir = ( + tempfile.mkdtemp(prefix="tvpaint_render_") + ).replace("\\", "/") instance.data["stagingDir"] = output_dir self.log.debug(