Compare commits
23 Commits
version-1.
...
version-1.
Author | SHA1 | Date | |
---|---|---|---|
405b823c81 | |||
9e952035d3 | |||
d77acfb9c8 | |||
70de9741df | |||
cc37e73bc6 | |||
e32e75e3db | |||
6fa5ab5481 | |||
379580de86 | |||
db30b3df76 | |||
5de99baaef | |||
2184b39d27 | |||
23b1f7de7d | |||
28f68c6fbf | |||
b00cb233cc | |||
2142e9e7fc | |||
1dea802932 | |||
077bd1abdb | |||
5a2c528681 | |||
53b12376d1 | |||
8495868ea6 | |||
cf810de41b | |||
c457767edf | |||
985b3f6a7d |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,11 +1,36 @@
|
||||
# Blender Cloud changelog
|
||||
|
||||
## Version 1.17 (2021-02-04)
|
||||
|
||||
- Upgrade BAT to version 1.3.1, which brings compatibility with Geometry Nodes and
|
||||
fixes some issues on Windows.
|
||||
|
||||
|
||||
## Version 1.16 (2020-03-03)
|
||||
|
||||
- Fixed Windows compatibility issue with the handling of Shaman URLs.
|
||||
|
||||
|
||||
## Version 1.15 (2019-12-12)
|
||||
|
||||
- Avoid creating BAT pack when the to-be-rendered file is already inside the job storage
|
||||
directory. This assumes that the paths are already correct for the Flamenco Workers.
|
||||
|
||||
|
||||
## Version 1.14 (2019-10-10)
|
||||
|
||||
- Upgraded BAT to 1.2 for missing smoke caches, compatibility with Blender 2.81, and some
|
||||
Windows-specific fixes.
|
||||
- Removed warnings on the terminal when running Blender 2.80+
|
||||
|
||||
|
||||
## Version 1.13 (2019-04-18)
|
||||
|
||||
- Upgraded BAT to 1.1.1 for a compatibility fix with Blender 2.79
|
||||
- Flamenco: Support for Flamenco Manager settings versioning + for settings version 2.
|
||||
When using Blender Cloud Add-on 1.12 or older, Flamenco Server will automatically convert the
|
||||
Manager settings to version 1.
|
||||
- More Blender 2.80 compatibility fixes
|
||||
|
||||
|
||||
## Version 1.12 (2019-03-25)
|
||||
|
@@ -21,7 +21,7 @@
|
||||
bl_info = {
|
||||
'name': 'Blender Cloud',
|
||||
"author": "Sybren A. Stüvel, Francesco Siddi, Inês Almeida, Antony Riakiotakis",
|
||||
'version': (1, 13, 3),
|
||||
'version': (1, 17),
|
||||
'blender': (2, 80, 0),
|
||||
'location': 'Addon Preferences panel, and Ctrl+Shift+Alt+A anywhere for texture browser',
|
||||
'description': 'Texture library browser and Blender Sync. Requires the Blender ID addon '
|
||||
|
@@ -47,6 +47,7 @@ if "bpy" in locals():
|
||||
pillar = importlib.reload(pillar)
|
||||
async_loop = importlib.reload(async_loop)
|
||||
blender = importlib.reload(blender)
|
||||
compatibility = importlib.reload(compatibility)
|
||||
else:
|
||||
import bpy
|
||||
|
||||
@@ -54,7 +55,7 @@ else:
|
||||
from . import draw_27 as draw
|
||||
else:
|
||||
from . import draw
|
||||
from .. import pillar, async_loop, blender
|
||||
from .. import pillar, async_loop, blender, compatibility
|
||||
|
||||
import bpy
|
||||
import pillarsdk
|
||||
@@ -63,6 +64,7 @@ from pillarsdk.projects import Project
|
||||
from pillarsdk import exceptions as sdk_exceptions
|
||||
|
||||
from bpy.types import Operator, Panel, AddonPreferences
|
||||
import bl_ui.space_sequencer
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -251,7 +253,7 @@ class ATTRACT_PT_tools(AttractPollMixin, Panel):
|
||||
icon='RENDER_STILL')
|
||||
|
||||
# Group more dangerous operations.
|
||||
dangerous_sub = layout.split(**blender.factor(0.6), align=True)
|
||||
dangerous_sub = layout.split(**compatibility.factor(0.6), align=True)
|
||||
dangerous_sub.operator('attract.strip_unlink',
|
||||
text='Unlink %s' % noun,
|
||||
icon='PANEL_CLOSE')
|
||||
@@ -407,6 +409,7 @@ class ATTRACT_OT_shot_fetch_update(AttractOperatorMixin, Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class ATTRACT_OT_shot_relink(AttractOperatorMixin, Operator):
|
||||
bl_idname = "attract.shot_relink"
|
||||
bl_label = "Relink With Attract"
|
||||
@@ -476,6 +479,7 @@ class ATTRACT_OT_shot_open_in_browser(AttractOperatorMixin, Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class ATTRACT_OT_shot_delete(AttractOperatorMixin, Operator):
|
||||
bl_idname = 'attract.shot_delete'
|
||||
bl_label = 'Delete Shot'
|
||||
@@ -639,8 +643,7 @@ class ATTRACT_OT_open_meta_blendfile(AttractOperatorMixin, Operator):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return AttractOperatorMixin.poll(context) and \
|
||||
bool(any(cls.filename_from_metadata(s) for s in context.selected_sequences))
|
||||
return bool(any(cls.filename_from_metadata(s) for s in context.selected_sequences))
|
||||
|
||||
@staticmethod
|
||||
def filename_from_metadata(strip):
|
||||
@@ -915,6 +918,7 @@ class ATTRACT_OT_copy_id_to_clipboard(AttractOperatorMixin, Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class ATTRACT_OT_project_open_in_browser(Operator):
|
||||
bl_idname = 'attract.project_open_in_browser'
|
||||
bl_label = 'Open Project in Browser'
|
||||
@@ -946,25 +950,31 @@ class ATTRACT_OT_project_open_in_browser(Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def draw_strip_movie_meta(self, context):
|
||||
strip = active_strip(context)
|
||||
if not strip:
|
||||
return
|
||||
class ATTRACT_PT_strip_metadata(bl_ui.space_sequencer.SequencerButtonsPanel, Panel):
|
||||
bl_label = "Metadata"
|
||||
bl_parent_id = "SEQUENCER_PT_source"
|
||||
bl_category = "Strip"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
meta = strip.get('metadata', None)
|
||||
if not meta:
|
||||
return None
|
||||
def draw(self, context):
|
||||
strip = active_strip(context)
|
||||
if not strip:
|
||||
return
|
||||
|
||||
box = self.layout.column(align=True)
|
||||
row = box.row(align=True)
|
||||
fname = meta.get('BLEND_FILE', None) or None
|
||||
if fname:
|
||||
row.label(text='Original Blendfile: %s' % fname)
|
||||
row.operator(ATTRACT_OT_open_meta_blendfile.bl_idname,
|
||||
text='', icon='FILE_BLEND')
|
||||
sfra = meta.get('START_FRAME', '?')
|
||||
efra = meta.get('END_FRAME', '?')
|
||||
box.label(text='Original Frame Range: %s-%s' % (sfra, efra))
|
||||
meta = strip.get('metadata', None)
|
||||
if not meta:
|
||||
return None
|
||||
|
||||
box = self.layout.column(align=True)
|
||||
row = box.row(align=True)
|
||||
fname = meta.get('BLEND_FILE', None) or None
|
||||
if fname:
|
||||
row.label(text='Original Blendfile: %s' % fname)
|
||||
row.operator(ATTRACT_OT_open_meta_blendfile.bl_idname,
|
||||
text='', icon='FILE_BLEND')
|
||||
sfra = meta.get('START_FRAME', '?')
|
||||
efra = meta.get('END_FRAME', '?')
|
||||
box.label(text='Original Frame Range: %s-%s' % (sfra, efra))
|
||||
|
||||
|
||||
def activate():
|
||||
@@ -997,7 +1007,6 @@ def deactivate():
|
||||
|
||||
_rna_classes = [cls for cls in locals().values()
|
||||
if isinstance(cls, type) and cls.__name__.startswith('ATTRACT')]
|
||||
log.info('RNA classes:\n%s', '\n'.join([repr(cls) for cls in _rna_classes]))
|
||||
|
||||
|
||||
def register():
|
||||
@@ -1023,13 +1032,6 @@ def register():
|
||||
name="Status")
|
||||
bpy.types.Sequence.atc_order = bpy.props.IntProperty(name="Order")
|
||||
|
||||
try:
|
||||
panel = bpy.types.SEQUENCER_PT_info_input
|
||||
except AttributeError:
|
||||
# Blender 2.79 and older:
|
||||
panel = bpy.types.SEQUENCER_PT_edit
|
||||
panel.append(draw_strip_movie_meta)
|
||||
|
||||
for cls in _rna_classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
|
@@ -30,7 +30,7 @@ from bpy.types import AddonPreferences, Operator, WindowManager, Scene, Property
|
||||
from bpy.props import StringProperty, EnumProperty, PointerProperty, BoolProperty, IntProperty
|
||||
import rna_prop_ui
|
||||
|
||||
from . import pillar, async_loop, flamenco, project_specific
|
||||
from . import compatibility, pillar, async_loop, flamenco, project_specific
|
||||
from .utils import pyside_cache, redraw
|
||||
|
||||
PILLAR_WEB_SERVER_URL = os.environ.get('BCLOUD_SERVER', 'https://cloud.blender.org/')
|
||||
@@ -40,23 +40,6 @@ ADDON_NAME = 'blender_cloud'
|
||||
log = logging.getLogger(__name__)
|
||||
icons = None
|
||||
|
||||
if bpy.app.version < (2, 80):
|
||||
SYNC_SELECT_VERSION_ICON = 'DOTSDOWN'
|
||||
else:
|
||||
SYNC_SELECT_VERSION_ICON = 'DOWNARROW_HLT'
|
||||
|
||||
|
||||
@functools.lru_cache()
|
||||
def factor(factor: float) -> dict:
|
||||
"""Construct keyword argument for UILayout.split().
|
||||
|
||||
On Blender 2.8 this returns {'factor': factor}, and on earlier Blenders it returns
|
||||
{'percentage': factor}.
|
||||
"""
|
||||
if bpy.app.version < (2, 80, 0):
|
||||
return {'percentage': factor}
|
||||
return {'factor': factor}
|
||||
|
||||
|
||||
@pyside_cache('version')
|
||||
def blender_syncable_versions(self, context):
|
||||
@@ -69,6 +52,7 @@ def blender_syncable_versions(self, context):
|
||||
return [(v, v, '') for v in versions]
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class SyncStatusProperties(PropertyGroup):
|
||||
status = EnumProperty(
|
||||
items=[
|
||||
@@ -156,6 +140,7 @@ def project_extensions(project_id) -> set:
|
||||
return set(proj.get('enabled_for', ()))
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class BlenderCloudProjectGroup(PropertyGroup):
|
||||
status = EnumProperty(
|
||||
items=[
|
||||
@@ -185,6 +170,7 @@ class BlenderCloudProjectGroup(PropertyGroup):
|
||||
project_specific.handle_project_update()
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class BlenderCloudPreferences(AddonPreferences):
|
||||
bl_idname = ADDON_NAME
|
||||
|
||||
@@ -257,7 +243,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
||||
name='Relative Paths Only',
|
||||
description='When enabled, only assets that are referred to with a relative path are '
|
||||
'packed, and assets referred to by an absolute path are excluded from the '
|
||||
'BAT pack. When disabled, all assets are packed.',
|
||||
'BAT pack. When disabled, all assets are packed',
|
||||
default=False,
|
||||
update=project_specific.store,
|
||||
)
|
||||
@@ -331,7 +317,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
||||
bss = context.window_manager.blender_sync_status
|
||||
bsync_box = layout.box()
|
||||
bsync_box.enabled = msg_icon != 'ERROR'
|
||||
row = bsync_box.row().split(**factor(0.33))
|
||||
row = bsync_box.row().split(**compatibility.factor(0.33))
|
||||
row.label(text='Blender Sync with Blender Cloud', icon_value=icon('CLOUD'))
|
||||
|
||||
icon_for_level = {
|
||||
@@ -374,7 +360,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
||||
layout.enabled = bss.status in {'NONE', 'IDLE'}
|
||||
|
||||
buttons = layout.column()
|
||||
row_buttons = buttons.row().split(**factor(0.5))
|
||||
row_buttons = buttons.row().split(**compatibility.factor(0.5))
|
||||
row_push = row_buttons.row()
|
||||
row_pull = row_buttons.row(align=True)
|
||||
|
||||
@@ -396,7 +382,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
||||
props.blender_version = bss.version
|
||||
row_pull.operator('pillar.sync',
|
||||
text='',
|
||||
icon=SYNC_SELECT_VERSION_ICON).action = 'SELECT'
|
||||
icon=compatibility.SYNC_SELECT_VERSION_ICON).action = 'SELECT'
|
||||
else:
|
||||
row_pull.label(text='Cloud Sync is running.')
|
||||
|
||||
@@ -444,7 +430,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
||||
header_row = flamenco_box.row(align=True)
|
||||
header_row.label(text='Flamenco:', icon_value=icon('CLOUD'))
|
||||
|
||||
manager_split = flamenco_box.split(**factor(0.32), align=True)
|
||||
manager_split = flamenco_box.split(**compatibility.factor(0.32), align=True)
|
||||
manager_split.label(text='Manager:')
|
||||
manager_box = manager_split.row(align=True)
|
||||
|
||||
@@ -461,7 +447,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
||||
else:
|
||||
manager_box.label(text='Fetching available managers.')
|
||||
|
||||
path_split = flamenco_box.split(**factor(0.32), align=True)
|
||||
path_split = flamenco_box.split(**compatibility.factor(0.32), align=True)
|
||||
path_split.label(text='Job File Path:')
|
||||
path_box = path_split.row(align=True)
|
||||
path_box.prop(self, 'flamenco_job_file_path', text='')
|
||||
@@ -469,7 +455,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
||||
props.path = self.flamenco_job_file_path
|
||||
|
||||
job_output_box = flamenco_box.column(align=True)
|
||||
path_split = job_output_box.split(**factor(0.32), align=True)
|
||||
path_split = job_output_box.split(**compatibility.factor(0.32), align=True)
|
||||
path_split.label(text='Job Output Path:')
|
||||
path_box = path_split.row(align=True)
|
||||
path_box.prop(self, 'flamenco_job_output_path', text='')
|
||||
@@ -477,7 +463,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
||||
props.path = self.flamenco_job_output_path
|
||||
job_output_box.prop(self, 'flamenco_exclude_filter')
|
||||
|
||||
prop_split = job_output_box.split(**factor(0.32), align=True)
|
||||
prop_split = job_output_box.split(**compatibility.factor(0.32), align=True)
|
||||
prop_split.label(text='Strip Components:')
|
||||
prop_split.prop(self, 'flamenco_job_output_strip_components', text='')
|
||||
|
||||
@@ -561,6 +547,7 @@ class PILLAR_OT_subscribe(Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class PILLAR_OT_project_open_in_browser(Operator):
|
||||
bl_idname = 'pillar.project_open_in_browser'
|
||||
bl_label = 'Open in Browser'
|
||||
|
70
blender_cloud/compatibility.py
Normal file
70
blender_cloud/compatibility.py
Normal file
@@ -0,0 +1,70 @@
|
||||
"""Compatibility functions to support Blender 2.79 and 2.80+ in one code base."""
|
||||
import functools
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
if bpy.app.version < (2, 80):
|
||||
SYNC_SELECT_VERSION_ICON = 'DOTSDOWN'
|
||||
else:
|
||||
SYNC_SELECT_VERSION_ICON = 'DOWNARROW_HLT'
|
||||
|
||||
|
||||
# Get references to all property definition functions in bpy.props,
|
||||
# so that they can be used to replace 'x = IntProperty()' to 'x: IntProperty()'
|
||||
# dynamically when working on Blender 2.80+
|
||||
__all_prop_funcs = {
|
||||
getattr(bpy.props, propname)
|
||||
for propname in dir(bpy.props)
|
||||
if propname.endswith('Property')
|
||||
}
|
||||
|
||||
def convert_properties(class_):
|
||||
"""Class decorator to avoid warnings in Blender 2.80+
|
||||
|
||||
This decorator replaces property definitions like this:
|
||||
|
||||
someprop = bpy.props.IntProperty()
|
||||
|
||||
to annotations, as introduced in Blender 2.80:
|
||||
|
||||
someprop: bpy.props.IntProperty()
|
||||
|
||||
No-op if running on Blender 2.79 or older.
|
||||
"""
|
||||
|
||||
if bpy.app.version < (2, 80):
|
||||
return class_
|
||||
|
||||
if not hasattr(class_, '__annotations__'):
|
||||
class_.__annotations__ = {}
|
||||
|
||||
attrs_to_delete = []
|
||||
for name, value in class_.__dict__.items():
|
||||
if not isinstance(value, tuple) or len(value) != 2:
|
||||
continue
|
||||
|
||||
prop_func, kwargs = value
|
||||
if prop_func not in __all_prop_funcs:
|
||||
continue
|
||||
|
||||
# This is a property definition, replace it with annotation.
|
||||
attrs_to_delete.append(name)
|
||||
class_.__annotations__[name] = value
|
||||
|
||||
for attr_name in attrs_to_delete:
|
||||
delattr(class_, attr_name)
|
||||
|
||||
return class_
|
||||
|
||||
|
||||
@functools.lru_cache()
|
||||
def factor(factor: float) -> dict:
|
||||
"""Construct keyword argument for UILayout.split().
|
||||
|
||||
On Blender 2.8 this returns {'factor': factor}, and on earlier Blenders it returns
|
||||
{'percentage': factor}.
|
||||
"""
|
||||
if bpy.app.version < (2, 80, 0):
|
||||
return {'percentage': factor}
|
||||
return {'factor': factor}
|
@@ -34,12 +34,13 @@ if "bpy" in locals():
|
||||
bat_interface = importlib.reload(bat_interface)
|
||||
sdk = importlib.reload(sdk)
|
||||
blender = importlib.reload(blender)
|
||||
compatibility = importlib.reload(compatibility)
|
||||
except NameError:
|
||||
from . import bat_interface, sdk
|
||||
from .. import blender
|
||||
from .. import blender, compatibility
|
||||
else:
|
||||
from . import bat_interface, sdk
|
||||
from .. import blender
|
||||
from .. import blender, compatibility
|
||||
|
||||
import bpy
|
||||
from bpy.types import AddonPreferences, Operator, WindowManager, Scene, PropertyGroup
|
||||
@@ -138,6 +139,7 @@ def silently_quit_blender():
|
||||
bpy.ops.wm.quit_blender()
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class FlamencoManagerGroup(PropertyGroup):
|
||||
manager = EnumProperty(
|
||||
items=available_managers,
|
||||
@@ -238,6 +240,41 @@ def guess_output_file_extension(output_format: str, scene) -> str:
|
||||
return '.' + container.lower()
|
||||
|
||||
|
||||
def is_shaman_url(path_or_url: str) -> bool:
|
||||
"""Check whether the given string is a Shaman URL.
|
||||
|
||||
:param path_or_url: A string that may represent a filesystem path or a URL.
|
||||
May not be a pathlib.Path, as that would break URL notation on Windows.
|
||||
"""
|
||||
assert isinstance(path_or_url, str)
|
||||
return any(path_or_url.startswith(scheme) for scheme in SHAMAN_URL_SCHEMES)
|
||||
|
||||
|
||||
def is_file_inside_job_storage(prefs, current_file: typing.Union[str, Path]) -> bool:
|
||||
"""Check whether current blend file is inside the storage path.
|
||||
|
||||
:return: True when 'current_file' is inside the Flamenco
|
||||
job storage directory already. In this case it won't be
|
||||
BAT-packed, as it's assumed the job storage dir is
|
||||
accessible by the workers already.
|
||||
"""
|
||||
|
||||
if isinstance(current_file, str):
|
||||
# Shaman URLs are always remote, so the current file cannot be in there.
|
||||
if is_shaman_url(current_file):
|
||||
return False
|
||||
current_file = Path(current_file)
|
||||
|
||||
flamenco_job_file_path = Path(prefs.flamenco_job_file_path).absolute().resolve()
|
||||
current_file = current_file.absolute().resolve()
|
||||
try:
|
||||
current_file.relative_to(flamenco_job_file_path)
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class FLAMENCO_OT_render(async_loop.AsyncModalOperatorMixin,
|
||||
pillar.AuthenticatedPillarOperatorMixin,
|
||||
FlamencoPollMixin,
|
||||
@@ -435,7 +472,7 @@ class FLAMENCO_OT_render(async_loop.AsyncModalOperatorMixin,
|
||||
|
||||
# Pop out some settings so that settings of irrelevant Managers are excluded.
|
||||
flamenco_managers_settings = project_settings.pop('flamenco_managers_settings', {})
|
||||
flamenco_manager_settings = flamenco_managers_settings.pop(manager_id)
|
||||
flamenco_manager_settings = flamenco_managers_settings.pop(manager_id, '-unknown-')
|
||||
|
||||
info = {
|
||||
'_meta': {'version': 2},
|
||||
@@ -565,7 +602,7 @@ class FLAMENCO_OT_render(async_loop.AsyncModalOperatorMixin,
|
||||
|
||||
self.log.debug('projdir: %s', projdir)
|
||||
|
||||
if any(prefs.flamenco_job_file_path.startswith(scheme) for scheme in SHAMAN_URL_SCHEMES):
|
||||
if is_shaman_url(prefs.flamenco_job_file_path):
|
||||
endpoint, _ = bat_interface.parse_shaman_endpoint(prefs.flamenco_job_file_path)
|
||||
self.log.info('Sending BAT pack to Shaman at %s', endpoint)
|
||||
try:
|
||||
@@ -593,6 +630,11 @@ class FLAMENCO_OT_render(async_loop.AsyncModalOperatorMixin,
|
||||
outfile = PurePath('{shaman}') / outfile
|
||||
return None, outfile, missing_sources
|
||||
|
||||
if is_file_inside_job_storage(prefs, filepath):
|
||||
# The blend file is contained in the job storage path, no need to copy anything.
|
||||
# Since BAT doesn't run, we also don't know whether files are missing.
|
||||
return filepath.parent, filepath, []
|
||||
|
||||
# Create a unique directory that is still more or less identifyable.
|
||||
# This should work better than a random ID.
|
||||
unique_dir = '%s-%s-%s' % (datetime.now().isoformat('-').replace(':', ''),
|
||||
@@ -729,6 +771,7 @@ class FLAMENCO_OT_abort(Operator, FlamencoPollMixin):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class FLAMENCO_OT_explore_file_path(FlamencoPollMixin,
|
||||
Operator):
|
||||
"""Opens the Flamenco job storage path in a file explorer.
|
||||
@@ -796,6 +839,7 @@ class FLAMENCO_OT_disable_output_path_override(Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class FLAMENCO_OT_set_recommended_sample_cap(Operator):
|
||||
bl_idname = 'flamenco.set_recommended_sample_cap'
|
||||
bl_label = 'Set Recommended Maximum Sample Count'
|
||||
@@ -962,7 +1006,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
||||
|
||||
prefs = preferences()
|
||||
|
||||
labeled_row = layout.split(**blender.factor(0.25), align=True)
|
||||
labeled_row = layout.split(**compatibility.factor(0.25), align=True)
|
||||
labeled_row.label(text='Manager:')
|
||||
prop_btn_row = labeled_row.row(align=True)
|
||||
|
||||
@@ -980,7 +1024,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
||||
else:
|
||||
prop_btn_row.label(text='Fetching available managers.')
|
||||
|
||||
labeled_row = layout.split(**blender.factor(0.25), align=True)
|
||||
labeled_row = layout.split(**compatibility.factor(0.25), align=True)
|
||||
labeled_row.label(text='Job Type:')
|
||||
labeled_row.prop(context.scene, 'flamenco_render_job_type', text='')
|
||||
|
||||
@@ -1005,7 +1049,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
||||
sample_count = scene_sample_count(context.scene)
|
||||
recommended_cap = sample_count // 4
|
||||
|
||||
split = box.split(**blender.factor(0.4))
|
||||
split = box.split(**compatibility.factor(0.4))
|
||||
split.label(text='Total Sample Count: %d' % sample_count)
|
||||
props = split.operator('flamenco.set_recommended_sample_cap',
|
||||
text='Recommended Max Samples per Task: %d' % recommended_cap)
|
||||
@@ -1019,7 +1063,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
||||
else:
|
||||
box.prop(context.scene, 'flamenco_render_fchunk_size')
|
||||
|
||||
labeled_row = layout.split(**blender.factor(0.25), align=True)
|
||||
labeled_row = layout.split(**compatibility.factor(0.25), align=True)
|
||||
labeled_row.label(text='Frame Range:')
|
||||
prop_btn_row = labeled_row.row(align=True)
|
||||
prop_btn_row.prop(context.scene, 'flamenco_render_frame_range', text='')
|
||||
@@ -1030,7 +1074,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
||||
|
||||
paths_layout = layout.column(align=True)
|
||||
|
||||
labeled_row = paths_layout.split(**blender.factor(0.25), align=True)
|
||||
labeled_row = paths_layout.split(**compatibility.factor(0.25), align=True)
|
||||
labeled_row.label(text='Storage:')
|
||||
prop_btn_row = labeled_row.row(align=True)
|
||||
prop_btn_row.label(text=prefs.flamenco_job_file_path)
|
||||
@@ -1038,12 +1082,18 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
||||
text='', icon='DISK_DRIVE')
|
||||
props.path = prefs.flamenco_job_file_path
|
||||
|
||||
|
||||
if is_file_inside_job_storage(prefs, context.blend_data.filepath):
|
||||
# File is contained in the job storage path, no need to copy anything.
|
||||
paths_layout.label(text='Current file already in job storage path; '
|
||||
'not going to create BAT pack.')
|
||||
|
||||
render_output = render_output_path(context)
|
||||
if render_output is None:
|
||||
paths_layout.label(text='Unable to render with Flamenco, outside of project directory.')
|
||||
return
|
||||
|
||||
labeled_row = paths_layout.split(**blender.factor(0.25), align=True)
|
||||
labeled_row = paths_layout.split(**compatibility.factor(0.25), align=True)
|
||||
labeled_row.label(text='Output:')
|
||||
prop_btn_row = labeled_row.row(align=True)
|
||||
|
||||
@@ -1062,7 +1112,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
||||
props.path = str(render_output.parent)
|
||||
|
||||
if context.scene.flamenco_do_override_output_path:
|
||||
labeled_row = paths_layout.split(**blender.factor(0.25), align=True)
|
||||
labeled_row = paths_layout.split(**compatibility.factor(0.25), align=True)
|
||||
labeled_row.label(text='Effective Output Path:')
|
||||
labeled_row.label(text=str(render_output))
|
||||
|
||||
@@ -1072,7 +1122,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
||||
flamenco_status = context.window_manager.flamenco_status
|
||||
if flamenco_status in {'IDLE', 'ABORTED', 'DONE'}:
|
||||
if prefs.flamenco_show_quit_after_submit_button:
|
||||
ui = layout.split(**blender.factor(0.75), align=True)
|
||||
ui = layout.split(**compatibility.factor(0.75), align=True)
|
||||
else:
|
||||
ui = layout
|
||||
ui.operator(FLAMENCO_OT_render.bl_idname,
|
||||
|
@@ -25,7 +25,7 @@ import bpy
|
||||
import pillarsdk
|
||||
from pillarsdk import exceptions as sdk_exceptions
|
||||
from .pillar import pillar_call
|
||||
from . import async_loop, pillar, home_project, blender
|
||||
from . import async_loop, compatibility, pillar, home_project, blender
|
||||
|
||||
REQUIRES_ROLES_FOR_IMAGE_SHARING = {'subscriber', 'demo'}
|
||||
IMAGE_SHARING_GROUP_NODE_NAME = 'Image sharing'
|
||||
@@ -53,6 +53,7 @@ async def find_image_sharing_group_id(home_project_id, user_id):
|
||||
return share_group['_id']
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class PILLAR_OT_image_share(pillar.PillarOperatorMixin,
|
||||
async_loop.AsyncModalOperatorMixin,
|
||||
bpy.types.Operator):
|
||||
|
@@ -70,8 +70,8 @@ def handle_project_update(_=None, _2=None):
|
||||
with mark_as_loading():
|
||||
prefs = preferences()
|
||||
project_id = prefs.project.project
|
||||
log.info('Updating internal state to reflect extensions enabled on current project %s.',
|
||||
project_id)
|
||||
log.debug('Updating internal state to reflect extensions enabled on current project %s.',
|
||||
project_id)
|
||||
|
||||
project_extensions.cache_clear()
|
||||
|
||||
|
@@ -35,7 +35,7 @@ import asyncio
|
||||
import pillarsdk
|
||||
from pillarsdk import exceptions as sdk_exceptions
|
||||
from .pillar import pillar_call
|
||||
from . import async_loop, blender, pillar, cache, blendfile, home_project
|
||||
from . import async_loop, blender, compatibility, pillar, cache, blendfile, home_project
|
||||
|
||||
SETTINGS_FILES_TO_UPLOAD = ['userpref.blend', 'startup.blend']
|
||||
|
||||
@@ -196,6 +196,7 @@ async def available_blender_versions(home_project_id: str, user_id: str) -> list
|
||||
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
@compatibility.convert_properties
|
||||
class PILLAR_OT_sync(pillar.PillarOperatorMixin,
|
||||
async_loop.AsyncModalOperatorMixin,
|
||||
bpy.types.Operator):
|
||||
|
@@ -26,7 +26,7 @@ import bpy
|
||||
import bgl
|
||||
|
||||
import pillarsdk
|
||||
from .. import async_loop, pillar, cache, blender, utils
|
||||
from .. import async_loop, compatibility, pillar, cache, blender, utils
|
||||
from . import menu_item as menu_item_mod # so that we can have menu items called 'menu_item'
|
||||
from . import nodes
|
||||
|
||||
@@ -648,6 +648,7 @@ class BlenderCloudBrowser(pillar.PillarOperatorMixin,
|
||||
self.scroll_offset_target = self.scroll_offset = 0
|
||||
|
||||
|
||||
@compatibility.convert_properties
|
||||
class PILLAR_OT_switch_hdri(pillar.PillarOperatorMixin,
|
||||
async_loop.AsyncModalOperatorMixin,
|
||||
bpy.types.Operator):
|
||||
@@ -776,7 +777,7 @@ def _hdri_download_panel(self, current_image):
|
||||
current_image.name)
|
||||
return
|
||||
|
||||
row = self.layout.row(align=True).split(**blender.factor(0.3))
|
||||
row = self.layout.row(align=True).split(**compatibility.factor(0.3))
|
||||
row.label(text='HDRi', icon_value=blender.icon('CLOUD'))
|
||||
row.prop(current_image, 'hdri_variation', text='')
|
||||
|
||||
|
@@ -94,7 +94,10 @@ def pyside_cache(propname):
|
||||
result = wrapped(self, context)
|
||||
return result
|
||||
finally:
|
||||
rna_type, rna_info = getattr(self.bl_rna, propname)
|
||||
try:
|
||||
rna_type, rna_info = self.bl_rna.__annotations__[propname]
|
||||
except AttributeError:
|
||||
rna_type, rna_info = getattr(self.bl_rna, propname)
|
||||
rna_info['_cached_result'] = result
|
||||
return wrapper
|
||||
return decorator
|
||||
|
@@ -3,7 +3,7 @@
|
||||
lockfile==0.12.2
|
||||
pillarsdk==1.8.0
|
||||
wheel==0.29.0
|
||||
blender-asset-tracer==1.1.1
|
||||
blender-asset-tracer==1.3.1
|
||||
|
||||
# Secondary requirements:
|
||||
asn1crypto==0.24.0
|
||||
|
6
setup.py
6
setup.py
@@ -123,8 +123,8 @@ class BuildWheels(Command):
|
||||
"""Downloads a wheel from PyPI and saves it in self.wheels_path."""
|
||||
|
||||
subprocess.check_call([
|
||||
'pip', 'download',
|
||||
'--no-deps',
|
||||
sys.executable, '-m', 'pip',
|
||||
'download', '--no-deps',
|
||||
'--dest', str(self.wheels_path),
|
||||
requirement[0]
|
||||
])
|
||||
@@ -236,7 +236,7 @@ setup(
|
||||
'wheels': BuildWheels},
|
||||
name='blender_cloud',
|
||||
description='The Blender Cloud addon allows browsing the Blender Cloud from Blender.',
|
||||
version='1.13.3',
|
||||
version='1.17',
|
||||
author='Sybren A. Stüvel',
|
||||
author_email='sybren@stuvel.eu',
|
||||
packages=find_packages('.'),
|
||||
|
@@ -19,4 +19,4 @@ echo git commit -m \'Bumped version to $VERSION\' setup.py blender_cloud/__init_
|
||||
echo git tag -a version-$VERSION -m \'Tagged version $VERSION\'
|
||||
echo
|
||||
echo "To build a distribution ZIP:"
|
||||
echo python setup.py bdist
|
||||
echo python3 setup.py bdist
|
||||
|
Reference in New Issue
Block a user