Integrating data system; unit tests in Blender
This commit is contained in:
parent
48841cc05b
commit
0d81cc5857
|
@ -1,11 +0,0 @@
|
|||
#script to run:
|
||||
SCRIPT="/project/terry/Dev/eclipse-workspace/ABX/src/abx.py"
|
||||
|
||||
#path to the PyDev folder that contains a file named pydevd.py:
|
||||
PYDEVD_PATH='/home/terry/.eclipse/360744294_linux_gtk_x86_64/plugins/org.python.pydev.core_7.3.0.201908161924/pysrc/'
|
||||
|
||||
#PYDEVD_PATH='/home/terry/.config/blender/2.79/scripts/addons/modules/pydev_debug.py'
|
||||
|
||||
import pydev_debug as pydev #pydev_debug.py is in a folder from Blender PYTHONPATH
|
||||
|
||||
pydev.debug(SCRIPT, PYDEVD_PATH, trace = True)
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
# Run the script in the debugger client within Blender:
|
||||
import subprocess
|
||||
subprocess.call(['blender', '-P', '/project/terry/Dev/eclipse-workspace/ABX/BlenderRemoteDebug.py'])
|
||||
subprocess.call(['blender279', '-P', '/project/terry/Dev/Git/abx/scripts/BlenderRemoteDebug.py'])
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
# Inject the unittest runner script into Blender and run it in batch mode:
|
||||
import subprocess
|
||||
subprocess.call(['blender279', '-b', '-P', '/project/terry/Dev/Git/abx/scripts/TestInBlender_bpy.py'])
|
|
@ -2,7 +2,7 @@
|
|||
bl_info = {
|
||||
"name": "ABX",
|
||||
"author": "Terry Hancock / Lunatics.TV Project / Anansi Spaceworks",
|
||||
"version": (0, 2, 5),
|
||||
"version": (0, 2, 6),
|
||||
"blender": (2, 79, 0),
|
||||
"location": "SpaceBar Search -> ABX",
|
||||
"description": "Anansi Studio Extensions for Blender",
|
||||
|
@ -22,17 +22,20 @@ try:
|
|||
except ImportError:
|
||||
print("Blender Add-On 'ABX' requires the Blender Python environment to run.")
|
||||
|
||||
print("blender_present = ", blender_present)
|
||||
|
||||
if blender_present:
|
||||
if blender_present:
|
||||
from . import abx_ui
|
||||
|
||||
|
||||
BlendFile = abx_ui.BlendFile
|
||||
|
||||
def register():
|
||||
bpy.utils.register_module(__name__)
|
||||
|
||||
abx_ui.register()
|
||||
#bpy.utils.register_module(__name__)
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_module(__name__)
|
||||
abx_ui.unregister()
|
||||
#bpy.utils.unregister_module(__name__)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
175
abx/abx.yaml
175
abx/abx.yaml
|
@ -1,72 +1,113 @@
|
|||
# DEFAULT ABX SETTINGS
|
||||
---
|
||||
project_schema:
|
||||
- rank: project
|
||||
delimiter: '-'
|
||||
words: True
|
||||
type: string
|
||||
|
||||
- rank: sequence
|
||||
type:
|
||||
VN: Vague Name
|
||||
|
||||
- rank: shot
|
||||
type: letter
|
||||
maxlength: 1
|
||||
|
||||
- rank: element
|
||||
type: string
|
||||
maxlength: 2
|
||||
abx_default: True
|
||||
|
||||
render_profiles:
|
||||
previz:
|
||||
name: PreViz,
|
||||
desc: 'GL/AVI Previz Render for Animatics',
|
||||
engine: gl
|
||||
version: any
|
||||
fps: 30
|
||||
fps_div: 1000
|
||||
fps_skip: 1
|
||||
suffix: GL
|
||||
format: AVI_JPEG
|
||||
extension: avi
|
||||
freestyle: False
|
||||
project_unit: []
|
||||
|
||||
project_schema: []
|
||||
|
||||
definitions:
|
||||
filetypes:
|
||||
blend: "Blender File"
|
||||
kdenlive: "Kdenlive Video Editor File"
|
||||
mlt: "Kdenlive Video Mix Script"
|
||||
svg: "Scalable Vector Graphics (Inkscape)"
|
||||
kra: "Krita Graphic File"
|
||||
xcf: "Gimp Graphic File"
|
||||
png: "Portable Network Graphics (PNG) Image"
|
||||
jpg: "Joint Photographic Experts Group (JPEG) Image"
|
||||
aup: "Audacity Project"
|
||||
ardour: "Ardour Project"
|
||||
flac: "Free Lossless Audio Codec (FLAC)"
|
||||
mp3: "MPEG Audio Layer III (MP3) Audio File"
|
||||
ogg: "Ogg Vorbis Audio File"
|
||||
avi: "Audio Video Interleave (AVI) Video Container"
|
||||
mkv: "Matroska Video Container"
|
||||
mp4: "Moving Picture Experts Group (MPEG) 4 Format"
|
||||
txt: "Plain Text File"
|
||||
|
||||
quick:
|
||||
name: 30fps Paint
|
||||
desc: '30fps Simplified Paint-Only Render'
|
||||
engine: bi
|
||||
fps: 30
|
||||
fps_skip: 3
|
||||
suffix: PT
|
||||
format: AVI_JPEG
|
||||
extension: avi
|
||||
freestyle: False,
|
||||
antialias: False,
|
||||
motionblur: False
|
||||
roles:
|
||||
extras: "Extras, crowds, auxillary animated movement"
|
||||
mech: "Mechanical animation"
|
||||
anim: "Character animation"
|
||||
cam: "Camera direction"
|
||||
vfx: "Visual special effects"
|
||||
compos: "Compositing"
|
||||
bkg: "Background 2D image"
|
||||
bb: "Billboard 2D image"
|
||||
tex: "Texture 2D image"
|
||||
foley: "Foley sound"
|
||||
voice: "Voice recording"
|
||||
fx: "Sound effects"
|
||||
music: "Music track"
|
||||
cue: "Musical cue"
|
||||
amb: "Ambient sound"
|
||||
loop: "Ambient sound loop"
|
||||
edit: "Video edit"
|
||||
|
||||
roles_by_filetype:
|
||||
kdenlive: edit
|
||||
mlt: edit
|
||||
|
||||
omit_ranks: # Controls how much we shorten names
|
||||
edit: 0
|
||||
render: 0
|
||||
filename: 0
|
||||
scene: 0
|
||||
|
||||
abx:
|
||||
render_profiles:
|
||||
previz:
|
||||
name: PreViz,
|
||||
desc: 'GL/AVI Previz Render for Animatics'
|
||||
engine: gl
|
||||
version: any
|
||||
fps: 30
|
||||
fps_div: 1000
|
||||
fps_skip: 1
|
||||
suffix: GL
|
||||
format: AVI_JPEG
|
||||
extension: avi
|
||||
freestyle: False
|
||||
|
||||
check:
|
||||
name: 1fps Check
|
||||
desc: '1fps Full-Features Check Renders'
|
||||
engine: bi
|
||||
fps: 30
|
||||
fps_skip: 30
|
||||
suffix: CH
|
||||
format: JPEG
|
||||
extension: jpg
|
||||
framedigits: 5
|
||||
freestyle: True
|
||||
antialias: 8
|
||||
|
||||
full:
|
||||
name: 30fps Full
|
||||
desc: 'Full Render with all Features Turned On',
|
||||
engine: bi
|
||||
fps: 30
|
||||
fps_skip: 1
|
||||
suffix: ''
|
||||
format: PNG
|
||||
extension: png
|
||||
framedigits: 5
|
||||
freestyle: True
|
||||
antialias: 8
|
||||
quick:
|
||||
name: 30fps Paint
|
||||
desc: '30fps Simplified Paint-Only Render'
|
||||
engine: bi
|
||||
fps: 30
|
||||
fps_skip: 3
|
||||
suffix: PT
|
||||
format: AVI_JPEG
|
||||
extension: avi
|
||||
freestyle: False,
|
||||
antialias: False,
|
||||
motionblur: False
|
||||
|
||||
check:
|
||||
name: 1fps Check
|
||||
desc: '1fps Full-Features Check Renders'
|
||||
engine: bi
|
||||
fps: 30
|
||||
fps_skip: 30
|
||||
suffix: CH
|
||||
format: JPEG
|
||||
extension: jpg
|
||||
framedigits: 5
|
||||
freestyle: True
|
||||
antialias: 8
|
||||
|
||||
full:
|
||||
name: 30fps Full
|
||||
desc: 'Full Render with all Features Turned On'
|
||||
engine: bi
|
||||
fps: 30
|
||||
fps_skip: 1
|
||||
suffix: ''
|
||||
format: PNG
|
||||
extension: png
|
||||
framedigits: 5
|
||||
freestyle: True
|
||||
antialias: 8
|
||||
motionblur: 2
|
||||
rendersize: 100
|
||||
compress: 50
|
||||
|
|
|
@ -23,14 +23,22 @@ run into.
|
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
|
||||
|
||||
import os
|
||||
|
||||
import bpy, bpy.utils, bpy.types, bpy.props
|
||||
from bpy.app.handlers import persistent
|
||||
|
||||
from . import file_context
|
||||
|
||||
# if bpy.data.filepath:
|
||||
# BlendfileContext = file_context.FileContext(bpy.data.filepath)
|
||||
# else:
|
||||
# BlendfileContext = file_context.FileContext()
|
||||
#
|
||||
# abx_data = BlendfileContext.abx_data
|
||||
|
||||
from . import copy_anim
|
||||
from . import std_lunatics_ink
|
||||
from abx import ink_paint
|
||||
from . import render_profile
|
||||
|
||||
|
||||
|
@ -273,8 +281,7 @@ class LunaticsSceneProperties(bpy.types.PropertyGroup):
|
|||
maxlen=0
|
||||
)
|
||||
|
||||
bpy.utils.register_class(LunaticsSceneProperties)
|
||||
bpy.types.Scene.lunaprops = bpy.props.PointerProperty(type=LunaticsSceneProperties)
|
||||
|
||||
|
||||
class LunaticsScenePanel(bpy.types.Panel):
|
||||
"""
|
||||
|
@ -315,9 +322,7 @@ class RenderProfileSettings(bpy.types.PropertyGroup):
|
|||
description="Select from pre-defined profiles of render settings",
|
||||
default='full')
|
||||
|
||||
bpy.utils.register_class(RenderProfileSettings)
|
||||
bpy.types.Scene.render_profile_settings = bpy.props.PointerProperty(
|
||||
type=RenderProfileSettings)
|
||||
|
||||
|
||||
class RenderProfilesOperator(bpy.types.Operator):
|
||||
"""
|
||||
|
@ -335,6 +340,7 @@ class RenderProfilesOperator(bpy.types.Operator):
|
|||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class RenderProfilesPanel(bpy.types.Panel):
|
||||
"""
|
||||
Add simple drop-down selector for generating common render settings with
|
||||
|
@ -354,6 +360,7 @@ class RenderProfilesPanel(bpy.types.Panel):
|
|||
row.operator('render.render_profiles')
|
||||
|
||||
|
||||
|
||||
class copy_animation(bpy.types.Operator):
|
||||
"""
|
||||
Copy animation from active object to selected objects (select source last!).
|
||||
|
@ -399,6 +406,8 @@ class copy_animation(bpy.types.Operator):
|
|||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
|
||||
class copy_animation_settings(bpy.types.PropertyGroup):
|
||||
"""
|
||||
Settings for the 'copy_animation' operator.
|
||||
|
@ -423,8 +432,7 @@ class copy_animation_settings(bpy.types.PropertyGroup):
|
|||
description = "Scale factor for scaling animation (Re-Scale w/ 1.0 copies actions)",
|
||||
default = 1.0)
|
||||
|
||||
bpy.utils.register_class(copy_animation_settings)
|
||||
bpy.types.Scene.copy_anim_settings = bpy.props.PointerProperty(type=copy_animation_settings)
|
||||
|
||||
|
||||
class CharacterPanel(bpy.types.Panel):
|
||||
bl_space_type = "VIEW_3D" # window type panel is displayed in
|
||||
|
@ -443,7 +451,7 @@ class CharacterPanel(bpy.types.Panel):
|
|||
layout.prop(settings, 'rescale')
|
||||
layout.prop(settings, 'scale_factor')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class lunatics_compositing_settings(bpy.types.PropertyGroup):
|
||||
|
@ -465,9 +473,7 @@ class lunatics_compositing_settings(bpy.types.PropertyGroup):
|
|||
description = "Render sky separately with compositing support (better shadows)",
|
||||
default = True)
|
||||
|
||||
bpy.utils.register_class(lunatics_compositing_settings)
|
||||
bpy.types.Scene.lx_compos_settings = bpy.props.PointerProperty(type=lunatics_compositing_settings)
|
||||
|
||||
|
||||
class lunatics_compositing(bpy.types.Operator):
|
||||
"""
|
||||
Set up standard Lunatics scene compositing.
|
||||
|
@ -483,7 +489,7 @@ class lunatics_compositing(bpy.types.Operator):
|
|||
"""
|
||||
scene = context.scene
|
||||
|
||||
shot = std_lunatics_ink.LunaticsShot(scene,
|
||||
shot = ink_paint.LunaticsShot(scene,
|
||||
inkthru=context.scene.lx_compos_settings.inkthru,
|
||||
billboards=context.scene.lx_compos_settings.billboards,
|
||||
sepsky=context.scene.lx_compos_settings.sepsky )
|
||||
|
@ -497,7 +503,7 @@ class lunatics_compositing(bpy.types.Operator):
|
|||
# self.col = self.layout.col()
|
||||
# col.prop(settings, "inkthru", text="Ink Thru")
|
||||
# col.prop(settings, "billboards", text="Ink Thru")
|
||||
|
||||
|
||||
|
||||
|
||||
class LunaticsPanel(bpy.types.Panel):
|
||||
|
@ -515,16 +521,52 @@ class LunaticsPanel(bpy.types.Panel):
|
|||
layout.prop(settings, 'inkthru', text="Ink-Thru")
|
||||
layout.prop(settings, 'billboards', text="Billboards")
|
||||
layout.prop(settings, 'sepsky', text="Separate Sky")
|
||||
|
||||
|
||||
|
||||
BlendFile = file_context.FileContext()
|
||||
|
||||
@persistent
|
||||
def update_handler(ctxt):
|
||||
BlendFile.update(bpy.data.filepath)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.utils.register_module(__name__)
|
||||
bpy.utils.register_class(LunaticsSceneProperties)
|
||||
bpy.types.Scene.lunaprops = bpy.props.PointerProperty(type=LunaticsSceneProperties)
|
||||
bpy.utils.register_class(LunaticsScenePanel)
|
||||
|
||||
bpy.utils.register_class(RenderProfileSettings)
|
||||
bpy.types.Scene.render_profile_settings = bpy.props.PointerProperty(
|
||||
type=RenderProfileSettings)
|
||||
bpy.utils.register_class(RenderProfilesOperator)
|
||||
bpy.utils.register_class(RenderProfilesPanel)
|
||||
|
||||
bpy.utils.register_class(copy_animation)
|
||||
bpy.utils.register_class(copy_animation_settings)
|
||||
bpy.types.Scene.copy_anim_settings = bpy.props.PointerProperty(type=copy_animation_settings)
|
||||
bpy.utils.register_class(CharacterPanel)
|
||||
|
||||
bpy.utils.register_class(lunatics_compositing_settings)
|
||||
bpy.types.Scene.lx_compos_settings = bpy.props.PointerProperty(type=lunatics_compositing_settings)
|
||||
bpy.utils.register_class(lunatics_compositing)
|
||||
bpy.utils.register_class(LunaticsPanel)
|
||||
|
||||
bpy.app.handlers.save_post.append(update_handler)
|
||||
bpy.app.handlers.load_post.append(update_handler)
|
||||
bpy.app.handlers.scene_update_post.append(update_handler)
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_module(__name__)
|
||||
bpy.utils.unregister_class(LunaticsSceneProperties)
|
||||
bpy.utils.unregister_class(LunaticsScenePanel)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
||||
|
||||
|
||||
bpy.utils.unregister_class(RenderProfileSettings)
|
||||
bpy.utils.unregister_class(RenderProfilesOperator)
|
||||
bpy.utils.unregister_class(RenderProfilesPanel)
|
||||
|
||||
bpy.utils.unregister_class(copy_animation)
|
||||
bpy.utils.unregister_class(copy_animation_settings)
|
||||
bpy.utils.unregister_class(CharacterPanel)
|
||||
|
||||
bpy.utils.unregister_class(lunatics_compositing_settings)
|
||||
bpy.utils.unregister_class(lunatics_compositing)
|
||||
bpy.utils.unregister_class(LunaticsPanel)
|
||||
|
|
|
@ -244,6 +244,10 @@ class RecursiveDict(collections.OrderedDict):
|
|||
#--------
|
||||
# Code for collecting the YAML files we need
|
||||
|
||||
ABX_YAML = os.path.join(os.path.dirname(
|
||||
os.path.abspath(os.path.join(__file__))),
|
||||
'abx.yaml')
|
||||
|
||||
|
||||
def collect_yaml_files(path, stems, dirmatch=False, sidecar=False, root='/'):
|
||||
"""
|
||||
|
@ -327,8 +331,10 @@ def get_project_data(filepath):
|
|||
|
||||
kitcat_root = get_project_root(kitcat_paths)
|
||||
|
||||
abx_data = combine_yaml(collect_yaml_files(filepath,
|
||||
'abx', root=kitcat_root))
|
||||
abx_data = combine_yaml([ABX_YAML])['abx']
|
||||
|
||||
abx_data.update(combine_yaml(collect_yaml_files(filepath,
|
||||
'abx', root=kitcat_root)))
|
||||
|
||||
return kitcat_root, kitcat_data, abx_data
|
||||
|
||||
|
|
|
@ -58,6 +58,11 @@ Demo:
|
|||
import os, re, copy, string, collections
|
||||
import yaml
|
||||
|
||||
DEFAULT_YAML = {}
|
||||
with open(os.path.join(os.path.dirname(__file__), 'abx.yaml')) as def_yaml_file:
|
||||
DEFAULT_YAML.update(yaml.safe_load(def_yaml_file))
|
||||
|
||||
|
||||
TESTPATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'testdata', 'myproject', 'Episodes', 'A.001-Pilot', 'Seq', 'LP-LastPoint', 'A.001-LP-1-BeginningOfEnd-anim.txt'))
|
||||
|
||||
from . import accumulate
|
||||
|
@ -66,6 +71,53 @@ from .accumulate import RecursiveDict
|
|||
|
||||
wordre = re.compile(r'([A-Z][a-z]+|[a-z]+|[0-9]+|[A-Z][A-Z]+)')
|
||||
|
||||
class Enum(dict):
|
||||
def __init__(self, *options):
|
||||
for i, option in enumerate(options):
|
||||
if isinstance(option, list) or isinstance(option, tuple):
|
||||
name = option[0]
|
||||
self[i] = tuple(option)
|
||||
else:
|
||||
name = str(option)
|
||||
self[i] = (option, option, option)
|
||||
self[name] = i
|
||||
if name not in ('name', 'number', 'options'):
|
||||
setattr(self, name, i)
|
||||
|
||||
@property
|
||||
def options(self):
|
||||
"""
|
||||
This gives the options in a Blender-friendly format, with
|
||||
tuples of three strings for initializing bpy.props.Enum().
|
||||
|
||||
If the Enum was initialized with strings, the options will
|
||||
contain the same string three times. If initialized with
|
||||
tuples of strings, they will be used unaltered.
|
||||
"""
|
||||
options = []
|
||||
number_keys = sorted([k for k in self.keys() if type(k) is int])
|
||||
return [self[i] for i in number_keys]
|
||||
|
||||
def name(self, n):
|
||||
if type(n) is int:
|
||||
return self[n][0]
|
||||
elif type(n) is str:
|
||||
return n
|
||||
else:
|
||||
return None
|
||||
|
||||
def number(self, n):
|
||||
if type(n) is str:
|
||||
return self[n]
|
||||
elif type(n) is int:
|
||||
return n
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
log_level = Enum('DEBUG', 'INFO', 'WARNING', 'ERROR')
|
||||
|
||||
|
||||
NameParsers = {} # Parser registry
|
||||
|
||||
def registered_parser(parser):
|
||||
|
@ -352,9 +404,12 @@ class Parser_ABX_Schema(object):
|
|||
start = 0
|
||||
for start, (schema, name) in enumerate(zip(self.schemas, namepath)):
|
||||
field, r, s = self._parse_beginning(remainder, schema.delimiter)
|
||||
if field.lower() == schema.format.format(name).lower():
|
||||
score += 1.0
|
||||
break
|
||||
try:
|
||||
if field.lower() == schema.format.format(name).lower():
|
||||
score += 1.0
|
||||
break
|
||||
except ValueError:
|
||||
print(' (365) field, format', field, schema.format)
|
||||
|
||||
possible += 1.0
|
||||
|
||||
|
@ -366,11 +421,14 @@ class Parser_ABX_Schema(object):
|
|||
if not remainder: break
|
||||
field, remainder, s = self._parse_beginning(remainder, schema.delimiter)
|
||||
score += s
|
||||
if ( type(field) == str and
|
||||
field.lower() == schema.format.format(name).lower()):
|
||||
fields[schema.rank]={'code':field}
|
||||
fields['rank'] = schema.rank
|
||||
score += 1.0
|
||||
try:
|
||||
if ( type(field) == str and
|
||||
field.lower() == schema.format.format(name).lower()):
|
||||
fields[schema.rank]={'code':field}
|
||||
fields['rank'] = schema.rank
|
||||
score += 1.0
|
||||
except ValueError:
|
||||
print(' (384) field, format', field, schema.format)
|
||||
possible += 2.0
|
||||
|
||||
# Remaining fields are authoritative (doesn't affect score)
|
||||
|
@ -387,6 +445,77 @@ class Parser_ABX_Schema(object):
|
|||
fields['role'] = self.roles_by_filetype[fields['filetype']]
|
||||
|
||||
return score/possible, fields
|
||||
|
||||
@registered_parser
|
||||
class Parser_ABX_Fallback(object):
|
||||
"""
|
||||
Highly-tolerant parser to fall back to if the others fail
|
||||
or can't be used.
|
||||
"""
|
||||
name = 'abx_fallback'
|
||||
|
||||
filetypes = DEFAULT_YAML['definitions']['filetypes']
|
||||
roles = DEFAULT_YAML['definitions']['roles']
|
||||
roles_by_filetype = (
|
||||
DEFAULT_YAML['definitions']['roles_by_filetype'])
|
||||
|
||||
main_sep_re = re.compile(r'\W+') # Any single non-word char
|
||||
comment_sep_re = re.compile(r'[\W_][\W_]+|[~#$!=+&]+')
|
||||
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
pass
|
||||
|
||||
def _parse_ending(self, filename, separator):
|
||||
try:
|
||||
remainder, suffix = filename.rsplit(separator, 1)
|
||||
score = 1.0
|
||||
except ValueError:
|
||||
remainder = filename
|
||||
suffix = None
|
||||
score = 0.0
|
||||
return (suffix, remainder, score)
|
||||
|
||||
def __call__(self, filename, namepath):
|
||||
fields = {}
|
||||
score = 1.0
|
||||
possible = 4.5
|
||||
|
||||
split = filename.rsplit('.', 1)
|
||||
if len(split)<2 or split[1] not in self.filetypes:
|
||||
fields['filetype'] = None
|
||||
remainder = filename
|
||||
score += 1.0
|
||||
else:
|
||||
fields['filetype'] = split[1]
|
||||
remainder = split[0]
|
||||
|
||||
comment_match = self.comment_sep_re.search(remainder)
|
||||
if comment_match:
|
||||
fields['comment'] = remainder[comment_match.end():]
|
||||
remainder = remainder[:comment_match.start()]
|
||||
else:
|
||||
fields['comment'] = None
|
||||
|
||||
role = self.main_sep_re.split(remainder)[-1]
|
||||
if role in self.roles:
|
||||
fields['role'] = role
|
||||
remainder = remainder[:-1-len(role)]
|
||||
score += 1.0
|
||||
else:
|
||||
fields['role'] = None
|
||||
|
||||
# Implied role
|
||||
if fields['filetype'] in self.roles_by_filetype:
|
||||
fields['role'] = self.roles_by_filetype[fields['filetype']]
|
||||
score += 1.0
|
||||
|
||||
words = self.main_sep_re.split(remainder)
|
||||
fields['code'] = ''.join([w.capitalize() for w in words])
|
||||
fields['title'] = remainder
|
||||
|
||||
return score/possible, fields
|
||||
|
||||
|
||||
|
||||
class RankNotFound(LookupError):
|
||||
|
@ -574,8 +703,19 @@ class NameContext(object):
|
|||
"""
|
||||
|
||||
def __init__(self, container, fields=None, namepath_segment=(), ):
|
||||
self.schemas = []
|
||||
self.clear()
|
||||
if container or fields or namepath_segment:
|
||||
self.update(container, fields, namepath_segment)
|
||||
|
||||
def clear(self):
|
||||
self.fields = {}
|
||||
self.schemas = ['project']
|
||||
self.rank = 0
|
||||
self.code = 'untitled'
|
||||
self.container = None
|
||||
self.namepath_segment = []
|
||||
|
||||
def update(self, container=None, fields=None, namepath_segment=()):
|
||||
self.container = container
|
||||
|
||||
if namepath_segment:
|
||||
|
@ -584,12 +724,9 @@ class NameContext(object):
|
|||
self.namepath_segment = []
|
||||
|
||||
try:
|
||||
#self.namepath = self.container.namepath
|
||||
self.schemas = self.container.schemas
|
||||
|
||||
except AttributeError:
|
||||
self.schemas = []
|
||||
#self.namepath = []
|
||||
|
||||
try:
|
||||
self.omit_ranks = self.container.omit_ranks
|
||||
|
@ -606,12 +743,6 @@ class NameContext(object):
|
|||
self.fields.update(fields)
|
||||
elif isinstance(fields, str):
|
||||
self.fields.update(yaml.safe_load(fields))
|
||||
|
||||
# if 'code' in self.fields:
|
||||
# self.namepath.append(self.fields['code'])
|
||||
|
||||
#self.code = self.fields[self.rank]['code']
|
||||
|
||||
|
||||
def update_fields(self, data):
|
||||
self.fields.update(data)
|
||||
|
@ -684,7 +815,7 @@ class NameContext(object):
|
|||
return None
|
||||
|
||||
@rank.setter
|
||||
def set_rank(self, rank):
|
||||
def rank(self, rank):
|
||||
self.fields['rank'] = rank
|
||||
|
||||
@property
|
||||
|
@ -699,7 +830,7 @@ class NameContext(object):
|
|||
return ''
|
||||
|
||||
@name.setter
|
||||
def set_name(self, name):
|
||||
def name(self, name):
|
||||
self.fields['name'] = name
|
||||
|
||||
@property
|
||||
|
@ -710,7 +841,7 @@ class NameContext(object):
|
|||
return self.fields['code']
|
||||
|
||||
@code.setter
|
||||
def code_setter(self, code):
|
||||
def code(self, code):
|
||||
if self.rank:
|
||||
self.fields[self.rank] = {'code': code}
|
||||
else:
|
||||
|
@ -724,7 +855,7 @@ class NameContext(object):
|
|||
return ''
|
||||
|
||||
@description.setter
|
||||
def set_description(self, description):
|
||||
def description(self, description):
|
||||
self.fields['description'] = str(description)
|
||||
|
||||
def _get_name_components(self):
|
||||
|
@ -797,6 +928,7 @@ class FileContext(NameContext):
|
|||
# hierarchy = None
|
||||
#schema = None
|
||||
|
||||
# IMMUTABLE DEFAULTS:
|
||||
filepath = None
|
||||
root = None
|
||||
folders = ()
|
||||
|
@ -820,97 +952,151 @@ class FileContext(NameContext):
|
|||
Collect path context information from a given filepath.
|
||||
(Searches the filesystem for context information).
|
||||
"""
|
||||
#self.clear()
|
||||
self.notes = []
|
||||
|
||||
# First init the superclass NameContext
|
||||
NameContext.__init__(self, None, {})
|
||||
|
||||
self.namepath_segment = []
|
||||
|
||||
# TODO:
|
||||
# I need to specify what happens when the path isn't defined.
|
||||
# (Like we might need to initialize later?)
|
||||
|
||||
self.clear()
|
||||
self.clear_notes()
|
||||
if path:
|
||||
self.update(path)
|
||||
|
||||
def clear(self):
|
||||
NameContext.clear(self)
|
||||
|
||||
# Identity
|
||||
self.root = os.path.abspath(os.environ['HOME'])
|
||||
self.render_root = os.path.join(self.root, 'Renders')
|
||||
self.filetype = ''
|
||||
self.role = ''
|
||||
self.title = ''
|
||||
self.comment = ''
|
||||
|
||||
# Containers
|
||||
#self.notes = []
|
||||
self.name_contexts = []
|
||||
|
||||
# Status / Settings
|
||||
self.filepath = None
|
||||
self.filename = None
|
||||
self.file_exists = False
|
||||
self.folder_exists = False
|
||||
self.omit_ranks = {
|
||||
'edit': 0,
|
||||
'render': 0,
|
||||
'filename': 0,
|
||||
'scene': 0}
|
||||
|
||||
# Defaults
|
||||
self.provided_data = RecursiveDict(DEFAULT_YAML)
|
||||
self.abx_fields = DEFAULT_YAML['abx']
|
||||
|
||||
def clear_notes(self):
|
||||
# We use this for logging, so it doesn't get cleared by the
|
||||
# normal clear process.
|
||||
self.notes = []
|
||||
|
||||
def update(self, path):
|
||||
# Basic File Path Info
|
||||
self.filepath = os.path.abspath(path)
|
||||
self.filename = os.path.basename(path)
|
||||
# Basic File Path Info
|
||||
self.filepath = os.path.abspath(path)
|
||||
self.filename = os.path.basename(path)
|
||||
|
||||
# Does the file path exist?
|
||||
if os.path.exists(path):
|
||||
self.file_exists = True
|
||||
self.folder_exists = True
|
||||
else:
|
||||
self.file_exists = False
|
||||
if os.path.exists(os.path.dirname(path)):
|
||||
self.folder_exists = True
|
||||
else:
|
||||
self.folder_exists = False
|
||||
|
||||
# Does the file path exist?
|
||||
# - Should we create it? / Are we creating it?
|
||||
|
||||
# We should add a default YAML file in the ABX software to guarantee
|
||||
# necessary fields are in place, and to document the configuration for
|
||||
# project developers.
|
||||
|
||||
# Data from YAML Files
|
||||
self._collect_yaml_data()
|
||||
|
||||
# Did we find the YAML data for the project?
|
||||
# Did we find the project root?
|
||||
|
||||
# TODO: Bug?
|
||||
# Note that 'project_schema' might not be correct if overrides are given.
|
||||
# As things are, I think it will simply append the overrides, and this
|
||||
# may lead to odd results. We'd need to actively compress the list by
|
||||
# overwriting according to rank
|
||||
#
|
||||
# - Should we create it? / Are we creating it?
|
||||
|
||||
# We should add a default YAML file in the ABX software to guarantee
|
||||
# necessary fields are in place, and to document the configuration for
|
||||
# project developers.
|
||||
|
||||
# Data from YAML Files
|
||||
#self._collect_yaml_data()
|
||||
self.provided_data = RecursiveDict(DEFAULT_YAML)
|
||||
|
||||
kitcat_root, kitcat_data, abx_data = accumulate.get_project_data(self.filepath)
|
||||
self.root = kitcat_root
|
||||
self.provided_data.update(kitcat_data)
|
||||
path = os.path.abspath(os.path.normpath(self.filepath))
|
||||
root = os.path.abspath(self.root)
|
||||
self.folders = [os.path.basename(self.root)]
|
||||
self.folders.extend(os.path.normpath(os.path.relpath(path, root)).split(os.sep)[:-1])
|
||||
|
||||
self.abx_fields = abx_data
|
||||
# Did we find the YAML data for the project?
|
||||
# Did we find the project root?
|
||||
|
||||
# TODO: Bug?
|
||||
# Note that 'project_schema' might not be correct if overrides are given.
|
||||
# As things are, I think it will simply append the overrides, and this
|
||||
# may lead to odd results. We'd need to actively compress the list by
|
||||
# overwriting according to rank
|
||||
#
|
||||
try:
|
||||
self._load_schemas(self.provided_data['project_schema'])
|
||||
self.namepath_segment = [d['code'] for d in self.provided_data['project_unit']]
|
||||
self.code = self.namepath[-1]
|
||||
|
||||
# Was there a "project_schema" section?
|
||||
# - if not, do we fall back to a default?
|
||||
|
||||
# Was there a "project_unit" section?
|
||||
# - if not, can we construct what we need from project_root & folders?
|
||||
|
||||
# Is there a definitions section?
|
||||
# Do we provide defaults?
|
||||
|
||||
try:
|
||||
self.render_root = os.path.join(self.root,
|
||||
self.provided_data['definitions']['render_root'])
|
||||
except KeyError:
|
||||
self.render_root = os.path.join(self.root, 'Renders')
|
||||
|
||||
self.omit_ranks = {}
|
||||
try:
|
||||
for key, val in self.provided_data['definitions']['omit_ranks'].items():
|
||||
self.omit_ranks[key] = int(val)
|
||||
except KeyError:
|
||||
self.omit_ranks.update({
|
||||
'edit': 0,
|
||||
'render': 1,
|
||||
'filename': 1,
|
||||
'scene': 3})
|
||||
|
||||
# Data from Parsing the File Name
|
||||
try:
|
||||
self.parsers = [NameParsers[self.provided_data['definitions']['parser']](**self.schema['filenames'])]
|
||||
except (TypeError, KeyError, IndexError):
|
||||
self.parsers = [
|
||||
#Parser_ABX_Episode(),
|
||||
Parser_ABX_Schema(self.schemas, self.provided_data['definitions'])]
|
||||
except:
|
||||
print("Errors finding Name Path (is there a 'project_schema' or 'project_unit' defined?")
|
||||
pass
|
||||
# print("\n(899) filename = ", self.filename)
|
||||
# if 'project_schema' in self.provided_data:
|
||||
# print("(899) project_schema: ", self.provided_data['project_schema'])
|
||||
# else:
|
||||
# print("(899) project schema NOT DEFINED")
|
||||
#
|
||||
# print("(904) self.namepath_segment = ", self.namepath_segment)
|
||||
|
||||
self.parser_chosen, self.parser_score = self._parse_filename()
|
||||
|
||||
# Was there a "project_schema" section?
|
||||
# - if not, do we fall back to a default?
|
||||
|
||||
# Was there a "project_unit" section?
|
||||
# - if not, can we construct what we need from project_root & folders?
|
||||
|
||||
# Is there a definitions section?
|
||||
# Do we provide defaults?
|
||||
|
||||
try:
|
||||
self.render_root = os.path.join(self.root,
|
||||
self.provided_data['definitions']['render_root'])
|
||||
except KeyError:
|
||||
self.render_root = os.path.join(self.root, 'Renders')
|
||||
|
||||
self.omit_ranks = {}
|
||||
try:
|
||||
for key, val in self.provided_data['definitions']['omit_ranks'].items():
|
||||
self.omit_ranks[key] = int(val)
|
||||
except KeyError:
|
||||
self.omit_ranks.update({
|
||||
'edit': 0,
|
||||
'render': 1,
|
||||
'filename': 1,
|
||||
'scene': 3})
|
||||
|
||||
# Data from Parsing the File Name
|
||||
try:
|
||||
self.parsers = [NameParsers[self.provided_data['definitions']['parser']](**self.schema['filenames'])]
|
||||
except (TypeError, KeyError, IndexError):
|
||||
self.parsers = [
|
||||
#Parser_ABX_Episode(),
|
||||
Parser_ABX_Schema(self.schemas, self.provided_data['definitions'])]
|
||||
|
||||
self.filetype = self.fields['filetype']
|
||||
self.role = self.fields['role']
|
||||
self.title = self.fields['title']
|
||||
self.comment = self.fields['comment']
|
||||
|
||||
# TODO:
|
||||
# We don't currently consider the information from the folder names,
|
||||
# though we could get some additional information this way
|
||||
|
||||
# Empty / default attributes
|
||||
self.name_contexts = []
|
||||
parser_chosen, parser_score = self._parse_filename()
|
||||
self.log(log_level.INFO, "Parsed with %s, score: %d" %
|
||||
(parser_chosen, parser_score))
|
||||
|
||||
|
||||
|
||||
# TODO:
|
||||
# We don't currently consider the information from the folder names,
|
||||
# though we could get some additional information this way
|
||||
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -919,7 +1105,18 @@ class FileContext(NameContext):
|
|||
s = s + str(self.code) + '(' + str(self.rank) + ')'
|
||||
s = s + ')'
|
||||
return s
|
||||
|
||||
|
||||
def log(self, level, msg):
|
||||
if type(level) is str:
|
||||
level = log_level.index(level)
|
||||
self.notes.append((level, msg))
|
||||
|
||||
def get_log_text(self, level=log_level.INFO):
|
||||
level = log_level.number(level)
|
||||
return '\n'.join([
|
||||
': '.join((log_level.name(note[0]), note[1]))
|
||||
for note in self.notes
|
||||
if log_level.number(note[0]) >= level])
|
||||
|
||||
def _parse_filename(self):
|
||||
"""
|
||||
|
@ -928,6 +1125,7 @@ class FileContext(NameContext):
|
|||
"""
|
||||
fields = {}
|
||||
best_score = 0.0
|
||||
best_parser_name = None
|
||||
for parser in self.parsers:
|
||||
score, fielddata = parser(self.filename, self.namepath)
|
||||
if score > best_score:
|
||||
|
@ -946,18 +1144,51 @@ class FileContext(NameContext):
|
|||
self.fields[key] = val
|
||||
|
||||
|
||||
def _collect_yaml_data(self):
|
||||
self.provided_data = RecursiveDict()
|
||||
kitcat_root, kitcat_data, abx_data = accumulate.get_project_data(self.filepath)
|
||||
self.root = kitcat_root
|
||||
self.provided_data.update(kitcat_data)
|
||||
path = os.path.abspath(os.path.normpath(self.filepath))
|
||||
root = os.path.abspath(self.root)
|
||||
self.folders = [os.path.basename(self.root)]
|
||||
self.folders.extend(os.path.normpath(os.path.relpath(path, root)).split(os.sep)[:-1])
|
||||
|
||||
self.abx_fields = abx_data
|
||||
# def _collect_yaml_data(self):
|
||||
|
||||
@property
|
||||
def filetype(self):
|
||||
if 'filetype' in self.fields:
|
||||
return self.fields['filetype']
|
||||
else:
|
||||
return ''
|
||||
|
||||
@filetype.setter
|
||||
def filetype(self, filetype):
|
||||
self.fields['filetype'] = filetype
|
||||
|
||||
@property
|
||||
def role(self):
|
||||
if 'role' in self.fields:
|
||||
return self.fields['role']
|
||||
else:
|
||||
return ''
|
||||
|
||||
@role.setter
|
||||
def role(self, role):
|
||||
self.fields['role'] = role
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
if 'title' in self.fields:
|
||||
return self.fields['title']
|
||||
else:
|
||||
return ''
|
||||
|
||||
@title.setter
|
||||
def title(self, title):
|
||||
self.fields['title'] = title
|
||||
|
||||
@property
|
||||
def comment(self):
|
||||
if 'comment' in self.fields:
|
||||
return self.fields['comment']
|
||||
else:
|
||||
return ''
|
||||
|
||||
@comment.setter
|
||||
def comment(self, comment):
|
||||
self.fields['comment'] = comment
|
||||
|
||||
@classmethod
|
||||
def deref_implications(cls, values, matchfields):
|
||||
|
@ -993,12 +1224,9 @@ class FileContext(NameContext):
|
|||
fields = {}
|
||||
fields.update(self.fields)
|
||||
|
||||
namepath_segment = []
|
||||
|
||||
ranks = [s.rank for s in self.schemas]
|
||||
|
||||
i_rank = len(self.namepath)
|
||||
|
||||
namepath_segment = []
|
||||
ranks = [s.rank for s in self.schemas]
|
||||
i_rank = len(self.namepath)
|
||||
old_rank = ranks[i_rank -1]
|
||||
|
||||
# The new rank will be the highest rank mentioned, or the
|
||||
|
|
|
@ -3,81 +3,201 @@
|
|||
Blender Python code to set parameters based on render profiles.
|
||||
"""
|
||||
|
||||
import bpy
|
||||
import bpy, bpy.types, bpy.utils, bpy.props
|
||||
|
||||
from . import std_lunatics_ink
|
||||
from abx import ink_paint
|
||||
|
||||
render_formats = {
|
||||
# VERY simplified and limited list of formats from Blender that we need:
|
||||
# <API 'format'>: (<bpy file format>, <filename extension>),
|
||||
'PNG': ('PNG', 'png'),
|
||||
'JPG': ('JPEG', 'jpg'),
|
||||
'EXR': ('OPEN_EXR_MULTILAYER', 'exr'),
|
||||
'AVI': ('AVI_JPEG', 'avi'),
|
||||
'MKV': ('FFMPEG', 'mkv')
|
||||
}
|
||||
from . import file_context
|
||||
|
||||
|
||||
def set_render_from_profile(scene, profile):
|
||||
if 'engine' in profile:
|
||||
if profile['engine'] == 'gl':
|
||||
pass
|
||||
elif profile['engine'] == 'bi':
|
||||
scene.render.engine = 'BLENDER_RENDER'
|
||||
elif profile['engine'] == 'cycles':
|
||||
scene.render.engine = 'CYCLES'
|
||||
elif profile['engine'] == 'bge':
|
||||
scene.render.engine = 'BLENDER_GAME'
|
||||
class RenderProfile(object):
|
||||
render_formats = {
|
||||
# VERY simplified and limited list of formats from Blender that we need:
|
||||
# <API 'format'>: (<bpy file format>, <filename extension>),
|
||||
'PNG': ('PNG', 'png'),
|
||||
'JPG': ('JPEG', 'jpg'),
|
||||
'EXR': ('OPEN_EXR_MULTILAYER', 'exr'),
|
||||
'AVI': ('AVI_JPEG', 'avi'),
|
||||
'MKV': ('FFMPEG', 'mkv')
|
||||
}
|
||||
|
||||
engines = {
|
||||
'bi': 'BLENDER_RENDER',
|
||||
'BLENDER_RENDER': 'BLENDER_RENDER',
|
||||
'BI': 'BLENDER_RENDER',
|
||||
|
||||
'cycles': 'CYCLES',
|
||||
'CYCLES': 'CYCLES',
|
||||
|
||||
'bge': 'BLENDER_GAME',
|
||||
'BLENDER_GAME': 'BLENDER_GAME',
|
||||
'BGE': 'BLENDER_GAME',
|
||||
|
||||
'gl': None,
|
||||
'GL': None
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, fields):
|
||||
|
||||
# Note: Settings w/ value *None* are left unaltered
|
||||
# That is, they remain whatever they were before
|
||||
# If a setting isn't included in the fields, then
|
||||
# the attribute will be *None*.
|
||||
|
||||
if 'engine' not in fields:
|
||||
fields['engine'] = None
|
||||
|
||||
if 'fps' in profile:
|
||||
scene.render.fps = profile['fps']
|
||||
|
||||
if 'fps_skip' in profile:
|
||||
scene.frame_step = profile['fps_skip']
|
||||
|
||||
if 'format' in profile:
|
||||
scene.render.image_settings.file_format = render_formats[profile['format']][0]
|
||||
|
||||
if 'freestyle' in profile:
|
||||
scene.render.use_freestyle = profile['freestyle']
|
||||
|
||||
if 'antialias' in profile:
|
||||
if profile['antialias']:
|
||||
scene.render.use_antialiasing = True
|
||||
if profile['antialias'] in (5,8,11,16):
|
||||
scene.render.antialiasing_samples = str(profile['antialias'])
|
||||
if fields['engine']=='gl':
|
||||
self.viewport_render = True
|
||||
self.engine = None
|
||||
else:
|
||||
scene.render.use_antialiasing = False
|
||||
|
||||
if 'motionblur' in profile:
|
||||
if profile['motionblur']:
|
||||
scene.render.use_motion_blur = True
|
||||
if type(profile['motionblur'])==int:
|
||||
scene.render.motion_blur_samples = profile['motionblur']
|
||||
self.viewport_render = False
|
||||
|
||||
if fields['engine'] in self.engines:
|
||||
self.engine = self.engines[fields['engine']]
|
||||
else:
|
||||
scene.render.use_motion_blur = False
|
||||
|
||||
# Use Lunatics naming scheme for render target:
|
||||
if 'framedigits' in profile:
|
||||
framedigits = profile['framedigits']
|
||||
else:
|
||||
framedigits = 5
|
||||
self.engine = None
|
||||
|
||||
# Parameters which are stored as-is, without modification:
|
||||
self.fps = 'fps' in fields and int(fields['fps']) or None
|
||||
self.fps_skip = 'fps_skip' in fields and int(fields['fps_skip']) or None
|
||||
self.fps_divisor = 'fps_divisor' in fields and float(fields['fps_divisor']) or None
|
||||
self.rendersize = 'rendersize' in fields and int(fields['rendersize']) or None
|
||||
self.compress = 'compress' in fields and int(fields['compress']) or None
|
||||
|
||||
if 'suffix' in profile:
|
||||
suffix = profile['suffix']
|
||||
else:
|
||||
suffix = ''
|
||||
self.format = 'format' in fields and str(fields['format']) or None
|
||||
|
||||
if 'format' in profile:
|
||||
rdr_fmt = render_formats[profile['format']][0]
|
||||
ext = render_formats[profile['format']][1]
|
||||
else:
|
||||
rdr_fmt = 'PNG'
|
||||
ext = 'png'
|
||||
|
||||
path = std_lunatics_ink.LunaticsShot(scene).render_path(
|
||||
suffix=suffix, framedigits=framedigits, ext=ext, rdr_fmt=rdr_fmt)
|
||||
|
||||
scene.render.filepath = path
|
||||
self.freestyle = 'freestyle' in fields and bool(fields['freestyle']) or None
|
||||
|
||||
self.antialiasing_samples = None
|
||||
self.use_antialiasing = None
|
||||
if 'antialias' in fields:
|
||||
if fields['antialias']:
|
||||
self.use_antialiasing = True
|
||||
if fields['antialias'] in (5,8,11,16):
|
||||
self.antialiasing_samples = str(fields['antialias'])
|
||||
else:
|
||||
self.use_antialiasing = False
|
||||
|
||||
self.use_motion_blur = None
|
||||
self.motion_blur_samples = None
|
||||
if 'motionblur' in fields:
|
||||
if fields['motionblur']:
|
||||
self.use_motion_blur = True
|
||||
if type(fields['motionblur'])==int:
|
||||
self.motion_blur_samples = int(fields['motionblur'])
|
||||
else:
|
||||
self.use_motion_blur = False
|
||||
|
||||
if 'framedigits' in fields:
|
||||
self.framedigits = fields['framedigits']
|
||||
else:
|
||||
self.framedigits = 5
|
||||
|
||||
if 'suffix' in fields:
|
||||
self.suffix = fields['suffix']
|
||||
else:
|
||||
self.suffix = ''
|
||||
|
||||
def apply(self, scene):
|
||||
"""
|
||||
Apply the profile settings to the given scene.
|
||||
"""
|
||||
if self.engine: scene.render.engine = self.engine
|
||||
if self.fps: scene.render.fps = self.fps
|
||||
if self.fps_skip: scene.frame_step = self.fps_skip
|
||||
if self.fps_divisor: scene.render.fps_base = self.fps_divisor
|
||||
if self.rendersize: scene.render.resolution_percentage = self.rendersize
|
||||
if self.compress: scene.render.image_settings.compression = self.compress
|
||||
|
||||
if self.format:
|
||||
scene.render.image_settings.file_format = self.render_formats[self.format][0]
|
||||
|
||||
if self.freestyle: scene.render.use_freestyle = self.freestyle
|
||||
if self.use_antialiasing:
|
||||
scene.render.use_antialiasing = self.use_antialiasing
|
||||
|
||||
if self.antialiasing_samples:
|
||||
scene.render.antialiasing_samples = self.antialiasing_samples
|
||||
if self.use_motion_blur:
|
||||
scene.render.use_motion_blur = self.use_motion_blur
|
||||
|
||||
if self.motion_blur_samples:
|
||||
scene.render.motion_blur_samples = self.motion_blur_samples
|
||||
|
||||
if self.format:
|
||||
# prefix = scene.name_context.render_path
|
||||
# prefix = BlendfileContext.name_contexts[scene.name_context].render_path
|
||||
prefix = 'path_to_render' # We actually need to get this from NameContext
|
||||
if self.suffix:
|
||||
scene.render.filepath = (prefix + '-' + self.suffix + '-' +
|
||||
'f'+('#'*self.framedigits) + '.' +
|
||||
self.render_formats[self.format][1])
|
||||
|
||||
|
||||
|
||||
# def set_render_from_profile(scene, profile):
|
||||
# if 'engine' in profile:
|
||||
# if profile['engine'] == 'gl':
|
||||
# pass
|
||||
# elif profile['engine'] == 'bi':
|
||||
# scene.render.engine = 'BLENDER_RENDER'
|
||||
# elif profile['engine'] == 'cycles':
|
||||
# scene.render.engine = 'CYCLES'
|
||||
# elif profile['engine'] == 'bge':
|
||||
# scene.render.engine = 'BLENDER_GAME'
|
||||
#
|
||||
# if 'fps' in profile:
|
||||
# scene.render.fps = profile['fps']
|
||||
#
|
||||
# if 'fps_skip' in profile:
|
||||
# scene.frame_step = profile['fps_skip']
|
||||
#
|
||||
# if 'format' in profile:
|
||||
# scene.render.image_settings.file_format = render_formats[profile['format']][0]
|
||||
#
|
||||
# if 'freestyle' in profile:
|
||||
# scene.render.use_freestyle = profile['freestyle']
|
||||
#
|
||||
# if 'antialias' in profile:
|
||||
# if profile['antialias']:
|
||||
# scene.render.use_antialiasing = True
|
||||
# if profile['antialias'] in (5,8,11,16):
|
||||
# scene.render.antialiasing_samples = str(profile['antialias'])
|
||||
# else:
|
||||
# scene.render.use_antialiasing = False
|
||||
#
|
||||
# if 'motionblur' in profile:
|
||||
# if profile['motionblur']:
|
||||
# scene.render.use_motion_blur = True
|
||||
# if type(profile['motionblur'])==int:
|
||||
# scene.render.motion_blur_samples = profile['motionblur']
|
||||
# else:
|
||||
# scene.render.use_motion_blur = False
|
||||
#
|
||||
# # Use Lunatics naming scheme for render target:
|
||||
# if 'framedigits' in profile:
|
||||
# framedigits = profile['framedigits']
|
||||
# else:
|
||||
# framedigits = 5
|
||||
#
|
||||
# if 'suffix' in profile:
|
||||
# suffix = profile['suffix']
|
||||
# else:
|
||||
# suffix = ''
|
||||
#
|
||||
# if 'format' in profile:
|
||||
# rdr_fmt = render_formats[profile['format']][0]
|
||||
# ext = render_formats[profile['format']][1]
|
||||
# else:
|
||||
# rdr_fmt = 'PNG'
|
||||
# ext = 'png'
|
||||
#
|
||||
# path = ink_paint.LunaticsShot(scene).render_path(
|
||||
# suffix=suffix, framedigits=framedigits, ext=ext, rdr_fmt=rdr_fmt)
|
||||
#
|
||||
# scene.render.filepath = path
|
||||
|
||||
|
Binary file not shown.
|
@ -0,0 +1,39 @@
|
|||
|
||||
bl_info = {
|
||||
"name": "ABX",
|
||||
"author": "Terry Hancock / Lunatics.TV Project / Anansi Spaceworks",
|
||||
"version": (0, 2, 6),
|
||||
"blender": (2, 79, 0),
|
||||
"location": "SpaceBar Search -> ABX",
|
||||
"description": "Anansi Studio Extensions for Blender",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Object",
|
||||
}
|
||||
|
||||
blender_present = False
|
||||
try:
|
||||
# These are protected so we can read the add-on metadata from my
|
||||
# management scripts, which run in the O/S standard Python 3
|
||||
import bpy, bpy.utils, bpy.types
|
||||
blender_present = True
|
||||
|
||||
except ImportError:
|
||||
print("Blender Add-On 'ABX' requires the Blender Python environment to run.")
|
||||
|
||||
if blender_present:
|
||||
from . import abx_ui
|
||||
|
||||
def register():
|
||||
abx_ui.register()
|
||||
#bpy.utils.register_module(__name__)
|
||||
|
||||
def unregister():
|
||||
abx_ui.unregister()
|
||||
#bpy.utils.unregister_module(__name__)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
# DEFAULT ABX SETTINGS
|
||||
---
|
||||
abx_default: True
|
||||
|
||||
project_unit: []
|
||||
|
||||
project_schema: []
|
||||
|
||||
definitions:
|
||||
filetypes:
|
||||
blend: "Blender File"
|
||||
kdenlive: "Kdenlive Video Editor File"
|
||||
mlt: "Kdenlive Video Mix Script"
|
||||
svg: "Scalable Vector Graphics (Inkscape)"
|
||||
kra: "Krita Graphic File"
|
||||
xcf: "Gimp Graphic File"
|
||||
png: "Portable Network Graphics (PNG) Image"
|
||||
jpg: "Joint Photographic Experts Group (JPEG) Image"
|
||||
aup: "Audacity Project"
|
||||
ardour: "Ardour Project"
|
||||