Attract: render thumbnail button
Still a bit rough, needs GUI response to show upload is happening.
This commit is contained in:
parent
603159f0d1
commit
feb62ddae0
@ -36,17 +36,22 @@
|
|||||||
# "support": "TESTING"
|
# "support": "TESTING"
|
||||||
# }
|
# }
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
if "bpy" in locals():
|
if "bpy" in locals():
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
importlib.reload(draw)
|
draw = importlib.reload(draw)
|
||||||
|
pillar = importlib.reload(pillar)
|
||||||
|
async_loop = importlib.reload(async_loop)
|
||||||
else:
|
else:
|
||||||
from . import draw
|
from . import draw
|
||||||
|
from .. import pillar, async_loop
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
import pillarsdk
|
||||||
from pillarsdk.nodes import Node
|
from pillarsdk.nodes import Node
|
||||||
from pillarsdk.projects import Project
|
from pillarsdk.projects import Project
|
||||||
from pillarsdk import exceptions as sdk_exceptions
|
from pillarsdk import exceptions as sdk_exceptions
|
||||||
@ -115,12 +120,14 @@ class ToolsPanel(Panel):
|
|||||||
ro_sub.prop(strip, 'atc_notes', text='Notes')
|
ro_sub.prop(strip, 'atc_notes', text='Notes')
|
||||||
|
|
||||||
if strip.atc_is_synced:
|
if strip.atc_is_synced:
|
||||||
row = layout.row(align=True)
|
sub = layout.column(align=True)
|
||||||
|
row = sub.row(align=True)
|
||||||
row.operator('attract.submit_selected', text='Submit %s' % noun)
|
row.operator('attract.submit_selected', text='Submit %s' % noun)
|
||||||
row.operator(AttractShotFetchUpdate.bl_idname,
|
row.operator(AttractShotFetchUpdate.bl_idname,
|
||||||
text='', icon='FILE_REFRESH')
|
text='', icon='FILE_REFRESH')
|
||||||
row.operator(ATTRACT_OT_shot_open_in_browser.bl_idname,
|
row.operator(ATTRACT_OT_shot_open_in_browser.bl_idname,
|
||||||
text='', icon='WORLD')
|
text='', icon='WORLD')
|
||||||
|
sub.operator(ATTRACT_OT_make_shot_thumbnail.bl_idname)
|
||||||
|
|
||||||
# Group more dangerous operations.
|
# Group more dangerous operations.
|
||||||
dangerous_sub = layout.column(align=True)
|
dangerous_sub = layout.column(align=True)
|
||||||
@ -481,12 +488,131 @@ class ATTRACT_OT_open_meta_blendfile(AttractOperatorMixin, Operator):
|
|||||||
|
|
||||||
if scene:
|
if scene:
|
||||||
cmd.extend(['--python-expr',
|
cmd.extend(['--python-expr',
|
||||||
'import bpy; bpy.context.screen.scene = bpy.data.scenes["%s"]' % scene])
|
'import bpy; bpy.context.screen.scene = bpy.data.scenes["%s"]' % scene])
|
||||||
cmd.extend(['--scene', scene])
|
cmd.extend(['--scene', scene])
|
||||||
|
|
||||||
subprocess.Popen(cmd)
|
subprocess.Popen(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def thumbnail_render_settings(context, thumbnail_width=512):
|
||||||
|
orig_res_x = context.scene.render.resolution_x
|
||||||
|
orig_res_y = context.scene.render.resolution_y
|
||||||
|
orig_percentage = context.scene.render.resolution_percentage
|
||||||
|
orig_file_format = context.scene.render.image_settings.file_format
|
||||||
|
orig_quality = context.scene.render.image_settings.quality
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Update the render size to something thumbnaily.
|
||||||
|
factor = orig_res_y / orig_res_x
|
||||||
|
context.scene.render.resolution_x = thumbnail_width
|
||||||
|
context.scene.render.resolution_y = round(thumbnail_width * factor)
|
||||||
|
context.scene.render.resolution_percentage = 100
|
||||||
|
context.scene.render.image_settings.file_format = 'JPEG'
|
||||||
|
context.scene.render.image_settings.quality = 85
|
||||||
|
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
# Return the render settings to normal.
|
||||||
|
context.scene.render.resolution_x = orig_res_x
|
||||||
|
context.scene.render.resolution_y = orig_res_y
|
||||||
|
context.scene.render.resolution_percentage = orig_percentage
|
||||||
|
context.scene.render.image_settings.file_format = orig_file_format
|
||||||
|
context.scene.render.image_settings.quality = orig_quality
|
||||||
|
|
||||||
|
|
||||||
|
class ATTRACT_OT_make_shot_thumbnail(AttractOperatorMixin,
|
||||||
|
async_loop.AsyncModalOperatorMixin,
|
||||||
|
Operator):
|
||||||
|
bl_idname = 'attract.make_shot_thumbnail'
|
||||||
|
bl_label = 'Render shot thumbnail'
|
||||||
|
bl_description = 'Renders the current frame, and uploads it as thumbnail for the shot'
|
||||||
|
|
||||||
|
stop_upon_exception = True
|
||||||
|
|
||||||
|
async def async_execute(self, context):
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
# Later: for strip in context.selected_sequences:
|
||||||
|
strip = active_strip(context)
|
||||||
|
atc_object_id = getattr(strip, 'atc_object_id', None)
|
||||||
|
if not atc_object_id:
|
||||||
|
self.report({'ERROR'}, 'Strip %s not set up for Attract' % strip.name)
|
||||||
|
self.quit()
|
||||||
|
return
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile() as tmpfile:
|
||||||
|
with thumbnail_render_settings(context):
|
||||||
|
bpy.ops.render.render()
|
||||||
|
file_id = await self.upload_via_tempdir(bpy.data.images['Render Result'],
|
||||||
|
'attract_shot_thumbnail.jpg')
|
||||||
|
|
||||||
|
if file_id is None:
|
||||||
|
self.quit()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Update the shot to include this file as the picture.
|
||||||
|
node = pillarsdk.Node({'_id': atc_object_id})
|
||||||
|
await pillar.pillar_call(
|
||||||
|
node.patch,
|
||||||
|
{
|
||||||
|
'op': 'from-blender',
|
||||||
|
'$set': {
|
||||||
|
'picture': file_id,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.report({'INFO'}, 'Thumbnail uploaded to Attract')
|
||||||
|
self.quit()
|
||||||
|
|
||||||
|
async def upload_via_tempdir(self, datablock, filename_on_cloud) -> pillarsdk.Node:
|
||||||
|
"""Saves the datablock to file, and uploads it to the cloud.
|
||||||
|
|
||||||
|
Saving is done to a temporary directory, which is removed afterwards.
|
||||||
|
|
||||||
|
Returns the node.
|
||||||
|
"""
|
||||||
|
import tempfile
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
filepath = os.path.join(tmpdir, filename_on_cloud)
|
||||||
|
self.log.debug('Saving %s to %s', datablock, filepath)
|
||||||
|
datablock.save_render(filepath)
|
||||||
|
return await self.upload_file(filepath)
|
||||||
|
|
||||||
|
async def upload_file(self, filename: str, fileobj=None):
|
||||||
|
"""Uploads a file to the cloud, attached to the image sharing node.
|
||||||
|
|
||||||
|
Returns the node.
|
||||||
|
"""
|
||||||
|
from .. import blender
|
||||||
|
|
||||||
|
prefs = blender.preferences()
|
||||||
|
project = self.find_project(prefs.attract_project.project)
|
||||||
|
|
||||||
|
self.log.info('Uploading file %s', filename)
|
||||||
|
resp = await pillar.pillar_call(
|
||||||
|
pillarsdk.File.upload_to_project,
|
||||||
|
project['_id'],
|
||||||
|
'image/jpeg',
|
||||||
|
filename,
|
||||||
|
fileobj=fileobj)
|
||||||
|
|
||||||
|
self.log.debug('Returned data: %s', resp)
|
||||||
|
try:
|
||||||
|
file_id = resp['file_id']
|
||||||
|
except KeyError:
|
||||||
|
self.log.error('Upload did not succeed, response: %s', resp)
|
||||||
|
self.report({'ERROR'}, 'Unable to upload thumbnail to Attract: %s' % resp)
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.log.info('Created file %s', file_id)
|
||||||
|
self.report({'INFO'}, 'File succesfully uploaded to the cloud!')
|
||||||
|
|
||||||
|
return file_id
|
||||||
|
|
||||||
|
|
||||||
def draw_strip_movie_meta(self, context):
|
def draw_strip_movie_meta(self, context):
|
||||||
strip = active_strip(context)
|
strip = active_strip(context)
|
||||||
if not strip:
|
if not strip:
|
||||||
@ -537,6 +663,7 @@ def register():
|
|||||||
bpy.utils.register_class(AttractShotSubmitSelected)
|
bpy.utils.register_class(AttractShotSubmitSelected)
|
||||||
bpy.utils.register_class(ATTRACT_OT_open_meta_blendfile)
|
bpy.utils.register_class(ATTRACT_OT_open_meta_blendfile)
|
||||||
bpy.utils.register_class(ATTRACT_OT_shot_open_in_browser)
|
bpy.utils.register_class(ATTRACT_OT_shot_open_in_browser)
|
||||||
|
bpy.utils.register_class(ATTRACT_OT_make_shot_thumbnail)
|
||||||
draw.callback_enable()
|
draw.callback_enable()
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user