studio_renderLayer.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. # THIS FILE IS A PART OF VCStudio
  2. # PYTHON 3
  3. import os
  4. import datetime
  5. import json
  6. from subprocess import *
  7. # GTK module ( Graphical interface
  8. import gi
  9. gi.require_version('Gtk', '3.0')
  10. from gi.repository import Gtk
  11. from gi.repository import GLib
  12. from gi.repository import Gdk
  13. import cairo
  14. # Own modules
  15. from settings import settings
  16. from settings import talk
  17. from settings import fileformats
  18. from settings import oscalls
  19. from project_manager import pm_project
  20. #UI modules
  21. from UI import UI_elements
  22. from UI import UI_color
  23. from UI import UI_math
  24. # Studio
  25. from studio import studio_dialogs
  26. from studio import analytics
  27. from studio import story
  28. # Network / Rendering
  29. from network import network_renders
  30. def save_settings(win, filename):
  31. ############################################################################
  32. # This function will save the render settings file.
  33. ############################################################################
  34. folder = filename[:filename.rfind("/")]+"/extra"
  35. savefile = folder+filename[filename.rfind("/"):]+".json"
  36. # First let's make sure that the extra folder exists.
  37. try:
  38. os.makedirs(win.project+folder)
  39. except:
  40. pass
  41. # Then let's write the file in there.
  42. with open(win.project+savefile, 'w') as fp:
  43. json.dump(win.renders[filename], fp, sort_keys=True, indent=4)
  44. def layer(win, call):
  45. ##########################################################################
  46. # This file will setup and manage rendering of shots. It's a bit complex
  47. # in function. I have 2 network scripts at the moment. And it might grow
  48. # beyond that.
  49. # See:
  50. # network/during_render.py
  51. # network/network_renders.py
  52. # This file is the UI part of the process. ( The main UI ) Some beats and
  53. # peaces will exists in various windows through out the program.
  54. ##########################################################################
  55. # Making the layer
  56. surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, win.current['w'],
  57. win.current['h'])
  58. layer = cairo.Context(surface)
  59. #text setting
  60. layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
  61. UI_color.set(layer, win, "dark_overdrop")
  62. layer.rectangle(
  63. 0,
  64. 0,
  65. win.current["w"],
  66. win.current["h"],
  67. )
  68. layer.fill()
  69. UI_color.set(layer, win, "node_background")
  70. UI_elements.roundrect(layer, win,
  71. win.current["w"]/2-250,
  72. 100,
  73. 500,
  74. win.current["h"]-200,
  75. 10)
  76. # Documentation entry
  77. def do():
  78. def after(win, var):
  79. pass
  80. studio_dialogs.help(win, "help", after, SEARCH=talk.text("documentation_render"))
  81. UI_elements.roundrect(layer, win,
  82. win.current["w"]/2-250,
  83. win.current["h"]-140,
  84. 40,
  85. 40,
  86. 10,
  87. do,
  88. "question")
  89. is_rendering = False # This will determen whether
  90. for render in win.renders:
  91. if win.renders[render]["rendering"]:
  92. is_rendering = True
  93. if not is_rendering:
  94. # Render button
  95. def do():
  96. # This here will launch a script that will be on it's on from now
  97. # on. See:
  98. # network/during_render.py
  99. try:
  100. with open(win.project+"/render_runtime.json") as json_file:
  101. runtime = json.load(json_file)
  102. except:
  103. runtime = {}
  104. runtime["to_render"] = True
  105. with open(win.project+"/render_runtime.json", 'w') as fp:
  106. json.dump(runtime, fp, indent=4)
  107. Popen(["python3", "network/during_render.py", win.project, oscalls.get_current_blender(win)])
  108. UI_elements.roundrect(layer, win,
  109. win.current["w"]/2-20,
  110. win.current["h"]-140,
  111. 40,
  112. 40,
  113. 10,
  114. button=do,
  115. icon="right")
  116. else:
  117. # Stop Render button
  118. def do():
  119. network_renders.stop_render(win)
  120. UI_elements.roundrect(layer, win,
  121. win.current["w"]/2-20,
  122. win.current["h"]-140,
  123. 40,
  124. 40,
  125. 10,
  126. button=do,
  127. icon="stop")
  128. # Exit button
  129. def do():
  130. win.current["calls"][call]["var"] = False
  131. UI_elements.roundrect(layer, win,
  132. win.current["w"]/2+210,
  133. win.current["h"]-140,
  134. 40,
  135. 40,
  136. 10,
  137. button=do,
  138. icon="cancel",
  139. tip=talk.text("cancel"),
  140. url="render")
  141. x = win.current["w"]/2-250 + 10
  142. y = 100 + 10
  143. width = 500 - 20
  144. height = win.current["h"]-200 - 20
  145. UI_elements.roundrect(layer, win,
  146. x,
  147. y,
  148. width,
  149. height-60,
  150. 10,
  151. fill=False)
  152. layer.clip()
  153. clip = [
  154. x,
  155. y,
  156. width,
  157. height-60]
  158. # Let's get the filename of the current file that we want to setup.
  159. filename = win.current["renders_window"]["filename"]
  160. # So this window could be accessed from both main window and from the script.
  161. # One is to see where each render is. And ther other is to configure and add
  162. # renders to the list.
  163. if filename:
  164. # Basically if any file is inputted. It means that it's to configure.
  165. # but sometimes. ( I'm tyring to see myself using it ) the user will
  166. # click on the render button to just access the render. And to hell with
  167. # it. Let's make the filename variable the selection of the file.
  168. if filename not in win.renders:
  169. # So on the initialization we want to do a couple of things.
  170. # First of which will be to get render settings data from the
  171. # blend file.
  172. # I think a quick bpy script could do.
  173. # See:
  174. # studio/bpy_get_render_settings.py
  175. blenderpath = oscalls.get_current_blender(win)
  176. blend = win.project+filename
  177. checkframes = Popen([blenderpath, "-b", blend , "-P",
  178. os.getcwd()+"/studio/bpy_get_render_settings.py"],stdout=PIPE, universal_newlines=True)
  179. checkframes.wait()
  180. checkstring = checkframes.stdout.read()
  181. # We are going to need the following options.
  182. start_frame = 0
  183. end_frame = 250
  184. image_format = "PNG"
  185. save_folder = "storyboard"
  186. for line in checkstring.split("\n"):
  187. if line.startswith("Start_frame"):
  188. try:
  189. start_frame = int(line[line.find(":")+1:])
  190. except:
  191. pass
  192. if line.startswith("End_frame"):
  193. try:
  194. end_frame = int(line[line.find(":")+1:])
  195. except:
  196. pass
  197. # Now since we've got the data. Let's write it to the dictionary first.
  198. win.renders[filename] = {
  199. "start_frame" :start_frame , # The frame we want to start on
  200. "end_frame" :end_frame , # The frame we want to end on
  201. "image_format" :image_format, # What format to save the images
  202. "save_folder" :save_folder , # Into what folder to save images
  203. "clean_folder" :False , # Whether to delete current frames before rendering
  204. "current_frame":0 , # What is current frame rendering
  205. "rendering" :False , # Whether it's currently rendering
  206. "analytics" :{} # Times of each frame
  207. }
  208. # Now in order not to loose the data immediatly. We are going to need
  209. # to add the filename into a special file.
  210. s = open(win.project+"/set/active_renders.data", "a")
  211. s.write(filename+"\n")
  212. s.close()
  213. # Also we want to make a little json file in the extra folder of
  214. # the shot. This will contain our settings. And the file will be
  215. # read by the renderer script while it's running. It has to be on
  216. # it's own. So it's good to have extendable files.
  217. save_settings(win, filename)
  218. # Now let's get to the actuall UI of the stuff. Basically I want it to
  219. # always give us a list of the currently set renders. And one of them
  220. # might be selected and expendet to see they settings / current data.
  221. # Setting up the scroll
  222. if "render" not in win.scroll:
  223. win.scroll["render"] = 0
  224. current_Y = 0
  225. # So let's do this.
  226. is_rendering = False # This will determen whether
  227. # Before we dive into settings and graphs. Let's make a deletion
  228. if 65535 in win.current["keys"] and not win.renders[win.current["renders_window"]["filename"]]["rendering"]:
  229. try:
  230. del win.renders[win.current["renders_window"]["filename"]]
  231. active_renders = open(win.project+"/set/active_renders.data")
  232. active_renders = active_renders.read()
  233. active_renders = active_renders.split("\n")
  234. s = open(win.project+"/set/active_renders.data", "w")
  235. for i in active_renders:
  236. if i != win.current["renders_window"]["filename"] and i:
  237. s.write(i+"\n")
  238. s.close()
  239. except:
  240. pass
  241. win.current["renders_window"]["filename"] = ""
  242. win.current["keys"] = []
  243. for render in win.renders:
  244. # Let's get a shot name for each render.
  245. shot = render[:render.rfind("/")].replace("/rnd", "")
  246. blend = render[render.rfind("/"):]
  247. tip = (shot+blend).replace("/", "", 1).replace("/", " | ")
  248. if win.renders[render]["rendering"]:
  249. tip = win.renders[render]["rendering"]
  250. def do():
  251. win.current["renders_window"]["filename"] = render
  252. UI_elements.roundrect(layer, win,
  253. x,
  254. y+current_Y+win.scroll["render"],
  255. width,
  256. 80,
  257. 10,
  258. button=do,
  259. tip=tip,
  260. clip=clip)
  261. # I think the render logo could be cool.
  262. UI_elements.image(layer, win,
  263. "settings/themes/"+win.settings["Theme"]+"/icons/render.png",
  264. x+5, y+current_Y+win.scroll["render"]+5, 40, 40)
  265. # And the name of the shot
  266. UI_color.set(layer, win, "text_normal")
  267. layer.set_font_size(20)
  268. layer.move_to(x+60,
  269. y+current_Y + win.scroll["render"]+30)
  270. layer.show_text((shot+blend).replace("/", "", 1).replace("/", " | "))
  271. # And let's draw the fraction
  272. fraction = (win.renders[render]["current_frame"] - win.renders[render]["start_frame"])\
  273. / (win.renders[render]["end_frame"] - win.renders[render]["start_frame"])
  274. fraction = min(1, fraction)
  275. UI_color.set(layer, win, "progress_background")
  276. UI_elements.roundrect(layer, win,
  277. x+20,
  278. y+current_Y + win.scroll["render"]+55,
  279. width-40,
  280. 0,
  281. 5)
  282. UI_color.set(layer, win, "progress_active")
  283. UI_elements.roundrect(layer, win,
  284. x+20,
  285. y+current_Y + win.scroll["render"]+55,
  286. (width-40)*fraction,
  287. 0,
  288. 5)
  289. # Now selection. When you click on one you expend it. And you can see
  290. # what settings are inside.
  291. if win.current["renders_window"]["filename"] == render:
  292. UI_color.set(layer, win, "progress_background")
  293. UI_elements.roundrect(layer, win,
  294. x,
  295. y+current_Y+win.scroll["render"],
  296. width,
  297. 80,
  298. 10,
  299. fill=False)
  300. layer.stroke()
  301. current_Y = current_Y + 90
  302. # We are going to have 2 differnt UI's for those who are rendering
  303. # and those who are not rendering.
  304. if not win.renders[render]["rendering"]:
  305. # We need to choose the folder of where the given render will be done.
  306. # For the user tho I don't think nessesary to understand that it's a
  307. # folder nessesary. They will see 4 circles. 4 render qualities. And
  308. # will decide stuff based on that.
  309. fouricons = [ "storyboard", "opengl", "test_rnd", "rendered"]
  310. for num, f in enumerate(fouricons):
  311. if f == win.renders[render]["save_folder"]:
  312. UI_color.set(layer, win, "progress_time")
  313. UI_elements.roundrect(layer, win,
  314. x+20+(40*num),
  315. y+current_Y + win.scroll["render"],
  316. 40,
  317. 40,
  318. 10)
  319. def do():
  320. win.renders[render]["save_folder"] = f
  321. save_settings(win, render)
  322. UI_elements.roundrect(layer, win,
  323. x+20+(40*num),
  324. y+current_Y + win.scroll["render"],
  325. 40,
  326. 40,
  327. 10,
  328. button=do,
  329. icon=f,
  330. tip=f)
  331. # Here also I want to have a little clean icon. This will make sure
  332. # to clean the current frames that are currently inside the folder.
  333. # I know it's slightly counter intuitive compared to the rest of
  334. # the program in that it's better not to give the user the ability
  335. # to delete any actuall files. But in this case it makes a bit
  336. # sense. Since for the user rendering again is like replacing the
  337. # previous files with new ones. And the algorythm always renders
  338. # from the last frame in the folder. So it never deletes anything
  339. # by defaul. So I guess a button to clean frames could be a good
  340. # thing.
  341. if win.renders[render]["clean_folder"]:
  342. UI_color.set(layer, win, "progress_time")
  343. UI_elements.roundrect(layer, win,
  344. x+width-40,
  345. y+current_Y + win.scroll["render"],
  346. 40,
  347. 40,
  348. 10)
  349. def do():
  350. win.renders[render]["clean_folder"] = not win.renders[render]["clean_folder"]
  351. save_settings(win, render)
  352. UI_elements.roundrect(layer, win,
  353. x+width-40,
  354. y+current_Y + win.scroll["render"],
  355. 40,
  356. 40,
  357. 10,
  358. button=do,
  359. icon="clean",
  360. tip=talk.text("clean_render_folder"))
  361. current_Y = current_Y + 50
  362. # Now let's put the settings them selves.
  363. # First thing is we need start and end frames. And we also need it
  364. # somehow readable for the user.
  365. # I will probably need this.
  366. def is_number(string):
  367. try:
  368. int(string)
  369. return True
  370. except:
  371. return False
  372. # START FRAME
  373. UI_elements.text(layer, win, render+"start_frame",
  374. x+10,
  375. y+current_Y+win.scroll["render"],
  376. 100,
  377. 40,
  378. set_text=str(win.renders[render]["start_frame"]),
  379. tip=talk.text("rendering_start_frame"))
  380. if win.text[render+"start_frame"]["text"] != str(win.renders[render]["start_frame"])\
  381. and is_number(win.text[render+"start_frame"]["text"]):
  382. def do():
  383. win.renders[render]["start_frame"] = int(win.text[render+"start_frame"]["text"])
  384. save_settings(win, render)
  385. UI_elements.roundrect(layer, win,
  386. x+70,
  387. y+current_Y+win.scroll["render"],
  388. 40,
  389. 40,
  390. 10,
  391. button=do,
  392. icon="ok",
  393. tip=talk.text("checked"))
  394. # FILE FORMATS
  395. # I will not add any video files since the algoryhm will require
  396. # actuall frames to be stored as separate files. This will insure
  397. # that ALL frames were rendered. And in case of crash the algorythm
  398. # will pick up from a previous frame in a folder. With video is not
  399. # only impossible. But in case of a crash with video all the previous
  400. # frames will be lost.
  401. # What I want to do is to ejucate the user on the Open Formats.
  402. # You know using OGG video instead of MP4 and stuff like that.
  403. # For images there are the same types of Open Formats. The point
  404. # is that these formats could be made and played using entirelly
  405. # free software.
  406. # I will let selection of formats that are not in the list but I
  407. # will mark them as non-recommended. I will do it like so.
  408. # [ <start frame> ] [ PNG ] [ <png frame>
  409. # V PNG ?
  410. # V JPEG ?
  411. # V EXR ?
  412. # X HDR ?
  413. # And so on and forth. You can see that HDR is marked with an X
  414. # it will be a button linking to the :
  415. linfo = "http://www.linfo.org/free_file_format.html"
  416. # so the user could read a full document describing desisions
  417. # about the formats.
  418. formats = {
  419. "PNG" : [True, "Image PNG", "https://en.wikipedia.org/wiki/Portable_Network_Graphics"],
  420. "JPEG": [True, "Image JPEG", "https://en.wikipedia.org/wiki/JPEG"],
  421. "EXR" : [True, "Open EXR", "https://en.wikipedia.org/wiki/OpenEXR"],
  422. "HDR" : [False,"Radiance HDR", "https://en.wikipedia.org/wiki/RGBE_image_format"],
  423. "BMP" : [False,"Microsoft BMP", "https://en.wikipedia.org/wiki/BMP_file_format"],
  424. "TGA" : [False,"Truevision TGA", "https://en.wikipedia.org/wiki/Truevision_TGA"],
  425. "TIFF": [False,"Tiff", "https://en.wikipedia.org/wiki/Tagged_Image_File_Format"]
  426. }
  427. if "selecting_render_file_format" not in win.current:
  428. win.current["selecting_render_file_format"] = False
  429. def do():
  430. win.current["selecting_render_file_format"] = not win.current["selecting_render_file_format"]
  431. if win.current["selecting_render_file_format"]:
  432. win.scroll["render"] = win.scroll["render"]-50*len(formats)
  433. win.current["LMB"] = False
  434. win.previous["LMB"] = False
  435. UI_elements.roundrect(layer, win,
  436. x+120,
  437. y+current_Y + win.scroll["render"],
  438. 235,
  439. 40,
  440. 10,
  441. button=do,
  442. tip=talk.text("rendering_file_format"))
  443. currentformat = win.renders[render]["image_format"]
  444. if not win.current["selecting_render_file_format"]:
  445. UI_color.set(layer, win, "text_normal")
  446. layer.set_font_size(20)
  447. layer.move_to(win.current['w']/2-len(formats[currentformat][1])*6,
  448. y+current_Y + win.scroll["render"]+30)
  449. layer.show_text(formats[currentformat][1])
  450. # END FRAME
  451. UI_elements.text(layer, win, render+"end_frame",
  452. x+365,
  453. y+current_Y+win.scroll["render"],
  454. 100,
  455. 40,
  456. set_text=str(win.renders[render]["end_frame"]),
  457. tip=talk.text("rendering_end_frame"))
  458. if win.text[render+"end_frame"]["text"] != str(win.renders[render]["end_frame"])\
  459. and is_number(win.text[render+"end_frame"]["text"]):
  460. def do():
  461. win.renders[render]["end_frame"] = int(win.text[render+"end_frame"]["text"])
  462. save_settings(win, render)
  463. UI_elements.roundrect(layer, win,
  464. x+215+210,
  465. y+current_Y+win.scroll["render"],
  466. 40,
  467. 40,
  468. 10,
  469. button=do,
  470. icon="ok",
  471. tip=talk.text("checked"))
  472. current_Y = current_Y + 50
  473. if win.current["selecting_render_file_format"]:
  474. for num, f in enumerate(formats):
  475. if f == win.renders[render]["image_format"]:
  476. UI_color.set(layer, win, "progress_time")
  477. UI_elements.roundrect(layer, win,
  478. x+120,
  479. y+current_Y + win.scroll["render"],
  480. 235,
  481. 40,
  482. 10)
  483. def do():
  484. win.renders[render]["image_format"] = f
  485. save_settings(win, render)
  486. win.current["selecting_render_file_format"] = False
  487. UI_elements.roundrect(layer, win,
  488. x+120,
  489. y+current_Y + win.scroll["render"],
  490. 235,
  491. 40,
  492. 10,
  493. button=do)
  494. UI_color.set(layer, win, "text_normal")
  495. layer.set_font_size(20)
  496. layer.move_to(win.current['w']/2-len(formats[f][1])*6,
  497. y+current_Y + win.scroll["render"]+30)
  498. layer.show_text(formats[f][1])
  499. # RECCOMENDATION
  500. if formats[f][0]:
  501. rec = talk.text("recommended_yes")
  502. ic = "ok"
  503. else:
  504. rec = talk.text("recommended_not")
  505. ic = "cancel"
  506. def do():
  507. os.system("xdg-open "+linfo)
  508. UI_elements.roundrect(layer, win,
  509. x+10,
  510. y+current_Y + win.scroll["render"],
  511. 40,
  512. 40,
  513. 10,
  514. button=do,
  515. icon=ic,
  516. tip=rec)
  517. # WIKIPEDIA ABOUT THE FORMAT
  518. def do():
  519. os.system("xdg-open "+formats[f][-1])
  520. UI_elements.roundrect(layer, win,
  521. x+430,
  522. y+current_Y + win.scroll["render"],
  523. 40,
  524. 40,
  525. 10,
  526. button=do,
  527. icon="question",
  528. tip="Wikipedia")
  529. current_Y = current_Y + 50
  530. else:
  531. # And here comes the UI of when it's during RENDERING
  532. # First thing will be to draw a little graph. This will show current
  533. # frame and analytics data about render times.
  534. UI_color.set(layer, win, "dark_overdrop")
  535. layer.rectangle(
  536. x+5,
  537. y+current_Y+win.scroll["render"],
  538. width-10,
  539. 100)
  540. layer.fill()
  541. for frame in range(win.renders[render]["start_frame"], win.renders[render]["end_frame"]+1):
  542. numofis = win.renders[render]["end_frame"] - win.renders[render]["start_frame"]
  543. if frame == win.renders[render]["current_frame"]:
  544. UI_color.set(layer, win, "progress_time")
  545. layer.rectangle(
  546. x+5+(width-10)/numofis*(frame-1),
  547. y+current_Y+win.scroll["render"],
  548. (width-10)/numofis,
  549. 100)
  550. layer.fill()
  551. # Now I want to be able to interact with the graph. For this I want to
  552. # add a little mouse sensitive region. That will give me data about the
  553. # current frame. In a tooltip?
  554. if int(win.current["mx"]) in range(int(x+5+(width-10)/numofis*frame),int(x+5+(width-10)/numofis*frame+(width-10)/numofis))\
  555. and int(win.current["my"]) in range(int(y+current_Y+win.scroll["render"]), int(y+current_Y+win.scroll["render"]+100)):
  556. UI_color.set(layer, win, "progress_background")
  557. layer.move_to(x+5+(width-10)/numofis*(frame-0.5),
  558. y+current_Y+win.scroll["render"]
  559. )
  560. layer.line_to(
  561. x+5+(width-10)/numofis*(frame-0.5),
  562. y+current_Y+win.scroll["render"]+100
  563. )
  564. layer.stroke()
  565. if win.renders[render]["save_folder"] in win.renders[render]["analytics"]:
  566. if str(frame) in win.renders[render]["analytics"][win.renders[render]["save_folder"]]:
  567. value = win.renders[render]["analytics"][win.renders[render]["save_folder"]][str(frame)]
  568. UI_elements.tooltip(win, UI_math.timestring(value/1000000))
  569. # Now let's draw a graph. I love graphs. They are cool AF. First of all tho
  570. # we need to know the maximum value. Because who know how long was the render
  571. mx = 0
  572. allvalues = []
  573. if win.renders[render]["save_folder"] in win.renders[render]["analytics"]:
  574. for v in win.renders[render]["analytics"][win.renders[render]["save_folder"]]:
  575. mx = max(win.renders[render]["analytics"][win.renders[render]["save_folder"]][v], mx)
  576. allvalues.append(win.renders[render]["analytics"][win.renders[render]["save_folder"]][v])
  577. UI_color.set(layer, win, "progress_background")
  578. layer.move_to(x+5, y+current_Y+win.scroll["render"]+100)
  579. for frame in range(win.renders[render]["start_frame"], win.renders[render]["end_frame"]+1):
  580. numofis = win.renders[render]["end_frame"] - win.renders[render]["start_frame"]
  581. if win.renders[render]["save_folder"] in win.renders[render]["analytics"]:
  582. if str(frame) in win.renders[render]["analytics"][win.renders[render]["save_folder"]]:
  583. value = win.renders[render]["analytics"][win.renders[render]["save_folder"]][str(frame)]
  584. layer.line_to(
  585. x+5+(width-10)/numofis*(frame-0.5),
  586. (y+current_Y+win.scroll["render"]+100)-(100/mx*value)
  587. )
  588. layer.stroke()
  589. current_Y = current_Y + 110
  590. # Now let's put out some data in the text format. For the user to
  591. # know stuff he or she might want to know.
  592. # AVARAGE TIME
  593. avarage = 0
  594. try:
  595. avarage = sum(allvalues) / len(allvalues)
  596. except:
  597. pass
  598. UI_color.set(layer, win, "text_normal")
  599. layer.set_font_size(20)
  600. layer.move_to(x+10,
  601. y+current_Y + win.scroll["render"]+30)
  602. layer.show_text(talk.text("render_avarage_time")+" "+UI_math.timestring(avarage/1000000))
  603. current_Y = current_Y + 40
  604. # REMAINING TIME
  605. remaining = avarage * (win.renders[render]["end_frame"] - win.renders[render]["current_frame"])
  606. UI_color.set(layer, win, "text_normal")
  607. layer.set_font_size(20)
  608. layer.move_to(x+10,
  609. y+current_Y + win.scroll["render"]+30)
  610. layer.show_text(talk.text("render_remaining_time")+" "+UI_math.timestring(remaining/1000000))
  611. current_Y = current_Y + 40
  612. else:
  613. current_Y = current_Y + 85
  614. ###########################
  615. UI_elements.scroll_area(layer, win, "render",
  616. x,
  617. y,
  618. width,
  619. height-60,
  620. current_Y,
  621. bar=True,
  622. mmb=True,
  623. url="render"
  624. )
  625. return surface