Compare commits

..

23 Commits

Author SHA1 Message Date
db30b3df76 Bumped version to 1.14 2019-10-10 10:39:37 +02:00
5de99baaef Updated changelog 2019-10-10 10:39:28 +02:00
2184b39d27 Bump Blender Asset Tracer (BAT) version from 1.1.1 → 1.2.1 2019-10-10 10:29:53 +02:00
23b1f7de7d Convert property definitions from assignment to annotations on Blender 2.80+
The properties are still declared in the Python 3.5 compatible assignment
notation, and a class decorator that converts those to class annotations
as preferred by Blender 2.80.
2019-10-10 10:29:36 +02:00
28f68c6fbf update_version.sh: Use Python 3 in example command
This makes it possible to run the command outside of a Python 3 virtualenv.
2019-06-21 14:31:54 +02:00
b00cb233cc Bumped version to 1.13.5 2019-06-21 14:30:03 +02:00
2142e9e7fc Attract fix for Blender 2.80 panel change
Commit 1e7c3a159fd2ca42fd5688be067008ef0d2c03df removed the 'Info' panel
(which is good), so we have to attach the metadata subpanel somewhere else.
2019-06-21 14:29:49 +02:00
1dea802932 Attract doesn't have to be active to use ATTRACT_OT_open_meta_blendfile
It is pretty much independent of Attract.
2019-06-21 14:29:07 +02:00
077bd1abdb Prevent KeyError when Flamenco Manager settings are unknown 2019-06-12 11:47:16 +02:00
5a2c528681 Run Pip via {sys.executable} -m pip
This solves the same problem as c457767edf,
but in a way that's actually [recommended](https://pip.pypa.io/en/latest/user_guide/#using-pip-from-your-program).
2019-06-04 12:40:02 +02:00
53b12376d1 Revert "Use Python module to run Pip"
This reverts commit c457767edf. Modern pip
can no longer be used this way ('pip.main' does not exist).
2019-06-04 12:35:46 +02:00
8495868ea6 Bumped version to 1.13.4 2019-06-04 12:29:50 +02:00
cf810de41b Another Blender 2.8 compatibility fix 2019-06-04 12:29:37 +02:00
c457767edf Use Python module to run Pip
setup.py used systemcalls for package management pip. This call is
platform dependent as on ubuntu distros this needs to be pip3. On these
platforms pip points to the python2 version.

By direct calling the pip module from within the running python process
we know for sure we are triggering the correct one.

Differential revision: https://developer.blender.org/D4952/

Reviewed by: sybren
2019-05-29 10:29:14 +02:00
985b3f6a7d Attract: draw strip metadata as its own panel
The panel is a subpanel in Blender 2.80, and a top-level panel in 2.79.
2019-05-24 14:12:36 +02:00
a45bf3cd5c Bumped version to 1.13.3 2019-05-21 10:19:49 +02:00
3789742cc8 Fixed little bug
Missed a function call in a69f4d3fd9.
2019-05-21 10:19:34 +02:00
58f374e175 Bumped version to 1.13.2 2019-05-17 11:26:40 +02:00
99e90e1008 Mark version 1.13 as released 2019-05-17 11:26:29 +02:00
dd83d3ee60 Blender 2.80 compatibility for Attract panel in sequence editor 2019-05-17 11:15:34 +02:00
e74e014c66 Quick fix for Blender 2.80 texture loading
The `Image.gl_load()` call was changed in Blender commit
7ad802cf3ae500bc72863b6dba0f28a488fce3d1; the two parameters we were using
were removed.

This commit fixes the exception and makes the texture browser usable again,
but doesn't properly fix everything. The textures are drawn in the wrong
colour space, which will be fixed in another commit once I know how.
2019-05-17 11:09:57 +02:00
01541f181e Bumped Pillar Python SDK 1.7.0 → 1.8.0 2019-05-14 11:05:51 +02:00
a69f4d3fd9 Flamenco: Moved some code around, no semantic changes 2019-05-10 12:29:39 +02:00
17 changed files with 179 additions and 82 deletions

View File

@@ -1,11 +1,19 @@
# Blender Cloud changelog # Blender Cloud changelog
## Version 1.13 (in development) ## 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 - 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. - 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 When using Blender Cloud Add-on 1.12 or older, Flamenco Server will automatically convert the
Manager settings to version 1. Manager settings to version 1.
- More Blender 2.80 compatibility fixes
## Version 1.12 (2019-03-25) ## Version 1.12 (2019-03-25)

View File

@@ -21,7 +21,7 @@
bl_info = { bl_info = {
'name': 'Blender Cloud', 'name': 'Blender Cloud',
"author": "Sybren A. Stüvel, Francesco Siddi, Inês Almeida, Antony Riakiotakis", "author": "Sybren A. Stüvel, Francesco Siddi, Inês Almeida, Antony Riakiotakis",
'version': (1, 13, 1), 'version': (1, 14),
'blender': (2, 80, 0), 'blender': (2, 80, 0),
'location': 'Addon Preferences panel, and Ctrl+Shift+Alt+A anywhere for texture browser', '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 ' 'description': 'Texture library browser and Blender Sync. Requires the Blender ID addon '

View File

@@ -47,6 +47,7 @@ if "bpy" in locals():
pillar = importlib.reload(pillar) pillar = importlib.reload(pillar)
async_loop = importlib.reload(async_loop) async_loop = importlib.reload(async_loop)
blender = importlib.reload(blender) blender = importlib.reload(blender)
compatibility = importlib.reload(compatibility)
else: else:
import bpy import bpy
@@ -54,7 +55,7 @@ else:
from . import draw_27 as draw from . import draw_27 as draw
else: else:
from . import draw from . import draw
from .. import pillar, async_loop, blender from .. import pillar, async_loop, blender, compatibility
import bpy import bpy
import pillarsdk import pillarsdk
@@ -63,6 +64,7 @@ from pillarsdk.projects import Project
from pillarsdk import exceptions as sdk_exceptions from pillarsdk import exceptions as sdk_exceptions
from bpy.types import Operator, Panel, AddonPreferences from bpy.types import Operator, Panel, AddonPreferences
import bl_ui.space_sequencer
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -251,7 +253,7 @@ class ATTRACT_PT_tools(AttractPollMixin, Panel):
icon='RENDER_STILL') icon='RENDER_STILL')
# Group more dangerous operations. # 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', dangerous_sub.operator('attract.strip_unlink',
text='Unlink %s' % noun, text='Unlink %s' % noun,
icon='PANEL_CLOSE') icon='PANEL_CLOSE')
@@ -407,6 +409,7 @@ class ATTRACT_OT_shot_fetch_update(AttractOperatorMixin, Operator):
return {'FINISHED'} return {'FINISHED'}
@compatibility.convert_properties
class ATTRACT_OT_shot_relink(AttractOperatorMixin, Operator): class ATTRACT_OT_shot_relink(AttractOperatorMixin, Operator):
bl_idname = "attract.shot_relink" bl_idname = "attract.shot_relink"
bl_label = "Relink With Attract" bl_label = "Relink With Attract"
@@ -476,6 +479,7 @@ class ATTRACT_OT_shot_open_in_browser(AttractOperatorMixin, Operator):
return {'FINISHED'} return {'FINISHED'}
@compatibility.convert_properties
class ATTRACT_OT_shot_delete(AttractOperatorMixin, Operator): class ATTRACT_OT_shot_delete(AttractOperatorMixin, Operator):
bl_idname = 'attract.shot_delete' bl_idname = 'attract.shot_delete'
bl_label = 'Delete Shot' bl_label = 'Delete Shot'
@@ -639,8 +643,7 @@ class ATTRACT_OT_open_meta_blendfile(AttractOperatorMixin, Operator):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return AttractOperatorMixin.poll(context) and \ return bool(any(cls.filename_from_metadata(s) for s in context.selected_sequences))
bool(any(cls.filename_from_metadata(s) for s in context.selected_sequences))
@staticmethod @staticmethod
def filename_from_metadata(strip): def filename_from_metadata(strip):
@@ -915,6 +918,7 @@ class ATTRACT_OT_copy_id_to_clipboard(AttractOperatorMixin, Operator):
return {'FINISHED'} return {'FINISHED'}
@compatibility.convert_properties
class ATTRACT_OT_project_open_in_browser(Operator): class ATTRACT_OT_project_open_in_browser(Operator):
bl_idname = 'attract.project_open_in_browser' bl_idname = 'attract.project_open_in_browser'
bl_label = 'Open Project in Browser' bl_label = 'Open Project in Browser'
@@ -946,25 +950,31 @@ class ATTRACT_OT_project_open_in_browser(Operator):
return {'FINISHED'} return {'FINISHED'}
def draw_strip_movie_meta(self, context): class ATTRACT_PT_strip_metadata(bl_ui.space_sequencer.SequencerButtonsPanel, Panel):
strip = active_strip(context) bl_label = "Metadata"
if not strip: bl_parent_id = "SEQUENCER_PT_source"
return bl_category = "Strip"
bl_options = {'DEFAULT_CLOSED'}
meta = strip.get('metadata', None) def draw(self, context):
if not meta: strip = active_strip(context)
return None if not strip:
return
box = self.layout.column(align=True) meta = strip.get('metadata', None)
row = box.row(align=True) if not meta:
fname = meta.get('BLEND_FILE', None) or None return None
if fname:
row.label(text='Original Blendfile: %s' % fname) box = self.layout.column(align=True)
row.operator(ATTRACT_OT_open_meta_blendfile.bl_idname, row = box.row(align=True)
text='', icon='FILE_BLEND') fname = meta.get('BLEND_FILE', None) or None
sfra = meta.get('START_FRAME', '?') if fname:
efra = meta.get('END_FRAME', '?') row.label(text='Original Blendfile: %s' % fname)
box.label(text='Original Frame Range: %s-%s' % (sfra, efra)) 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(): def activate():
@@ -1023,8 +1033,6 @@ def register():
name="Status") name="Status")
bpy.types.Sequence.atc_order = bpy.props.IntProperty(name="Order") bpy.types.Sequence.atc_order = bpy.props.IntProperty(name="Order")
bpy.types.SEQUENCER_PT_edit.append(draw_strip_movie_meta)
for cls in _rna_classes: for cls in _rna_classes:
bpy.utils.register_class(cls) bpy.utils.register_class(cls)

View File

@@ -30,7 +30,7 @@ from bpy.types import AddonPreferences, Operator, WindowManager, Scene, Property
from bpy.props import StringProperty, EnumProperty, PointerProperty, BoolProperty, IntProperty from bpy.props import StringProperty, EnumProperty, PointerProperty, BoolProperty, IntProperty
import rna_prop_ui 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 from .utils import pyside_cache, redraw
PILLAR_WEB_SERVER_URL = os.environ.get('BCLOUD_SERVER', 'https://cloud.blender.org/') 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__) log = logging.getLogger(__name__)
icons = None 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') @pyside_cache('version')
def blender_syncable_versions(self, context): def blender_syncable_versions(self, context):
@@ -69,6 +52,7 @@ def blender_syncable_versions(self, context):
return [(v, v, '') for v in versions] return [(v, v, '') for v in versions]
@compatibility.convert_properties
class SyncStatusProperties(PropertyGroup): class SyncStatusProperties(PropertyGroup):
status = EnumProperty( status = EnumProperty(
items=[ items=[
@@ -156,6 +140,7 @@ def project_extensions(project_id) -> set:
return set(proj.get('enabled_for', ())) return set(proj.get('enabled_for', ()))
@compatibility.convert_properties
class BlenderCloudProjectGroup(PropertyGroup): class BlenderCloudProjectGroup(PropertyGroup):
status = EnumProperty( status = EnumProperty(
items=[ items=[
@@ -185,6 +170,7 @@ class BlenderCloudProjectGroup(PropertyGroup):
project_specific.handle_project_update() project_specific.handle_project_update()
@compatibility.convert_properties
class BlenderCloudPreferences(AddonPreferences): class BlenderCloudPreferences(AddonPreferences):
bl_idname = ADDON_NAME bl_idname = ADDON_NAME
@@ -331,7 +317,7 @@ class BlenderCloudPreferences(AddonPreferences):
bss = context.window_manager.blender_sync_status bss = context.window_manager.blender_sync_status
bsync_box = layout.box() bsync_box = layout.box()
bsync_box.enabled = msg_icon != 'ERROR' 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')) row.label(text='Blender Sync with Blender Cloud', icon_value=icon('CLOUD'))
icon_for_level = { icon_for_level = {
@@ -374,7 +360,7 @@ class BlenderCloudPreferences(AddonPreferences):
layout.enabled = bss.status in {'NONE', 'IDLE'} layout.enabled = bss.status in {'NONE', 'IDLE'}
buttons = layout.column() 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_push = row_buttons.row()
row_pull = row_buttons.row(align=True) row_pull = row_buttons.row(align=True)
@@ -396,7 +382,7 @@ class BlenderCloudPreferences(AddonPreferences):
props.blender_version = bss.version props.blender_version = bss.version
row_pull.operator('pillar.sync', row_pull.operator('pillar.sync',
text='', text='',
icon=SYNC_SELECT_VERSION_ICON).action = 'SELECT' icon=compatibility.SYNC_SELECT_VERSION_ICON).action = 'SELECT'
else: else:
row_pull.label(text='Cloud Sync is running.') row_pull.label(text='Cloud Sync is running.')
@@ -444,7 +430,7 @@ class BlenderCloudPreferences(AddonPreferences):
header_row = flamenco_box.row(align=True) header_row = flamenco_box.row(align=True)
header_row.label(text='Flamenco:', icon_value=icon('CLOUD')) 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_split.label(text='Manager:')
manager_box = manager_split.row(align=True) manager_box = manager_split.row(align=True)
@@ -461,7 +447,7 @@ class BlenderCloudPreferences(AddonPreferences):
else: else:
manager_box.label(text='Fetching available managers.') 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_split.label(text='Job File Path:')
path_box = path_split.row(align=True) path_box = path_split.row(align=True)
path_box.prop(self, 'flamenco_job_file_path', text='') path_box.prop(self, 'flamenco_job_file_path', text='')
@@ -469,7 +455,7 @@ class BlenderCloudPreferences(AddonPreferences):
props.path = self.flamenco_job_file_path props.path = self.flamenco_job_file_path
job_output_box = flamenco_box.column(align=True) 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_split.label(text='Job Output Path:')
path_box = path_split.row(align=True) path_box = path_split.row(align=True)
path_box.prop(self, 'flamenco_job_output_path', text='') path_box.prop(self, 'flamenco_job_output_path', text='')
@@ -477,7 +463,7 @@ class BlenderCloudPreferences(AddonPreferences):
props.path = self.flamenco_job_output_path props.path = self.flamenco_job_output_path
job_output_box.prop(self, 'flamenco_exclude_filter') 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.label(text='Strip Components:')
prop_split.prop(self, 'flamenco_job_output_strip_components', text='') prop_split.prop(self, 'flamenco_job_output_strip_components', text='')
@@ -561,6 +547,7 @@ class PILLAR_OT_subscribe(Operator):
return {'FINISHED'} return {'FINISHED'}
@compatibility.convert_properties
class PILLAR_OT_project_open_in_browser(Operator): class PILLAR_OT_project_open_in_browser(Operator):
bl_idname = 'pillar.project_open_in_browser' bl_idname = 'pillar.project_open_in_browser'
bl_label = 'Open in Browser' bl_label = 'Open in Browser'

View 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}

View File

@@ -34,12 +34,13 @@ if "bpy" in locals():
bat_interface = importlib.reload(bat_interface) bat_interface = importlib.reload(bat_interface)
sdk = importlib.reload(sdk) sdk = importlib.reload(sdk)
blender = importlib.reload(blender) blender = importlib.reload(blender)
compatibility = importlib.reload(compatibility)
except NameError: except NameError:
from . import bat_interface, sdk from . import bat_interface, sdk
from .. import blender from .. import blender, compatibility
else: else:
from . import bat_interface, sdk from . import bat_interface, sdk
from .. import blender from .. import blender, compatibility
import bpy import bpy
from bpy.types import AddonPreferences, Operator, WindowManager, Scene, PropertyGroup from bpy.types import AddonPreferences, Operator, WindowManager, Scene, PropertyGroup
@@ -138,6 +139,7 @@ def silently_quit_blender():
bpy.ops.wm.quit_blender() bpy.ops.wm.quit_blender()
@compatibility.convert_properties
class FlamencoManagerGroup(PropertyGroup): class FlamencoManagerGroup(PropertyGroup):
manager = EnumProperty( manager = EnumProperty(
items=available_managers, items=available_managers,
@@ -238,6 +240,7 @@ def guess_output_file_extension(output_format: str, scene) -> str:
return '.' + container.lower() return '.' + container.lower()
@compatibility.convert_properties
class FLAMENCO_OT_render(async_loop.AsyncModalOperatorMixin, class FLAMENCO_OT_render(async_loop.AsyncModalOperatorMixin,
pillar.AuthenticatedPillarOperatorMixin, pillar.AuthenticatedPillarOperatorMixin,
FlamencoPollMixin, FlamencoPollMixin,
@@ -435,7 +438,7 @@ class FLAMENCO_OT_render(async_loop.AsyncModalOperatorMixin,
# Pop out some settings so that settings of irrelevant Managers are excluded. # Pop out some settings so that settings of irrelevant Managers are excluded.
flamenco_managers_settings = project_settings.pop('flamenco_managers_settings', {}) 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 = { info = {
'_meta': {'version': 2}, '_meta': {'version': 2},
@@ -729,6 +732,7 @@ class FLAMENCO_OT_abort(Operator, FlamencoPollMixin):
return {'FINISHED'} return {'FINISHED'}
@compatibility.convert_properties
class FLAMENCO_OT_explore_file_path(FlamencoPollMixin, class FLAMENCO_OT_explore_file_path(FlamencoPollMixin,
Operator): Operator):
"""Opens the Flamenco job storage path in a file explorer. """Opens the Flamenco job storage path in a file explorer.
@@ -796,6 +800,7 @@ class FLAMENCO_OT_disable_output_path_override(Operator):
return {'FINISHED'} return {'FINISHED'}
@compatibility.convert_properties
class FLAMENCO_OT_set_recommended_sample_cap(Operator): class FLAMENCO_OT_set_recommended_sample_cap(Operator):
bl_idname = 'flamenco.set_recommended_sample_cap' bl_idname = 'flamenco.set_recommended_sample_cap'
bl_label = 'Set Recommended Maximum Sample Count' bl_label = 'Set Recommended Maximum Sample Count'
@@ -962,7 +967,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
prefs = preferences() 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:') labeled_row.label(text='Manager:')
prop_btn_row = labeled_row.row(align=True) prop_btn_row = labeled_row.row(align=True)
@@ -980,7 +985,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
else: else:
prop_btn_row.label(text='Fetching available managers.') 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.label(text='Job Type:')
labeled_row.prop(context.scene, 'flamenco_render_job_type', text='') labeled_row.prop(context.scene, 'flamenco_render_job_type', text='')
@@ -1005,7 +1010,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
sample_count = scene_sample_count(context.scene) sample_count = scene_sample_count(context.scene)
recommended_cap = sample_count // 4 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) split.label(text='Total Sample Count: %d' % sample_count)
props = split.operator('flamenco.set_recommended_sample_cap', props = split.operator('flamenco.set_recommended_sample_cap',
text='Recommended Max Samples per Task: %d' % recommended_cap) text='Recommended Max Samples per Task: %d' % recommended_cap)
@@ -1019,7 +1024,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
else: else:
box.prop(context.scene, 'flamenco_render_fchunk_size') 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:') labeled_row.label(text='Frame Range:')
prop_btn_row = labeled_row.row(align=True) prop_btn_row = labeled_row.row(align=True)
prop_btn_row.prop(context.scene, 'flamenco_render_frame_range', text='') prop_btn_row.prop(context.scene, 'flamenco_render_frame_range', text='')
@@ -1030,7 +1035,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
paths_layout = layout.column(align=True) 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:') labeled_row.label(text='Storage:')
prop_btn_row = labeled_row.row(align=True) prop_btn_row = labeled_row.row(align=True)
prop_btn_row.label(text=prefs.flamenco_job_file_path) prop_btn_row.label(text=prefs.flamenco_job_file_path)
@@ -1043,7 +1048,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
paths_layout.label(text='Unable to render with Flamenco, outside of project directory.') paths_layout.label(text='Unable to render with Flamenco, outside of project directory.')
return 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:') labeled_row.label(text='Output:')
prop_btn_row = labeled_row.row(align=True) prop_btn_row = labeled_row.row(align=True)
@@ -1062,7 +1067,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
props.path = str(render_output.parent) props.path = str(render_output.parent)
if context.scene.flamenco_do_override_output_path: 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='Effective Output Path:')
labeled_row.label(text=str(render_output)) labeled_row.label(text=str(render_output))
@@ -1072,7 +1077,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
flamenco_status = context.window_manager.flamenco_status flamenco_status = context.window_manager.flamenco_status
if flamenco_status in {'IDLE', 'ABORTED', 'DONE'}: if flamenco_status in {'IDLE', 'ABORTED', 'DONE'}:
if prefs.flamenco_show_quit_after_submit_button: 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: else:
ui = layout ui = layout
ui.operator(FLAMENCO_OT_render.bl_idname, ui.operator(FLAMENCO_OT_render.bl_idname,

View File

@@ -12,7 +12,10 @@ class Manager(List, Find):
@functools.lru_cache(maxsize=1) @functools.lru_cache(maxsize=1)
def _path_replacements(self) -> list: def _path_replacements(self) -> list:
"""Defer to _path_replacements_vN() to get path replacement vars.""" """Defer to _path_replacements_vN() to get path replacement vars.
Returns a list of tuples (variable name, variable value).
"""
settings_version = self.settings_version or 1 settings_version = self.settings_version or 1
try: try:
settings_func = getattr(self, '_path_replacements_v%d' % settings_version) settings_func = getattr(self, '_path_replacements_v%d' % settings_version)
@@ -20,7 +23,13 @@ class Manager(List, Find):
raise RuntimeError('This manager has unsupported settings version %d; ' raise RuntimeError('This manager has unsupported settings version %d; '
'upgrade Blender Cloud add-on') 'upgrade Blender Cloud add-on')
return settings_func() def longest_value_first(item):
var_name, var_value = item
return -len(var_value), var_value, var_name
replacements = settings_func()
replacements.sort(key=longest_value_first)
return replacements
def _path_replacements_v1(self) -> typing.List[typing.Tuple[str, str]]: def _path_replacements_v1(self) -> typing.List[typing.Tuple[str, str]]:
import platform import platform
@@ -68,13 +77,7 @@ class Manager(List, Find):
assert isinstance(some_path, pathlib.PurePath), \ assert isinstance(some_path, pathlib.PurePath), \
'some_path should be a PurePath, not %r' % some_path 'some_path should be a PurePath, not %r' % some_path
def by_length(item): for varname, path in self._path_replacements():
return -len(item[1]), item[1]
replacements = self._path_replacements()
replacements.sort(key=by_length)
for varname, path in replacements:
replacement = self.PurePlatformPath(path) replacement = self.PurePlatformPath(path)
try: try:
relpath = some_path.relative_to(replacement) relpath = some_path.relative_to(replacement)

View File

@@ -25,7 +25,7 @@ import bpy
import pillarsdk import pillarsdk
from pillarsdk import exceptions as sdk_exceptions from pillarsdk import exceptions as sdk_exceptions
from .pillar import pillar_call 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'} REQUIRES_ROLES_FOR_IMAGE_SHARING = {'subscriber', 'demo'}
IMAGE_SHARING_GROUP_NODE_NAME = 'Image sharing' 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'] return share_group['_id']
@compatibility.convert_properties
class PILLAR_OT_image_share(pillar.PillarOperatorMixin, class PILLAR_OT_image_share(pillar.PillarOperatorMixin,
async_loop.AsyncModalOperatorMixin, async_loop.AsyncModalOperatorMixin,
bpy.types.Operator): bpy.types.Operator):

View File

@@ -35,7 +35,7 @@ import asyncio
import pillarsdk import pillarsdk
from pillarsdk import exceptions as sdk_exceptions from pillarsdk import exceptions as sdk_exceptions
from .pillar import pillar_call 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'] 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 # noinspection PyAttributeOutsideInit
@compatibility.convert_properties
class PILLAR_OT_sync(pillar.PillarOperatorMixin, class PILLAR_OT_sync(pillar.PillarOperatorMixin,
async_loop.AsyncModalOperatorMixin, async_loop.AsyncModalOperatorMixin,
bpy.types.Operator): bpy.types.Operator):

View File

@@ -26,7 +26,7 @@ import bpy
import bgl import bgl
import pillarsdk 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 menu_item as menu_item_mod # so that we can have menu items called 'menu_item'
from . import nodes from . import nodes
@@ -648,6 +648,7 @@ class BlenderCloudBrowser(pillar.PillarOperatorMixin,
self.scroll_offset_target = self.scroll_offset = 0 self.scroll_offset_target = self.scroll_offset = 0
@compatibility.convert_properties
class PILLAR_OT_switch_hdri(pillar.PillarOperatorMixin, class PILLAR_OT_switch_hdri(pillar.PillarOperatorMixin,
async_loop.AsyncModalOperatorMixin, async_loop.AsyncModalOperatorMixin,
bpy.types.Operator): bpy.types.Operator):
@@ -776,7 +777,7 @@ def _hdri_download_panel(self, current_image):
current_image.name) current_image.name)
return 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.label(text='HDRi', icon_value=blender.icon('CLOUD'))
row.prop(current_image, 'hdri_variation', text='') row.prop(current_image, 'hdri_variation', text='')

View File

@@ -105,3 +105,8 @@ def bind_texture(texture: bpy.types.Image):
"""Bind a Blender image to a GL texture slot.""" """Bind a Blender image to a GL texture slot."""
bgl.glActiveTexture(bgl.GL_TEXTURE0) bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture.bindcode) bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture.bindcode)
def load_texture(texture: bpy.types.Image) -> int:
"""Load the texture, return OpenGL error code."""
return texture.gl_load()

View File

@@ -88,3 +88,8 @@ def aabox_with_texture(v1: Float2, v2: Float2):
def bind_texture(texture: bpy.types.Image): def bind_texture(texture: bpy.types.Image):
"""Bind a Blender image to a GL texture slot.""" """Bind a Blender image to a GL texture slot."""
bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture.bindcode[0]) bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture.bindcode[0])
def load_texture(texture: bpy.types.Image) -> int:
"""Load the texture, return OpenGL error code."""
return texture.gl_load(filter=bgl.GL_NEAREST, mag=bgl.GL_NEAREST)

View File

@@ -164,7 +164,7 @@ class MenuItem:
texture = self.icon texture = self.icon
if texture: if texture:
err = texture.gl_load(filter=bgl.GL_NEAREST, mag=bgl.GL_NEAREST) err = draw.load_texture(texture)
assert not err, 'OpenGL error: %i' % err assert not err, 'OpenGL error: %i' % err
# ------ TEXTURE ---------# # ------ TEXTURE ---------#

View File

@@ -94,7 +94,10 @@ def pyside_cache(propname):
result = wrapped(self, context) result = wrapped(self, context)
return result return result
finally: 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 rna_info['_cached_result'] = result
return wrapper return wrapper
return decorator return decorator

View File

@@ -1,9 +1,9 @@
# Primary requirements: # Primary requirements:
-e git+https://github.com/sybrenstuvel/cachecontrol.git@sybren-filecache-delete-crash-fix#egg=CacheControl -e git+https://github.com/sybrenstuvel/cachecontrol.git@sybren-filecache-delete-crash-fix#egg=CacheControl
lockfile==0.12.2 lockfile==0.12.2
pillarsdk==1.7.0 pillarsdk==1.8.0
wheel==0.29.0 wheel==0.29.0
blender-asset-tracer==1.1.1 blender-asset-tracer==1.2.1
# Secondary requirements: # Secondary requirements:
asn1crypto==0.24.0 asn1crypto==0.24.0

View File

@@ -123,8 +123,8 @@ class BuildWheels(Command):
"""Downloads a wheel from PyPI and saves it in self.wheels_path.""" """Downloads a wheel from PyPI and saves it in self.wheels_path."""
subprocess.check_call([ subprocess.check_call([
'pip', 'download', sys.executable, '-m', 'pip',
'--no-deps', 'download', '--no-deps',
'--dest', str(self.wheels_path), '--dest', str(self.wheels_path),
requirement[0] requirement[0]
]) ])
@@ -236,7 +236,7 @@ setup(
'wheels': BuildWheels}, 'wheels': BuildWheels},
name='blender_cloud', name='blender_cloud',
description='The Blender Cloud addon allows browsing the Blender Cloud from Blender.', description='The Blender Cloud addon allows browsing the Blender Cloud from Blender.',
version='1.13.1', version='1.14',
author='Sybren A. Stüvel', author='Sybren A. Stüvel',
author_email='sybren@stuvel.eu', author_email='sybren@stuvel.eu',
packages=find_packages('.'), packages=find_packages('.'),

View File

@@ -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 git tag -a version-$VERSION -m \'Tagged version $VERSION\'
echo echo
echo "To build a distribution ZIP:" echo "To build a distribution ZIP:"
echo python setup.py bdist echo python3 setup.py bdist