render_viewer.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. # Part of VCStudio
  2. # GPLv3 or later
  3. # This file will visualize the rendering process
  4. import os
  5. import sys
  6. import json
  7. import time
  8. if len(sys.argv) == 1:
  9. project = input("Project: ")
  10. else:
  11. project = sys.argv[1]
  12. def get_runtime_data(project):
  13. # This will read a specific .json file from the system.
  14. template = {"to_render":True,
  15. "current_progress":"Fra: 69 | Mem: 420 |Sample: 69/420"}
  16. try:
  17. with open(project+"/render_runtime.json") as json_file:
  18. data = json.load(json_file)
  19. except:
  20. data = template.copy()
  21. return data
  22. def save_runtime_data(data, project):
  23. with open(project+"/render_runtime.json", 'w') as fp:
  24. json.dump(data, fp, indent=4)
  25. # Colors are used to make the
  26. clr = {
  27. "norm":"\033[00m", # Reset to normal
  28. "bold":"\033[01m", # Bold Text
  29. "ital":"\033[03m", # Italic Text
  30. "undr":"\033[04m", # Underlined
  31. "blnk":"\033[05m", # Blinking
  32. # Text
  33. "tdbl":"\033[30m", # Dark Black
  34. "tdrd":"\033[31m", # Dark Red
  35. "tdgr":"\033[32m", # Dark Green
  36. "tdyl":"\033[33m", # Dark Yellow
  37. "tdbu":"\033[34m", # Dark Blue
  38. "tdma":"\033[35m", # Dark Magenta
  39. "tdcy":"\033[36m", # Dark Cyan
  40. "tdwh":"\033[37m", # Dark White
  41. "tbbl":"\033[90m", # Bright Black
  42. "tbrd":"\033[91m", # Bright Red
  43. "tbgr":"\033[92m", # Bright Green
  44. "tbyl":"\033[93m", # Bright Yellow
  45. "tbbu":"\033[94m", # Bright Blue
  46. "tbma":"\033[95m", # Bright Magenta
  47. "tbcy":"\033[96m", # Bright Cyan
  48. "tbwh":"\033[97m", # Bright White
  49. # Background
  50. "bdbl":"\033[40m", # Dark Black
  51. "bdrd":"\033[41m", # Dark Red
  52. "bdgr":"\033[42m", # Dark Green
  53. "bdyl":"\033[43m", # Dark Yellow
  54. "bdbu":"\033[44m", # Dark Blue
  55. "bdma":"\033[45m", # Dark Magenta
  56. "bdcy":"\033[46m", # Dark Cyan
  57. "bdwh":"\033[47m", # Dark White
  58. "bbbl":"\033[100m", # Bright Black
  59. "bbrd":"\033[101m", # Bright Red
  60. "bbgr":"\033[102m", # Bright Green
  61. "bbyl":"\033[103m", # Bright Yellow
  62. "bbbu":"\033[104m", # Bright Blue
  63. "bbma":"\033[105m", # Bright Magenta
  64. "bbcy":"\033[106m", # Bright Cyan
  65. "bbwh":"\033[108m" # Bright White
  66. }
  67. # A function that insures a specific width of the printed part
  68. def wdth(x, n):
  69. # Convert Data to String
  70. mode = "normal"
  71. if type(x) == bool and x == True:
  72. x = "V"
  73. mode = "bdgr"
  74. elif type(x) == bool and x == False:
  75. x = "X"
  76. mode = "bdrd"
  77. else:
  78. x = str(x)
  79. # Turn emogis
  80. #x = emote(x)
  81. # Some characters are too wide. They do not obey the
  82. # monospace of the terminal, thus making it not pretty.
  83. # This is the string of characters which are checked to
  84. good = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'’()*+,-./:;<=>?@[\]^_`{|}~ йцукенгшщзхъфывапролджэячсмитьбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮёЁ"
  85. # let's filter the string
  86. y = x
  87. x = ""
  88. for i in y:
  89. if i in good:
  90. x = x + i
  91. else:
  92. x = x + "▓"
  93. # Now let's print what we've got.
  94. if len(y) < n:
  95. fac = n-len(y)
  96. fac1 = int(round(fac/2))
  97. fac2 = fac1
  98. while fac1 + fac2 > fac:
  99. fac2 -=1
  100. while fac1 + fac2 < fac:
  101. fac2 +=1
  102. x = (" "*fac1)+x+(" "*fac2)
  103. elif len(y) > n:
  104. if n > 10:
  105. x = x[:n-3]+"..."
  106. else:
  107. x = x[:n]
  108. if mode == "normal":
  109. return x
  110. else:
  111. return clr[mode]+clr["bold"]+x+clr["norm"]
  112. def tsize():
  113. # This funtion will get the size of the terminal and
  114. # return it to the variables provided width, height
  115. # On some systems this may not work. So there is a
  116. # try function.
  117. try:
  118. # Getting the size of the terminal
  119. import os
  120. w, h = os.get_terminal_size()
  121. # Sometimes when the terminal width is either
  122. # even or odd. It breaks code for some other
  123. # thing written differenly. For example:
  124. # You may have an even width ( like 84 ) when
  125. # writing a function. And then it works on different
  126. # widths as well like 62 and 80 and 48. All of them
  127. # are still even. Then you scale the terminal to be
  128. # something off like 63 and the function breaks. You
  129. # have one character too much or one character too little.
  130. # This is why I do not want to have a difference. And
  131. # force width to be one less, if it's not divisible by 2.
  132. if not w % 2:
  133. w = w - 1
  134. return w, h
  135. except:
  136. # If, by any reason the terminal can't get it's size.
  137. # We want to return some size regardless.
  138. w = 60
  139. h = 20
  140. return w, h
  141. def table(data, number=True):
  142. # This function will present data in a pretty table thing.
  143. # So let's first of all get the size of the terminal
  144. w, h = tsize()
  145. if number:
  146. w = w - 4
  147. # Then let's draw the categories for this we need to extract
  148. # it's sizes. If there is no 'size' variable the sizes of
  149. # each category will be spread equally.
  150. size = [] # Here the size will go as pure character value.
  151. if "size" in data:
  152. for i in data["size"]:
  153. size.append(int(( w - 10 ) / sum(data["size"]) * i))
  154. while sum(size) < w - 10:
  155. size[-1] += 1
  156. # printing categories
  157. nb = ""
  158. if number:
  159. nb = " "
  160. s = " "+clr["bdma"]+" "+clr["tbwh"]+nb
  161. for n, item in enumerate(data["categories"]):
  162. s = s + wdth(item.upper(), size[n])
  163. print(s+clr["bdma"]+" "+clr["norm"])
  164. size[-1] += 1
  165. # printing items
  166. for b, i in enumerate(data["data"]):
  167. # dark bright sequence thingy
  168. if b % 2:
  169. d = "b"
  170. else:
  171. d = "d"
  172. nb = ""
  173. if number:
  174. nb = clr["tbwh"]+wdth(b,4)
  175. s = " "+clr["bdma"]+" "+nb+clr["norm"]+clr["b"+d+"bu"]#+clr["tbwh"]
  176. for n, item in enumerate(i):
  177. s = s +clr["b"+d+"bu"]+ clr["tbwh"]+wdth(item, size[n]-1)+clr["bdma"]+" "
  178. print(s+clr["norm"])
  179. def center(line, c="bdma", blink=False):
  180. # This funtiocn will bring a given string of text
  181. # in the center of the terminal with a nice backgroud
  182. # around it.
  183. w, h = tsize()
  184. if blink:
  185. blink = clr["blnk"]
  186. else:
  187. blink = ""
  188. if len(line) % 2:
  189. line = line + " "
  190. if len(line) < w - 11:
  191. print(" "+clr[c],
  192. wdth(" ", int((w-10)/2 - (len(line)/2))),
  193. clr["bold"]+clr["tbwh"]+blink+line,
  194. wdth(" ", int((w-10)/2 - (len(line)/2))-1),
  195. clr["norm"])
  196. else:
  197. print(" "+clr[c],
  198. clr["bold"]+clr["tbwh"]+blink+wdth(line,w-10),
  199. clr["norm"])
  200. running_for = 0
  201. lastframe = 0
  202. maxtime = 1000000
  203. while True:
  204. running_for = running_for + 1
  205. runtime = get_runtime_data(project)
  206. if not runtime.get("to_render"):
  207. break
  208. x,y = tsize()
  209. if y > 8:
  210. print("\n\n")
  211. process = runtime.get("current_progress", "").split(" | ")
  212. try:
  213. del runtime["current_progress"]
  214. except:
  215. pass
  216. data_print = {"categories":list(runtime.keys()),
  217. "size":[1]*(len(runtime)),
  218. "data":[list(runtime.values())]}
  219. table(data_print, False)
  220. data_print = {"categories":[""]*(len(process)),
  221. "size":[1]*(len(process)),
  222. "data":[process]}
  223. table(data_print, False)
  224. center("")
  225. # Latest frames data
  226. filename = runtime.get("current_file", "")
  227. folder = filename[:filename.rfind("/")]+"/extra"
  228. savefile = folder+filename[filename.rfind("/"):]+".json"
  229. try:
  230. with open(project+savefile) as json_file:
  231. data = json.load(json_file)
  232. except:
  233. data = {}
  234. listoftimesx = data.get("analytics", {}).get(data.get("save_folder", ""), [])
  235. listoftimes = {}
  236. minframe = data.get("start_frame", 0)
  237. for i in listoftimesx:
  238. try:
  239. listoftimes[int(i)] = listoftimesx[i]
  240. except:
  241. pass
  242. try:
  243. maxframe = max(list(listoftimes.keys()))
  244. if maxframe > lastframe:
  245. lastframe = maxframe
  246. running_for = 0
  247. maxtime = max(list(listoftimes.values()))
  248. maxtime = max(maxtime, running_for*1000000)
  249. print()
  250. for i in range(max(minframe,maxframe-y+16), maxframe+1):
  251. amount = int((x-14)/(maxtime-minframe)*(listoftimes[i]-minframe))
  252. print(" ",wdth(i, 4), "▒"*amount)
  253. except Exception as e:
  254. #print(e)
  255. maxframe = 0
  256. #maxtime = 1
  257. lastframe = maxframe
  258. running_for = 0
  259. amount = int((x-14)/maxtime*running_for*1000000)
  260. print(" " , wdth(maxframe+1, 4), "█"*amount)
  261. amount = int((x-14)/(data.get("end_frame", maxframe+1)-minframe)*(maxframe+1-minframe))
  262. print()
  263. print(" "+clr["tbma"]+wdth(data.get("end_frame", maxframe+1), 4)+" "+("█"*amount)+clr["norm"])
  264. time.sleep(1)
  265. os.system("clear")