Newer
Older
Pablo Vazquez
committed
# ##### BEGIN GPL LICENSE BLOCK #####
#
# 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.
#
# ##### END GPL LICENSE BLOCK #####
bl_info = {
"name": "Amaranth Toolset",
"author": "Pablo Vazquez, Bassam Kurdali, Sergey Sharybin, Lukas Tönne",
"blender": (2, 70),
"location": "Everywhere!",
Pablo Vazquez
committed
"description": "A collection of tools and settings to improve productivity",
"warning": "",
"wiki_url": "http://pablovazquez.org/amaranth",
"tracker_url": "",
"category": "Scene"}
import bpy
from bpy.types import Operator, AddonPreferences, Panel, Menu
from bpy.props import (BoolProperty, EnumProperty,
FloatProperty, FloatVectorProperty,
IntProperty, StringProperty)
Pablo Vazquez
committed
from mathutils import Vector
from bpy.app.handlers import persistent
from bl_operators.presets import AddPresetBase
Pablo Vazquez
committed
# Addon wide, we need to know if cycles is available
global cycles_exists
cycles_exists = 'cycles' in dir(bpy.types.Scene)
Pablo Vazquez
committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# Preferences
class AmaranthToolsetPreferences(AddonPreferences):
bl_idname = __name__
use_frame_current = BoolProperty(
name="Current Frame Slider",
description="Set the current frame from the Specials menu in the 3D View",
default=True,
)
use_file_save_reload = BoolProperty(
name="Save & Reload File",
description="File menu > Save & Reload, or Ctrl + Shift + W",
default=True,
)
use_scene_refresh = BoolProperty(
name="Refresh Scene",
description="Specials Menu [W], or hit F5",
default=True,
)
use_timeline_extra_info = BoolProperty(
name="Timeline Extra Info",
description="Timeline Header",
default=True,
)
use_image_node_display = BoolProperty(
name="Active Image Node in Editor",
description="Display active node image in image editor",
default=True,
)
use_scene_stats = BoolProperty(
name="Extra Scene Statistics",
description="Display extra scene statistics in Info editor's header",
default=True,
)
frames_jump = IntProperty(
name="Frames",
description="Number of frames to jump forward/backward",
default=10,
min=1)
use_layers_for_render = BoolProperty(
name="Current Layers for Render",
description="Save the layers that should be enabled for render",
default=True,
)
Pablo Vazquez
committed
def draw(self, context):
layout = self.layout
layout.label(
text="Here you can enable or disable specific tools, "
"in case they interfere with others or are just plain annoying")
split = layout.split(percentage=0.25)
col = split.column()
sub = col.column(align=True)
sub.label(text="3D View", icon="VIEW3D")
sub.prop(self, "use_frame_current")
sub.prop(self, "use_scene_refresh")
sub.separator()
sub.label(text="General", icon="SCENE_DATA")
sub.prop(self, "use_file_save_reload")
sub.prop(self, "use_timeline_extra_info")
sub.prop(self, "use_scene_stats")
Pablo Vazquez
committed
sub.separator()
CoDEmanX
committed
sub.label(text="Nodes Editor", icon="NODETREE")
Pablo Vazquez
committed
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
sub.prop(self, "use_image_node_display")
col = split.column()
sub = col.column(align=True)
sub.label(text="")
sub.label(
text="Set the current frame from the Specials menu in the 3D View [W]")
sub.label(
text="Refresh the current Scene. Hotkey: F5 or in Specials menu [W]")
sub.separator()
sub.label(text="") # General
sub.label(
text="Quickly save and reload the current file (no warning!). "
"File menu or Ctrl+Shift+W")
sub.label(
text="SMPTE Timecode and frames left/ahead on Timeline's header")
sub.label(
text="Display extra statistics for Scenes, Cameras, and Meshlights (Cycles)")
sub.separator()
sub.label(text="") # Nodes
sub.label(
text="When selecting an Image node, display it on the Image editor "
"(if any)")
# Properties
def init_properties():
scene = bpy.types.Scene
node = bpy.types.Node
nodes_compo = bpy.types.CompositorNodeTree
scene.use_unsimplify_render = BoolProperty(
Pablo Vazquez
committed
default=False,
name="Unsimplify Render",
description="Disable Simplify during render")
scene.simplify_status = BoolProperty(default=False)
Pablo Vazquez
committed
node.use_matching_indices = BoolProperty(
Pablo Vazquez
committed
default=True,
description="If disabled, display all available indices")
Pablo Vazquez
committed
("ALL", "All Types", "", 0),
("BLUR", "Blur", "", 1),
("BOKEHBLUR", "Bokeh Blur", "", 2),
("VECBLUR", "Vector Blur", "", 3),
("DEFOCUS", "Defocus", "", 4),
("R_LAYERS", "Render Layer", "", 5)
]
nodes_compo.types = EnumProperty(
items=nodes_compo_types, name = "Types")
Pablo Vazquez
committed
nodes_compo.toggle_mute = BoolProperty(default=False)
node.status = BoolProperty(default=False)
# Scene Debug
# Cycles Node Types
if cycles_exists:
cycles_shader_node_types = [
("BSDF_DIFFUSE", "Diffuse BSDF", "", 0),
("BSDF_GLOSSY", "Glossy BSDF", "", 1),
("BSDF_TRANSPARENT", "Transparent BSDF", "", 2),
("BSDF_REFRACTION", "Refraction BSDF", "", 3),
("BSDF_GLASS", "Glass BSDF", "", 4),
("BSDF_TRANSLUCENT", "Translucent BSDF", "", 5),
("BSDF_ANISOTROPIC", "Anisotropic BSDF", "", 6),
("BSDF_VELVET", "Velvet BSDF", "", 7),
("BSDF_TOON", "Toon BSDF", "", 8),
("SUBSURFACE_SCATTERING", "Subsurface Scattering", "", 9),
("EMISSION", "Emission", "", 10),
("BSDF_HAIR", "Hair BSDF", "", 11),
("BACKGROUND", "Background", "", 12),
("AMBIENT_OCCLUSION", "Ambient Occlusion", "", 13),
("HOLDOUT", "Holdout", "", 14),
("VOLUME_ABSORPTION", "Volume Absorption", "", 15),
("VOLUME_SCATTER", "Volume Scatter", "", 16)
]
scene.amaranth_cycles_node_types = EnumProperty(
items=cycles_shader_node_types, name = "Shader")
scene.amaranth_cycles_list_sampling = BoolProperty(
default=False,
name="Samples Per:")
bpy.types.CyclesRenderSettings.use_samples_final = BoolProperty(
name="Use Final Render Samples",
description="Use current shader samples as final render samples",
default=False)
scene.amaranth_lighterscorner_list_meshlights = BoolProperty(
name="List Meshlights",
description="Include light emitting meshes on the list")
scene.amaranth_debug_scene_list_missing_images = BoolProperty(
default=False,
name="List Missing Images",
description="Display a list of all the missing images")
bpy.types.ShaderNodeNormal.normal_vector = prop_normal_vector
bpy.types.CompositorNodeNormal.normal_vector = prop_normal_vector
bpy.types.Object.is_keyframe = is_keyframe
scene.amth_wire_toggle_scene_all = BoolProperty(
default=False,
name="All Scenes",
description="Toggle wire on objects in all scenes")
scene.amth_wire_toggle_is_selected = BoolProperty(
default=False,
name="Only Selected",
description="Only toggle wire on selected objects")
scene.amth_wire_toggle_edges_all = BoolProperty(
default=True,
name="All Edges",
description="Draw all edges")
scene.amth_wire_toggle_optimal = BoolProperty(
default=False,
name="Optimal Display",
description="Skip drawing/rendering of interior subdivided edges "
"on meshes with Subdivision Surface modifier")
Pablo Vazquez
committed
def clear_properties():
props = (
"use_unsimplify_render",
"simplify_status",
"use_matching_indices",
"use_simplify_nodes_vector",
"status",
"types",
"toggle_mute",
"amaranth_cycles_node_types",
"amaranth_lighterscorner_list_meshlights",
"amaranth_debug_scene_list_missing_images",
"amarath_cycles_list_sampling",
"normal_vector",
"use_samples_final",
'amth_wire_toggle_is_selected',
'amth_wire_toggle_scene_all',
"amth_wire_toggle_edges_all",
"amth_wire_toggle_optimal"
Pablo Vazquez
committed
)
Pablo Vazquez
committed
wm = bpy.context.window_manager
for p in props:
if p in wm:
del wm[p]
# Some settings are bound to be saved on a startup py file
def amaranth_text_startup(context):
amth_text_name = "AmaranthStartup.py"
amth_text_exists = False
global amth_text
try:
if bpy.data.texts:
for tx in bpy.data.texts:
if tx.name == amth_text_name:
amth_text_exists = True
amth_text = bpy.data.texts[amth_text_name]
break
else:
amth_text_exists = False
if not amth_text_exists:
bpy.ops.text.new()
amth_text = bpy.data.texts[-1]
amth_text.name = amth_text_name
amth_text.write("# Amaranth Startup Script\nimport bpy\n\n")
amth_text.use_module = True
return amth_text_exists
except AttributeError:
return None
# FUNCTION: Check if material has Emission (for select and stats)
def cycles_is_emission(context, ob):
is_emission = False
if ob.material_slots:
for ma in ob.material_slots:
if ma.material:
if ma.material.node_tree and ma.material.node_tree.nodes:
for no in ma.material.node_tree.nodes:
if no.type in {'EMISSION', 'GROUP'}:
for ou in no.outputs:
if ou.links:
if no.type == 'GROUP' and no.node_tree and no.node_tree.nodes:
for gno in no.node_tree.nodes:
if gno.type == 'EMISSION':
for gou in gno.outputs:
if ou.links and gou.links:
is_emission = True
elif no.type == 'EMISSION':
if ou.links:
is_emission = True
return is_emission
# 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
Pablo Vazquez
committed
# FEATURE: Refresh Scene!
Pablo Vazquez
committed
"""Refresh the current scene"""
bl_idname = "scene.refresh"
bl_label = "Refresh!"
Pablo Vazquez
committed
def execute(self, context):
preferences = context.user_preferences.addons[__name__].preferences
scene = context.scene
Pablo Vazquez
committed
# Changing the frame is usually the best way to go
scene.frame_current = scene.frame_current
self.report({"INFO"}, "Scene Refreshed!")
Pablo Vazquez
committed
return {'FINISHED'}
def button_refresh(self, context):
preferences = context.user_preferences.addons[__name__].preferences
if preferences.use_scene_refresh:
self.layout.separator()
self.layout.operator(
Pablo Vazquez
committed
text="Refresh!",
icon='FILE_REFRESH')
# // FEATURE: Refresh Scene!
# FEATURE: Save & Reload
def save_reload(self, context, path):
if path:
bpy.ops.wm.save_mainfile()
self.report({'INFO'}, "Saved & Reloaded")
bpy.ops.wm.open_mainfile("EXEC_DEFAULT", filepath=path)
else:
bpy.ops.wm.save_as_mainfile("INVOKE_AREA")
Pablo Vazquez
committed
"""Save and Reload the current blend file"""
bl_idname = "wm.save_reload"
bl_label = "Save & Reload"
def execute(self, context):
path = bpy.data.filepath
save_reload(self, context, path)
return {'FINISHED'}
def button_save_reload(self, context):
preferences = context.user_preferences.addons[__name__].preferences
if preferences.use_file_save_reload:
self.layout.separator()
self.layout.operator(
Pablo Vazquez
committed
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
text="Save & Reload",
icon='FILE_REFRESH')
# // FEATURE: Save & Reload
# FEATURE: Current Frame
def button_frame_current(self, context):
preferences = context.user_preferences.addons[__name__].preferences
scene = context.scene
if preferences.use_frame_current:
self.layout.separator()
self.layout.prop(
scene, "frame_current",
text="Set Current Frame")
# // FEATURE: Current Frame
# FEATURE: Timeline Time + Frames Left
def label_timeline_extra_info(self, context):
preferences = context.user_preferences.addons[__name__].preferences
layout = self.layout
scene = context.scene
if 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
Pablo Vazquez
committed
# 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
Pablo Vazquez
committed
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))
Pablo Vazquez
committed
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))
# // FEATURE: Timeline Time + Frames Left
# FEATURE: Directory Current Blend
class AMTH_FILE_OT_directory_current_blend(Operator):
Pablo Vazquez
committed
"""Go to the directory of the currently open blend file"""
bl_idname = "file.directory_current_blend"
bl_label = "Current Blend's Folder"
def execute(self, context):
bpy.ops.file.select_bookmark(dir='//')
return {'FINISHED'}
def button_directory_current_blend(self, context):
if bpy.data.filepath:
self.layout.operator(
Pablo Vazquez
committed
text="Current Blend's Folder",
icon='APPEND_BLEND')
# // FEATURE: Directory Current Blend
# FEATURE: Libraries panel on file browser
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'CHANNELS'
bl_label = "Libraries"
def draw(self, context):
layout = self.layout
libs = bpy.data.libraries
libslist = []
# Build the list of folders from libraries
for lib in libs:
directory_name = os.path.dirname(lib.filepath)
libslist.append(directory_name)
# Remove duplicates and sort by name
libslist = set(libslist)
libslist = sorted(libslist)
# Dra
Loading
Loading full blame...