import { blenderPath, blenderScriptPath, templatePath, finsishedIconPath, dataPath } from "./paths"; import {spawn} from "child_process"; import logger from "./logger"; import { setBlenderLoading, setBlenderStatus } from "./ui/menu"; import { setLogNumber, setStatus, addTerminalLine } from "./ui/renderingPage"; import {imageLoading, imageLoaded} from "./ui/settingsPage"; import { getInOutSettings, getActiveProfile } from "./settings"; import { pageSetRendering, setProgress, openPage, Page } from "../renderer"; import { setLog, setRenderProgress, startProgress, stopProgress } from "./progressController"; import { ipcRenderer } from "electron"; import path from 'path'; import fs from "fs"; // import { getDoNotDisturb } from "electron-notification-state"; const blenderStartString = [ templatePath, "--background", "--python", blenderScriptPath ] let blenderConsole = spawn(blenderPath, blenderStartString).on('error', function(err) { logger.errorMSG("Could not start blender: " + err.toString()); }); let readyToAcceptCommand = false; let renderingPicture = false; let renderingVideo = false; let waitingForRender = false; function getOutPath(log:string) { let fullOutPath = path.join(getInOutSettings().output, log.substring(log.lastIndexOf("\\")).replace(".csv", "."+getActiveProfile().videoFormat)); if(fs.existsSync(fullOutPath)) { let i = 1; while(fs.existsSync(fullOutPath.replace("."+getActiveProfile().videoFormat, " ("+i+")."+getActiveProfile().videoFormat))) { i++; } fullOutPath = fullOutPath.replace("."+getActiveProfile().videoFormat, " ("+i+")."+getActiveProfile().videoFormat); } return fullOutPath; } let outputArgs:string[] = []; function blenderArgs() { const outputList:string[] = []; getInOutSettings().logs.forEach(log => { outputList.push(getOutPath(log)); }); outputArgs = outputList; return JSON.stringify({ stickMode2:getActiveProfile().stickMode2, width:getActiveProfile().width, stickDistance:getActiveProfile().stickDistance, fps:getActiveProfile().fps, videoFormat:getActiveProfile().videoFormat, logs:getInOutSettings().logs, output:outputList, dataPath:dataPath }); } function startBlender() { let frames = "0"; let lastFrame = "0"; let log = "0"; blenderConsole.stdout.on('data', function(data) { const dataStr = data.toString(); logger.info("Blender: " + dataStr); if(renderingVideo) { addTerminalLine(dataStr); } if (dataStr.includes("Blender started successfully")) { renderingPicture = false; renderingVideo = false; setBlenderStatus("Started"); } if (dataStr.includes("Blender quit")) { if(renderingPicture) { logger.errorMSG("Rendering preview Failed!"); } else if(renderingVideo) { logger.errorMSG("Rendering video Failed!"); } readyToAcceptCommand = false; renderingPicture = false; renderingVideo = false; setBlenderStatus("Restarting"); setBlenderLoading(true); setProgress(); restartBlender(); } if(dataStr.includes("Frames:")) { frames = dataStr.split(":")[1]; renderingVideo = true; readyToAcceptCommand = false; setRenderProgress(parseInt(log), true, 0, 0); } if(dataStr.includes("Fra:") && renderingVideo) { lastFrame = dataStr.split(":")[1].split(" ")[0]; setStatus("Rendering Frame " + lastFrame + "/" + frames); setRenderProgress(parseInt(log), false, parseInt(frames), parseInt(lastFrame)); } if(dataStr.includes("Finished") && renderingVideo) { pageSetRendering(false); stopProgress(); if(lastFrame == frames) { openPage(Page.RenderFinish); ipcRenderer.send("renderFinished"); // TODO: only show notification if not in do not disturb mode, currently not working. Details: https://github.com/felixrieseberg/macos-notification-state/issues/30 new Notification("Render Finished", { body: "Rendering finished successfully!", icon: finsishedIconPath }).onclick = function() { ipcRenderer.send("openApp"); } } else { logger.errorMSG("Render Failed!"); } } if(dataStr.includes("Init:") && renderingVideo) { setStatus("Initialize Frame " + dataStr.split(":")[1] + "/" + frames); setRenderProgress(parseInt(log), true, parseInt(frames), parseInt(dataStr.split(":")[1])); } if(dataStr.includes("Lognr:") && renderingVideo) { log = dataStr.split(":")[1]; if(log !== "1") { setLog(parseInt(log)); } setLogNumber(log); } if(dataStr.includes("Waiting for command")) { pageSetRendering(false); setProgress(); if(renderingPicture) { imageLoaded(); } if(!waitingForRender) { readyToAcceptCommand = true; renderingPicture = false; renderingVideo = false; setBlenderStatus("Ready"); setBlenderLoading(false); } else { waitingForRender = false; renderingPicture = true; blenderConsole.stdin.write("getRender -- "+blenderArgs()+"\n"); setBlenderStatus("Rendering"); setBlenderLoading(true); imageLoading(); } } }); blenderConsole.stderr.on('data', function(data:string) { logger.errorMSG("Blender: " + data); }); } function restartBlender() { pageSetRendering(false); blenderConsole.kill(); blenderConsole = spawn(blenderPath, blenderStartString); startBlender(); } enum blenderCmd { getRender, startRendering, stopRendering, } function blender(command:blenderCmd) { if(command === blenderCmd.getRender) { if(readyToAcceptCommand) { readyToAcceptCommand = false; renderingPicture = true; imageLoading(); setBlenderStatus("Rendering"); setBlenderLoading(true); blenderConsole.stdin.write("getRender -- "+blenderArgs()+"\n"); } else { waitingForRender = true; } } else if(command === blenderCmd.startRendering) { if(readyToAcceptCommand) { if(getInOutSettings().logs.length === 0) { logger.warningMSG("No log selected!"); } else { readyToAcceptCommand = false; renderingVideo = true; pageSetRendering(true); setBlenderStatus("Rendering"); setBlenderLoading(true); blenderConsole.stdin.write("startRendering -- "+blenderArgs()+"\n"); startProgress(); } } } else if(command === blenderCmd.stopRendering) { readyToAcceptCommand = false; renderingPicture = false; renderingVideo = false; restartBlender(); } } ipcRenderer.on("isRenderActiveClose", () => { if(renderingVideo) { ipcRenderer.send("renderActiveClose"); } else { ipcRenderer.send("renderInactiveClose"); } }); export { blender, blenderCmd, startBlender, renderingPicture, outputArgs }