UI: Move Extensions repositories popover to header
[blender-addons-contrib.git] / render_time.py
blob91db3cf8d4cc59376f8a62347be04e4439be962f
1 # ***** BEGIN GPL LICENSE BLOCK *****
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # ***** END GPL LICENCE BLOCK *****
21 bl_info = {
22 "name": "Render Time Estimation",
23 "author": "Jason van Gumster (Fweeb)",
24 "version": (0, 5, 2),
25 "blender": (2, 80, 4),
26 "location": "UV/Image Editor > Properties > Image",
27 "description": "Estimates the time to complete rendering on animations",
28 "warning": "Does not work on OpenGL renders.",
29 "doc_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Render/Render_Time_Estimation",
30 "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
31 "category": "Render"}
34 import bpy, time
35 from bpy.app.handlers import persistent
36 from datetime import timedelta
37 import blf
40 timer = {"average": 0.0, "total": 0.0, "time_start": 0.0, "is_rendering": False, "hud": False}
42 def set_rendering(scene):
43 timer["is_rendering"] = True
45 @persistent
46 def unset_rendering(scene):
47 timer["is_rendering"] = False
49 @persistent
50 def start_timer(scene):
51 set_rendering(scene)
53 if scene.frame_current == scene.frame_start:
54 timer["average"] = 0.0
55 timer["total"] = 0.0
57 timer["time_start"] = time.time()
59 @persistent
60 def end_timer(scene):
61 render_time = time.time() - timer["time_start"]
62 timer["total"] += render_time
63 if scene.frame_current == scene.frame_start:
64 timer["average"] = render_time
65 else:
66 timer["average"] = (timer["average"] + render_time) / 2
68 print("Total render time: " + str(timedelta(seconds = timer["total"])))
69 print("Estimated completion: " + str(timedelta(seconds = (timer["average"] * (scene.frame_end - scene.frame_current)))))
72 # UI
74 def image_panel_rendertime(self, context):
75 scene = context.scene
76 layout = self.layout
78 if context.space_data.image is not None and context.space_data.image.type == 'RENDER_RESULT':
79 layout.label(text = "Total render time: " + str(timedelta(seconds = timer["total"])))
81 if timer["is_rendering"] and scene.frame_current != scene.frame_start:
82 layout.label(text = "Estimated completion: " + str(timedelta(seconds = (timer["average"] * (scene.frame_end - scene.frame_current)))))
84 def draw_callback_px(self, context):
85 scene = context.scene
87 font_id = 0 # XXX, need to find out how best to get this.
89 # draw some text
90 blf.position(font_id, 15, 30, 0)
91 blf.size(font_id, 18, 72)
92 blf.enable(font_id, blf.SHADOW)
93 blf.shadow(font_id, 5, 0.0, 0.0, 0.0, 1.0)
95 # Shorten / cut off milliseconds
96 time_total = str(timedelta(seconds = timer["total"]))
97 pos = time_total.rfind(".")
98 if pos != -1:
99 time_total = time_total[0:pos+3]
101 time_estimated = str(timedelta(seconds = (timer["average"] * (scene.frame_end - scene.frame_current))))
102 pos = time_estimated.rfind(".")
103 if pos != -1:
104 time_estimated = time_estimated[0:pos]
107 blf.draw(font_id, "Total render time " + time_total)
108 if timer["is_rendering"] and scene.frame_current != scene.frame_start:
109 blf.position(font_id, 15, 12, 0)
110 blf.draw(font_id, "Estimated completion: " + time_estimated)
112 # restore defaults
113 blf.disable(font_id, blf.SHADOW)
115 class RenderTimeHUD(bpy.types.Operator):
116 bl_idname = "view2d.rendertime_hud"
117 bl_label = "Display Render Times"
118 last_activity = 'NONE'
120 _handle = None
122 @staticmethod
123 def handle_add(self, context):
124 RenderTimeHUD._handle = bpy.types.SpaceImageEditor.draw_handler_add(
125 draw_callback_px, (self, context), 'WINDOW', 'POST_PIXEL')
127 @staticmethod
128 def handle_remove():
129 if RenderTimeHUD._handle is not None:
130 bpy.types.SpaceImageEditor.draw_handler_remove(RenderTimeHUD._handle, 'WINDOW')
131 RenderTimeHUD._handle = None
133 def modal(self, context, event):
134 if context.area:
135 context.area.tag_redraw()
137 #if event.type in {'ESC'}:
138 if timer["hud"] == False:
139 RenderTimeHUD.handle_remove()
140 return {'CANCELLED'}
142 return {'PASS_THROUGH'}
144 def invoke(self, context, event):
145 if context.area.type == 'IMAGE_EDITOR':
146 if timer["hud"] == False:
147 # Add the region OpenGL drawing callback
148 RenderTimeHUD.handle_add(self, context)
149 timer["hud"] = True
151 context.window_manager.modal_handler_add(self)
152 return {'RUNNING_MODAL'}
153 else:
154 timer["hud"] = False
155 return {'CANCELLED'}
156 else:
157 self.report({'WARNING'}, "UV/Image Editor not found, cannot run operator")
158 return {'CANCELLED'}
160 def display_hud(self, context):
161 layout = self.layout
162 text = RenderTimeHUD.bl_label if RenderTimeHUD._handle is None else "Hide Render Times"
163 layout.operator("view2d.rendertime_hud", text=text)
165 # Registration
167 def register():
168 bpy.app.handlers.render_complete.append(unset_rendering)
169 bpy.app.handlers.render_cancel.append(unset_rendering)
170 bpy.app.handlers.render_pre.append(start_timer)
171 bpy.app.handlers.render_post.append(end_timer)
172 bpy.types.IMAGE_PT_image_properties.append(image_panel_rendertime)
173 bpy.utils.register_class(RenderTimeHUD)
174 bpy.types.IMAGE_HT_header.append(display_hud)
176 # Keymapping XXX TODO - This doesn't work for some reason
177 #kc = bpy.context.window_manager.keyconfigs.addon
178 #km = kc.keymaps.new(name = "View 2D", space_type = 'IMAGE_EDITOR')
179 #kmi = km.keymap_items.new("view2d.rendertime_hud", 'E', 'PRESS')
180 #kmi.active = True
182 def unregister():
183 RenderTimeHUD.handle_remove()
185 #kc = bpy.context.window_manager.keyconfigs.addon
186 #km = kc.keymaps["View 2D"]
187 #km.keymap_items.remove(km.keymap_items["view2d.rendertime_hud"])
189 bpy.types.IMAGE_HT_header.remove(display_hud)
190 bpy.utils.unregister_class(RenderTimeHUD)
191 bpy.app.handlers.render_pre.remove(start_timer)
192 bpy.app.handlers.render_post.remove(end_timer)
193 bpy.app.handlers.render_cancel.remove(unset_rendering)
194 bpy.app.handlers.render_complete.remove(unset_rendering)
195 bpy.types.IMAGE_PT_image_properties.remove(image_panel_rendertime)
197 if __name__ == '__main__':
198 register()