studio_renderLayer.py 31 KB

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