Commit 32a6cb07 authored by CansecoGPC's avatar CansecoGPC
Browse files

Amaranth: Moved back to official add-ons repo

parent 018fdbdf
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
Amaranth
Using Blender every day, you get to change little things on it to speedup
your workflow. The problem is when you have to switch computers with
somebody else's Blender, it sucks.
That's the main reason behind Amaranth. I ported all sort of little changes
I find useful into this addon.
What is it about? Anything, whatever I think it can speedup workflow,
I'll try to add it. Enjoy <3
"""
import sys
# import amaranth's modules
# NOTE: avoid local imports whenever possible!
# Thanks to Christopher Crouzet for let me know about this.
# http://stackoverflow.com/questions/13392038/python-making-a-class-variable-static-even-when-a-module-is-imported-in-differe
from amaranth import prefs
from amaranth.modeling import symmetry_tools
from amaranth.scene import (
refresh,
save_reload,
current_blend,
stats,
goto_library,
debug,
material_remove_unassigned,
)
from amaranth.node_editor import (
id_panel,
display_image,
templates,
simplify_nodes,
node_stats,
normal_node,
switch_material,
node_shader_extra,
)
from amaranth.render import (
border_camera,
meshlight_add,
meshlight_select,
passepartout,
final_resolution,
samples_scene,
render_output_z,
)
from amaranth.animation import (
timeline_extra_info,
frame_current,
motion_paths,
jump_frames,
)
from amaranth.misc import (
color_management,
dupli_group_id,
toggle_wire,
sequencer_extra_info,
)
# register the addon + modules found in globals()
bl_info = {
"name": "Amaranth Toolset",
"author": "Pablo Vazquez, Bassam Kurdali, Sergey Sharybin, Lukas Tönne, Cesar Saez, CansecoGPC",
"version": (1, 0, 8),
"blender": (2, 81, 0),
"location": "Everywhere!",
"description": "A collection of tools and settings to improve productivity",
"warning": "",
"wiki_url": "https://pablovazquez.art/amaranth",
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
"category": "Interface",
}
def _call_globals(attr_name):
for m in globals().values():
if hasattr(m, attr_name):
getattr(m, attr_name)()
def _flush_modules(pkg_name):
pkg_name = pkg_name.lower()
for k in tuple(sys.modules.keys()):
if k.lower().startswith(pkg_name):
del sys.modules[k]
def register():
_call_globals("register")
def unregister():
_call_globals("unregister")
_flush_modules("amaranth") # reload amaranth
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
Current Frame Slider
Currently the only way to change the current frame is to have a Timeline
editor open, but sometimes you don't have one, or you're fullscreen.
This option adds the Current Frame slider to the Specials menu. Find it
hitting the W menu in Object mode, you can slide or click in the middle
of the button to set the frame manually.
"""
import bpy
def button_frame_current(self, context):
get_addon = "amaranth" in context.preferences.addons.keys()
if not get_addon:
return
scene = context.scene
if context.preferences.addons["amaranth"].preferences.use_frame_current:
self.layout.separator()
self.layout.prop(scene, "frame_current", text="Set Current Frame")
def register():
bpy.types.VIEW3D_MT_object_context_menu.append(button_frame_current)
bpy.types.VIEW3D_MT_pose_context_menu.append(button_frame_current)
def unregister():
bpy.types.VIEW3D_MT_object_context_menu.remove(button_frame_current)
bpy.types.VIEW3D_MT_pose_context_menu.remove(button_frame_current)
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
Jump X Frames on Shift Up/Down
When you hit Shift Up/Down, you'll jump 10 frames forward/backwards.
Sometimes is nice to tweak that value.
In the User Preferences, Editing tab, you'll find a "Frames to Jump"
slider where you can adjust how many frames you'd like to move
forwards/backwards.
Make sure you save your user settings if you want to use this value from
now on.
Find it on the User Preferences, Editing.
"""
import bpy
from bpy.types import Operator
from bpy.props import BoolProperty
KEYMAPS = list()
# FUNCTION: Check if object has keyframes for a specific frame
def is_keyframe(ob, frame):
if ob is not None and ob.animation_data is not None and ob.animation_data.action is not None:
for fcu in ob.animation_data.action.fcurves:
if frame in (p.co.x for p in fcu.keyframe_points):
return True
return False
# monkey path is_keyframe function
bpy.types.Object.is_keyframe = is_keyframe
# FEATURE: Jump to frame in-between next and previous keyframe
class AMTH_SCREEN_OT_keyframe_jump_inbetween(Operator):
"""Jump to half in-between keyframes"""
bl_idname = "screen.amth_keyframe_jump_inbetween"
bl_label = "Jump to Keyframe In-between"
backwards: BoolProperty()
def execute(self, context):
back = self.backwards
scene = context.scene
ob = bpy.context.object
frame_start = scene.frame_start
frame_end = scene.frame_end
if not context.scene.get("amth_keyframes_jump"):
context.scene["amth_keyframes_jump"] = list()
keyframes_list = context.scene["amth_keyframes_jump"]
for f in range(frame_start, frame_end):
if ob.is_keyframe(f):
keyframes_list = list(keyframes_list)
keyframes_list.append(f)
if keyframes_list:
keyframes_list_half = []
for i, item in enumerate(keyframes_list):
try:
next_item = keyframes_list[i + 1]
keyframes_list_half.append(int((item + next_item) / 2))
except:
pass
if len(keyframes_list_half) > 1:
if back:
v = (scene.frame_current == keyframes_list_half[::-1][-1],
scene.frame_current < keyframes_list_half[::-1][-1])
if any(v):
self.report({"INFO"}, "No keyframes behind")
else:
for i in keyframes_list_half[::-1]:
if scene.frame_current > i:
scene.frame_current = i
break
else:
v = (scene.frame_current == keyframes_list_half[-1],
scene.frame_current > keyframes_list_half[-1])
if any(v):
self.report({"INFO"}, "No keyframes ahead")
else:
for i in keyframes_list_half:
if scene.frame_current < i:
scene.frame_current = i
break
else:
self.report({"INFO"}, "Object has only 1 keyframe")
else:
self.report({"INFO"}, "Object has no keyframes")
return {"FINISHED"}
# FEATURE: Jump forward/backward every N frames
class AMTH_SCREEN_OT_frame_jump(Operator):
"""Jump a number of frames forward/backwards"""
bl_idname = "screen.amaranth_frame_jump"
bl_label = "Jump Frames"
forward: BoolProperty(default=True)
def execute(self, context):
scene = context.scene
get_addon = "amaranth" in context.preferences.addons.keys()
if not get_addon:
return {"CANCELLED"}
preferences = context.preferences.addons["amaranth"].preferences
if preferences.use_framerate:
framedelta = scene.render.fps
else:
framedelta = preferences.frames_jump
if self.forward:
scene.frame_current = scene.frame_current + framedelta
else:
scene.frame_current = scene.frame_current - framedelta
return {"FINISHED"}
def ui_userpreferences_edit(self, context):
get_addon = "amaranth" in context.preferences.addons.keys()
if not get_addon:
return
preferences = context.preferences.addons["amaranth"].preferences
col = self.layout.column()
split = col.split(factor=0.21)
split.prop(preferences, "frames_jump",
text="Frames to Jump")
def label(self, context):
get_addon = "amaranth" in context.preferences.addons.keys()
if not get_addon:
return
layout = self.layout
if context.preferences.addons["amaranth"].preferences.use_timeline_extra_info:
row = layout.row(align=True)
row.operator(AMTH_SCREEN_OT_keyframe_jump_inbetween.bl_idname,
icon="PREV_KEYFRAME", text="").backwards = True
row.operator(AMTH_SCREEN_OT_keyframe_jump_inbetween.bl_idname,
icon="NEXT_KEYFRAME", text="").backwards = False
def register():
bpy.utils.register_class(AMTH_SCREEN_OT_frame_jump)
bpy.utils.register_class(AMTH_SCREEN_OT_keyframe_jump_inbetween)
bpy.types.USERPREF_PT_animation_timeline.append(ui_userpreferences_edit)
bpy.types.USERPREF_PT_animation_timeline.append(label)
# register keyboard shortcuts
wm = bpy.context.window_manager
kc = wm.keyconfigs.addon
km = kc.keymaps.new(name="Frames")
kmi = km.keymap_items.new('screen.amth_keyframe_jump_inbetween', 'UP_ARROW', 'PRESS', shift=True, ctrl=True)
kmi.properties.backwards = False
KEYMAPS.append((km, kmi))
kmi = km.keymap_items.new('screen.amth_keyframe_jump_inbetween', 'DOWN_ARROW', 'PRESS', shift=True, ctrl=True)
kmi.properties.backwards = True
KEYMAPS.append((km, kmi))
kmi = km.keymap_items.new(
"screen.amaranth_frame_jump", "UP_ARROW", "PRESS", shift=True)
kmi.properties.forward = True
KEYMAPS.append((km, kmi))
kmi = km.keymap_items.new(
"screen.amaranth_frame_jump", "DOWN_ARROW", "PRESS", shift=True)
kmi.properties.forward = False
KEYMAPS.append((km, kmi))
def unregister():
bpy.utils.unregister_class(AMTH_SCREEN_OT_frame_jump)
bpy.utils.unregister_class(AMTH_SCREEN_OT_keyframe_jump_inbetween)
bpy.types.USERPREF_PT_animation_timeline.remove(ui_userpreferences_edit)
for km, kmi in KEYMAPS:
km.keymap_items.remove(kmi)
KEYMAPS.clear()
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
Bone Motion Paths:
Match Frame Range + Clear All Paths
* Clear All Paths:
Silly operator to loop through all bones and clear their paths, useful
when having hidden bones (othrewise you have to go through each one of
them and clear manually)
*Match Current Frame Range:
Set the current frame range as motion path range.
Both requests by Hjalti from Project Pampa
Thanks to Bassam Kurdali for helping finding out the weirdness behind
Motion Paths bpy.
Developed during Caminandes Open Movie Project
"""
import bpy
class AMTH_POSE_OT_paths_clear_all(bpy.types.Operator):
"""Clear motion paths from all bones"""
bl_idname = "pose.paths_clear_all"
bl_label = "Clear All Motion Paths"
bl_options = {"UNDO"}
@classmethod
def poll(cls, context):
return context.mode == "POSE"
def execute(self, context):
# silly but works
for b in context.object.data.bones:
b.select = True
bpy.ops.pose.paths_clear()
b.select = False
return {"FINISHED"}
class AMTH_POSE_OT_paths_frame_match(bpy.types.Operator):
"""Match Start/End frame of scene to motion path range"""
bl_idname = "pose.paths_frame_match"
bl_label = "Match Frame Range"
bl_options = {"UNDO"}
def execute(self, context):
avs = context.object.pose.animation_visualization
scene = context.scene
if avs.motion_path.type == "RANGE":
if scene.use_preview_range:
avs.motion_path.frame_start = scene.frame_preview_start
avs.motion_path.frame_end = scene.frame_preview_end
else:
avs.motion_path.frame_start = scene.frame_start
avs.motion_path.frame_end = scene.frame_end
else:
if scene.use_preview_range:
avs.motion_path.frame_before = scene.frame_preview_start
avs.motion_path.frame_after = scene.frame_preview_end
else:
avs.motion_path.frame_before = scene.frame_start
avs.motion_path.frame_after = scene.frame_end
return {"FINISHED"}
def pose_motion_paths_ui(self, context):
layout = self.layout
scene = context.scene
avs = context.object.pose.animation_visualization
if context.active_pose_bone:
mpath = context.active_pose_bone.motion_path
layout.separator()
layout.label(text="Motion Paths Extras:")
split = layout.split()
col = split.column(align=True)
if context.selected_pose_bones:
if mpath:
sub = col.row(align=True)
sub.operator(
"pose.paths_update", text="Update Path", icon="BONE_DATA")
sub.operator("pose.paths_clear", text="", icon="X")
else:
col.operator(
"pose.paths_calculate",
text="Calculate Path",
icon="BONE_DATA")
else:
col.label(text="Select Bones First", icon="ERROR")
col = split.column(align=True)
col.operator(
AMTH_POSE_OT_paths_frame_match.bl_idname,
text="Set Preview Frame Range" if scene.use_preview_range else "Set Frame Range",
icon="PREVIEW_RANGE" if scene.use_preview_range else "TIME")
col = layout.column()
row = col.row(align=True)
if avs.motion_path.type == "RANGE":
row.prop(avs.motion_path, "frame_start", text="Start")
row.prop(avs.motion_path, "frame_end", text="End")
else:
row.prop(avs.motion_path, "frame_before", text="Before")
row.prop(avs.motion_path, "frame_after", text="After")
layout.separator()
layout.operator(AMTH_POSE_OT_paths_clear_all.bl_idname, icon="X")
def register():
bpy.utils.register_class(AMTH_POSE_OT_paths_clear_all)
bpy.utils.register_class(AMTH_POSE_OT_paths_frame_match)
bpy.types.DATA_PT_display.append(pose_motion_paths_ui)
def unregister():
bpy.utils.unregister_class(AMTH_POSE_OT_paths_clear_all)
bpy.utils.unregister_class(AMTH_POSE_OT_paths_frame_match)
bpy.types.DATA_PT_display.remove(pose_motion_paths_ui)
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
Timeline Extra Info
Display amount of frames left until Frame End, very handy especially when
rendering an animation or OpenGL preview.
Display current/end time on SMPTE. Find it on the Timeline header.
"""
import bpy
def label_timeline_extra_info(self, context):
get_addon = "amaranth" in context.preferences.addons.keys()
if not get_addon:
return
layout = self.layout
scene = context.scene
if context.preferences.addons["amaranth"].preferences.use_timeline_extra_info:
row = layout.row(align=True)
# Check for preview range
frame_start = scene.frame_preview_start if scene.use_preview_range else scene.frame_start
frame_end = scene.frame_preview_end if scene.use_preview_range else scene.frame_end
row.label(
text="%s / %s" %
(bpy.utils.smpte_from_frame(
scene.frame_current -
frame_start),
bpy.utils.smpte_from_frame(
frame_end -
frame_start)))
if (scene.frame_current > frame_end):
row.label(text="%s Frames Ahead" %
((frame_end - scene.frame_current) * -1))
elif (scene.frame_current == frame_start):
row.label(text="Start Frame (%s left)" %
(frame_end - scene.frame_current))
elif (scene.frame_current == frame_end):
row.label(text="%s End Frame" % scene.frame_current)
else:
row.label(text="%s Frames Left" %
(frame_end - scene.frame_current))
def register():
bpy.types.STATUSBAR_HT_header.append(label_timeline_extra_info)
def unregister():
bpy.types.STATUSBAR_HT_header.remove(label_timeline_extra_info)
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
Color Management Presets
Save your Color Management options as presets, for easy re-use.