Esempio n. 1
0
    def get_frame_per_file_render_arguments(self):
        """
        Generates the render arguments for when FramePerFile mode is set to True.
        This means that each output frame has an associated scene file with the same frame number.
        This is mostly used in Octane 1 before .orbx was a thing.

        :return: a list of commandline arguments, and the scene file
        """
        render_args = ['-e', '-q']

        sceneFile = self.GetPluginInfoEntry("SceneFile")
        sceneFile = PathUtils.ToPlatformIndependentPath(
            RepositoryUtils.CheckPathMapping(sceneFile))
        outputFile = self.CreateOutputFile()

        paddingSize = 0
        if not self.GetBooleanPluginInfoEntryWithDefault("SingleFile", True):
            currPadding = FrameUtils.GetFrameStringFromFilename(sceneFile)
            paddingSize = len(currPadding)

            if paddingSize > 0:
                newPadding = StringUtils.ToZeroPaddedString(
                    self.GetStartFrame(), paddingSize, False)
                sceneFile = FrameUtils.SubstituteFrameNumber(
                    sceneFile, newPadding)

        # Build the new output file name.
        if outputFile:
            outputFile = PathUtils.ToPlatformIndependentPath(
                RepositoryUtils.CheckPathMapping(outputFile))

            # Add padding to output file if necessary.
            if paddingSize > 0:
                outputFile = FrameUtils.SubstituteFrameNumber(
                    outputFile, newPadding)
                outputPath = os.path.dirname(outputFile)
                outputFileName, outputExtension = os.path.splitext(outputFile)

                outputFile = os.path.join(
                    outputPath, outputFileName + newPadding + outputExtension)

            render_args.extend(['-o', outputFile])

        sample = self.GetIntegerPluginInfoEntryWithDefault(
            "OverrideSampling", 0)
        if sample > 0:
            render_args.extend(['-s', str(sample)])

        render_target = self.GetPluginInfoEntryWithDefault(
            "RenderTargetOCS", "")
        if render_target:
            render_args.extend(['-t', render_target])

        return render_args, sceneFile
Esempio n. 2
0
    def OnJobFinished(self, job):
        # Skip job if filtered or no filter
        jobNameFilter = self.GetConfigEntryWithDefault('JobNameFilter', '')
        if not jobNameFilter or not re.match(jobNameFilter, job.JobName):
            return

        pluginNameFilter = self.GetConfigEntryWithDefault(
            'PluginNameFilter', '')
        if not pluginNameFilter or not re.match(pluginNameFilter,
                                                job.JobPlugin):
            return

        inputFileName = self.GetConfigEntry('InputFile')
        outputFileName = self.GetConfigEntry('OutputFile')

        # Format tokens
        delimiter = self.GetConfigEntryWithDefault('Delimiter',
                                                   '').stript().replace(
                                                       ' ', '')
        if len(delimiter) in [1, 2]:
            inputFileName = formatToken(job, getTokens(inputFileName,
                                                       delimiter),
                                        inputFileName)
            outputFileName = formatToken(job,
                                         getTokens(outputFileName, delimiter),
                                         outputFileName)
        else:
            self.LogWarning(
                'Token Delimiter "%s" should be one or to char long' %
                delimiter)
            return

        # Path mapping
        inputFileName = RepositoryUtils.CheckPathMapping(inputFileName, True)
        outputFileName = RepositoryUtils.CheckPathMapping(outputFileName, True)

        if not os.path.isdir(os.path.dirname(inputFileName)):
            self.LogWarning('No such directory %s' %
                            os.path.dirname(inputFileName))
            return

        if not glob.glob(sequenceToWildcard(inputFileName)):
            self.LogWarning('No file/sequence %s' % inputFileName)
            return
        createFFmpegJob(
            job,
            inputFileName=inputFileName,
            outputFileName=outputFileName,
            outputArgs=self.GetConfigEntryWithDefault('OutputArgs', ''),
            inputArgs=self.GetConfigEntryWithDefault('InputArgs', ''),
            priority=self.GetConfigEntryWithDefault('Priority', '50'))
        self.LogInfo(
            'Submitted ffmpeg job with output: {}'.format(outputFileName))
Esempio n. 3
0
    def RenderArgument(self):
        """
        Builds up the commandline render arguments as a list which then gets transformed into string

        :return: a string of commandline arguments
        """
        scene_file = self.GetPluginInfoEntry("SceneFile")
        scene_file = PathUtils.ToPlatformIndependentPath(
            RepositoryUtils.CheckPathMapping(scene_file))

        render_args = ['--no-gui']

        frame_per_file_mode = self.GetBooleanPluginInfoEntryWithDefault(
            "FramePerFileMode", False)
        if frame_per_file_mode:
            # Octane 1 workflow that's still supported in 2 and onward.
            temp_render_args, scene_file = self.get_frame_per_file_render_arguments(
            )
            render_args.extend(temp_render_args)
        else:
            render_args.extend(self.get_script_render_arguments())

        additional_args = self.GetPluginInfoEntryWithDefault(
            "AdditionalArgs", "").strip()
        if additional_args:
            render_args.append(additional_args)

        render_args.extend(self.get_gpu_render_arguments())
        render_args.append(scene_file)

        return self.quote_cmdline_args(render_args)
Esempio n. 4
0
    def RenderArgument(self):
        arguments = str(self.GetPluginInfoEntryWithDefault("Arguments", ""))
        arguments = RepositoryUtils.CheckPathMapping(arguments)

        arguments = re.sub(r"<(?i)STARTFRAME>", str(self.GetStartFrame()),
                           arguments)
        arguments = re.sub(r"<(?i)ENDFRAME>", str(self.GetEndFrame()),
                           arguments)
        arguments = re.sub(r"<(?i)QUOTE>", "\"", arguments)

        arguments = self.ReplacePaddedFrame(arguments,
                                            "<(?i)STARTFRAME%([0-9]+)>",
                                            self.GetStartFrame())
        arguments = self.ReplacePaddedFrame(arguments,
                                            "<(?i)ENDFRAME%([0-9]+)>",
                                            self.GetEndFrame())

        count = 0
        for filename in self.GetAuxiliaryFilenames():
            localAuxFile = Path.Combine(self.GetJobsDataDirectory(), filename)
            arguments = re.sub(r"<(?i)AUXFILE" + str(count) + r">",
                               localAuxFile.replace("\\", "/"), arguments)
            count += 1

        return arguments
    def render_argument(self):
        """Generate command line arguments for render executable.

        Returns:
            (str): arguments to add to render executable.

        """
        # Read tile config file. This file is in compatible format with
        # Draft Tile Assembler
        data = {}
        with open(self.config_file, "rU") as f:
            for text in f:
                # Parsing key-value pair and removing white-space
                # around the entries
                info = [x.strip() for x in text.split("=", 1)]

                if len(info) > 1:
                    try:
                        data[str(info[0])] = info[1]
                    except Exception as e:
                        # should never be called
                        self.FailRender(
                            "Cannot parse config file: {}".format(e))

        # Get output file. We support only EXRs now.
        output_file = data["ImageFileName"]
        output_file = RepositoryUtils.CheckPathMapping(output_file)
        output_file = self.process_path(output_file)
        """
        _, ext = os.path.splitext(output_file)
        if "exr" not in ext:
            self.FailRender(
                "[{}] Only EXR format is supported for now.".format(ext))
        """
        tile_info = []
        for tile in range(int(data["TileCount"])):
            tile_info.append({
                "filepath": data["Tile{}".format(tile)],
                "pos_x": int(data["Tile{}X".format(tile)]),
                "pos_y": int(data["Tile{}Y".format(tile)]),
                "height": int(data["Tile{}Height".format(tile)]),
                "width": int(data["Tile{}Width".format(tile)])
            })

        # FFMpeg doesn't support tile coordinates at the moment.
        # arguments = self.tile_completer_ffmpeg_args(
        #     int(data["ImageWidth"]), int(data["ImageHeight"]),
        #     tile_info, output_file)

        arguments = self.tile_oiio_args(
            int(data["ImageWidth"]), int(data["ImageHeight"]),
            tile_info, output_file)
        self.LogInfo(
            "Using arguments: {}".format(" ".join(arguments)))
        self.tiles = tile_info
        return " ".join(arguments)
Esempio n. 6
0
    def get_script_render_arguments(self):
        """
        Generates the render arguments for the octane lua script workflow. Octane 2 and later.

        :return: a list of commandline arguments
        """
        output_folder = self.GetPluginInfoEntryWithDefault("OutputFolder", "")
        output_folder = PathUtils.ToPlatformIndependentPath(
            RepositoryUtils.CheckPathMapping(output_folder))

        lua_script = os.path.join(self.GetPluginDirectory(),
                                  "DeadlineOctane.lua")
        filename_template = self.GetPluginInfoEntryWithDefault(
            "FilenameTemplate", "")
        file_format = self.GetPluginInfoEntryWithDefault("FileFormat", "png8")

        render_target_ocs = self.GetPluginInfoEntryWithDefault(
            "RenderTargetOCS", "")
        render_target_orbx = self.GetPluginInfoEntryWithDefault(
            "RenderTargetORBX", "")
        render_target = ""
        if render_target_ocs:
            render_target = render_target_ocs
        elif render_target_orbx:
            render_target = render_target_orbx

        render_args = [
            '-q',
            '--script',
            lua_script,
            '-a',
            filename_template,
            '-a',
            output_folder,
            '-a',
            file_format,
            '-a',
            str(self.GetStartFrame()),
            '-a',
            str(self.GetEndFrame()),
            '-a',
            render_target,
            '--stop-after-script',
        ]

        sample = self.GetIntegerPluginInfoEntryWithDefault(
            "OverrideSampling", 0)
        if sample > 0:
            render_args.extend(['-s', str(sample)])

        if render_target:
            render_args.extend(['-t', render_target])

        return render_args
Esempio n. 7
0
def pype(deadlinePlugin):
    """Remaps `PYPE_METADATA_FILE` and `PYPE_PYTHON_EXE` environment vars.

    `PYPE_METADATA_FILE` is used on farm to point to rendered data. This path
    originates on platform from which this job was published. To be able to
    publish on different platform, this path needs to be remapped.

    `PYPE_PYTHON_EXE` can be used to specify custom location of python
    interpreter to use for Pype. This is remappeda also if present even
    though it probably doesn't make much sense.

    Arguments:
        deadlinePlugin: Deadline job plugin passed by Deadline

    """
    job = deadlinePlugin.GetJob()
    # PYPE should be here, not OPENPYPE - backward compatibility!!
    pype_metadata = job.GetJobEnvironmentKeyValue("PYPE_METADATA_FILE")
    pype_python = job.GetJobEnvironmentKeyValue("PYPE_PYTHON_EXE")
    # test if it is pype publish job.
    if pype_metadata:
        pype_metadata = RepositoryUtils.CheckPathMapping(pype_metadata)
        if platform.system().lower() == "linux":
            pype_metadata = pype_metadata.replace("\\", "/")

        print("- remapping PYPE_METADATA_FILE: {}".format(pype_metadata))
        job.SetJobEnvironmentKeyValue("PYPE_METADATA_FILE", pype_metadata)
        deadlinePlugin.SetProcessEnvironmentVariable("PYPE_METADATA_FILE",
                                                     pype_metadata)

    if pype_python:
        pype_python = RepositoryUtils.CheckPathMapping(pype_python)
        if platform.system().lower() == "linux":
            pype_python = pype_python.replace("\\", "/")

        print("- remapping PYPE_PYTHON_EXE: {}".format(pype_python))
        job.SetJobEnvironmentKeyValue("PYPE_PYTHON_EXE", pype_python)
        deadlinePlugin.SetProcessEnvironmentVariable("PYPE_PYTHON_EXE",
                                                     pype_python)

    deadlinePlugin.ModifyCommandLineCallback += pype_command_line
Esempio n. 8
0
def _remove_files_from_directive(directiveLine, additionalFilesToMap):
    directiveLine = directiveLine.strip()

    directiveInfo = directiveLine.split(None, 1)
    #Directive is of the form #include "PATH"
    if len(directiveInfo) == 2:
        includePath = directiveInfo[1]
        includePath = includePath.strip().strip("\"'")
        includePath = replaceSlashesByOS(includePath)
        includePath = RepositoryUtils.CheckPathMapping(includePath)
        additionalFilesToMap.append(includePath)

        directiveInfo[1] = u'"%s"' % os.path.basename(includePath)

    directiveLine = u" ".join(directiveInfo)

    return directiveLine + u"\r\n"
Esempio n. 9
0
    def MapAndCleanPath(self, path):
        path = RepositoryUtils.CheckPathMapping(path)
        if SystemUtils.IsRunningOnWindows():
            path = path.replace("/", "\\")
            if path.startswith("\\") and not path.startswith("\\\\"):
                path = "\\" + path

        extension = os.path.splitext(path)[1]
        if extension == ".project":
            tempSceneDirectory = self.CreateTempDirectory(
                "thread" + str(self.GetThreadNumber()))
            tempSceneFileName = os.path.basename(path)
            tempSceneFilename = os.path.join(tempSceneDirectory,
                                             tempSceneFileName)
            RepositoryUtils.CheckPathMappingInFileAndReplace(
                path, tempSceneFilename, "", "")
            path = tempSceneFilename

        return path.replace("\\", "/")
Esempio n. 10
0
def pype_command_line(executable, arguments, workingDirectory):
    """Remap paths in comand line argument string.

    Using Deadline rempper it will remap all path found in command-line.

    Args:
        executable (str): path to executable
        arguments (str): arguments passed to executable
        workingDirectory (str): working directory path

    Returns:
        Tuple(executable, arguments, workingDirectory)

    """
    print("-" * 40)
    print("executable: {}".format(executable))
    print("arguments: {}".format(arguments))
    print("workingDirectory: {}".format(workingDirectory))
    print("-" * 40)
    print("Remapping arguments ...")
    arguments = RepositoryUtils.CheckPathMapping(arguments)
    print("* {}".format(arguments))
    print("-" * 40)
    return executable, arguments, workingDirectory
Esempio n. 11
0
    def RenderArgument(self):
        outputDirectory = self.GetPluginInfoEntryWithDefault(
            "ExportDirectory", "")
        outputFilename = self.GetPluginInfoEntryWithDefault("ExportName", "")
        outputFormat = self.GetPluginInfoEntryWithDefault("ExportFormat", "")

        output = os.path.join(outputDirectory, outputFilename + outputFormat)
        output = RepositoryUtils.CheckPathMapping(output)

        scene = self.GetPluginInfoEntryWithDefault("SceneFile",
                                                   self.GetDataFilename())
        scene = RepositoryUtils.CheckPathMapping(scene)

        # Windows handles both slashes as long as we don't mix and match the first two
        if os.name == 'nt':
            # Check if it is a unc path
            if scene.startswith("\\"):
                if scene[0:2] != "\\\\":
                    scene = "\\" + scene
            elif scene.startswith("/"):
                if scene[0:2] != "//":
                    scene = "/" + scene

            if output.startswith("\\"):
                if output[0:2] != "\\\\":
                    output = "\\" + output
            elif output.startswith("/"):
                if output[0:2] != "//":
                    output = "/" + output

        else:
            scene = scene.replace("\\", "/")
            if scene[0:2] == "//":
                scene = scene[1:len(scene)]

            output = output.replace("\\", "/")
            if output[0:2] == "//":
                output = output[1:len(output)]

        # We should fail out early here if the file can't be found
        if not os.path.isfile(scene):
            self.FailRender('Could not find the following scene file: "%s"' %
                            scene)

        # Check if directory exists, create if otherwise. SketchUp won't export anything if the directory doesn't exist
        directory = os.path.dirname(output)
        if not os.path.exists(directory):
            self.LogWarning(
                'The following output folder does not exist: "%s", trying to create it...'
                % directory)
            try:
                os.makedirs(directory)
            except Exception as e:
                self.FailRender(
                    'Failed to create the directory: "%s", please ensure the directory is created and accessible before trying again.\n%s'
                    % (directory, e))
        elif not os.path.isdir(directory):
            self.FailRender(
                '"%s" exists but it is not a directory. Choose a different destination and ensure it exists and is accessible.'
                % directory)

        rubyScript = os.path.join(self.GetPluginDirectory(),
                                  "SketchUpDeadline.rb")

        outputFilename, outputExtension = os.path.splitext(
            os.path.basename(output))
        infoFileContents = [
            self.GetPluginInfoEntryWithDefault("ExportType", ""),
            os.path.dirname(output), outputFilename, outputExtension,
            self.GetPluginInfoEntryWithDefault("Width", "0"),
            self.GetPluginInfoEntryWithDefault("Height", "0"),
            self.GetPluginInfoEntryWithDefault("AntiAlias", "False"),
            self.GetPluginInfoEntryWithDefault("Compression", "0"),
            self.GetPluginInfoEntryWithDefault("Transparent", "False"),
            self.GetPluginInfoEntryWithDefault("UseVray", "False"),
            self.GetPluginInfoEntryWithDefault("FrameRate", "0"),
            self.GetPluginInfoEntryWithDefault("SceneName", ""),
            self.GetPluginInfoEntryWithDefault("VrayVersion", "2"),
            str(self.GetStartFrame()),
            str(self.GetEndFrame())
        ]

        self.LogInfo("Contents of DEADLINE_SKETCHUP_INFO file:")
        with open(self.infoFilePath, 'w') as fileHandle:
            for line_desc, line in zip(self.INFO_FILE_LINE_DESC,
                                       infoFileContents):
                fileHandle.write(line + '\n')
                self.LogInfo("\t%s=%s" % (line_desc, line))

        # Construct the command line and return it
        arguments = ' -RubyStartup "' + rubyScript + '" "' + scene + '"'

        return arguments
Esempio n. 12
0
    def renderArgument(self):

        renderEngines = {
            "V-Ray": "0",
            "V-Ray RT": "1",
            u"V-Ray RT(OpenCL)": "3",
            u"V-Ray RT(CUDA)": "5"
        }
        sRGBOptions = ["On", "Off"]

        displayWindow = self.GetBooleanPluginInfoEntryWithDefault(
            "DisplayVFB", False)
        autoclose = self.GetBooleanPluginInfoEntryWithDefault(
            "AutocloseVFB", True)
        displaySRGB = self.GetPluginInfoEntryWithDefault("DisplaySRGB", "On")

        # Get the frame information.
        startFrame = self.GetStartFrame()
        endFrame = self.GetEndFrame()
        singleRegionJob = self.IsTileJob()
        singleRegionFrame = str(self.GetStartFrame())
        singleRegionIndex = self.GetCurrentTaskId()
        separateFilesPerFrame = self.GetBooleanPluginInfoEntryWithDefault(
            "SeparateFilesPerFrame", False)
        regionRendering = self.GetBooleanPluginInfoEntryWithDefault(
            "RegionRendering", False)
        rtEngine = self.GetPluginInfoEntryWithDefault("VRayEngine", "V-Ray")
        rtTimeout = self.GetFloatPluginInfoEntryWithDefault("RTTimeout", 0.00)
        rtNoise = self.GetFloatPluginInfoEntryWithDefault("RTNoise", 0.001)
        rtSampleLevel = self.GetIntegerPluginInfoEntryWithDefault(
            "RTSamples", 0)

        # Can't allow it to be interactive or display the image because that would hang the slave
        renderarguments = " -scenefile=\"" + self.tempSceneFilename + "\" -interactive=0"

        if not displayWindow:
            renderarguments += " -display=0"  # Default value is 1
        else:
            if autoclose:
                renderarguments += " -autoclose=1"  # Default value is 0

            renderarguments += " -displaySRGB=%s" % (
                sRGBOptions.index(displaySRGB) + 1)

        renderarguments += " -rtEngine=%s" % renderEngines[rtEngine.strip()]

        if not rtEngine == "V-Ray":
            renderarguments += " -rtTimeOut=%s -rtNoise=%s -rtSampleLevel=%s" % (
                rtTimeout, rtNoise, rtSampleLevel)

        renderarguments += " -frames=" + str(startFrame)
        if endFrame > startFrame:
            renderarguments += "-" + str(endFrame)

        # Set the output path.
        outputFile = self.GetPluginInfoEntryWithDefault("OutputFilename",
                                                        "").strip()
        if outputFile != "":
            outputFile = RepositoryUtils.CheckPathMapping(outputFile)
            outputFile = PathUtils.ToPlatformIndependentPath(outputFile)

            if regionRendering:
                outputPath = Path.GetDirectoryName(outputFile)
                outputFileName = Path.GetFileNameWithoutExtension(outputFile)
                outputExtension = Path.GetExtension(outputFile)

                if singleRegionJob:
                    outputFile = os.path.join(
                        outputPath, ("_tile%s_" % singleRegionIndex) +
                        outputFileName + outputExtension)

                else:
                    currTile = self.GetIntegerPluginInfoEntryWithDefault(
                        "CurrentTile", 1)
                    outputFile = os.path.join(outputPath,
                                              ("_tile%d_" % currTile) +
                                              outputFileName + outputExtension)

            renderarguments += " -imgFile=\"" + outputFile + "\""

        # Now set the rest of the options.
        renderarguments += " -numThreads=" + str(self.GetThreadCount())

        width = self.GetIntegerPluginInfoEntryWithDefault("Width", 0)
        if width > 0:
            renderarguments += " -imgWidth=" + str(width)

        height = self.GetIntegerPluginInfoEntryWithDefault("Height", 0)
        if height > 0:
            renderarguments += " -imgHeight=" + str(height)

        if regionRendering:
            regionNumString = ""
            if singleRegionJob:
                regionNumString = str(singleRegionIndex)

            #Coordinates In Pixels will always be true when using the common tilerendering code.
            if self.GetBooleanPluginInfoEntryWithDefault(
                    "CoordinatesInPixels", False):
                #With the coordinates already being in pixels we do not need to modify the coordinates.
                xStart = self.GetIntegerPluginInfoEntryWithDefault(
                    "RegionXStart" + regionNumString, 0)
                xEnd = self.GetIntegerPluginInfoEntryWithDefault(
                    "RegionXEnd" + regionNumString, 0)
                yStart = self.GetIntegerPluginInfoEntryWithDefault(
                    "RegionYStart" + regionNumString, 0)
                yEnd = self.GetIntegerPluginInfoEntryWithDefault(
                    "RegionYEnd" + regionNumString, 0)

            else:
                self.LogWarning(
                    "Using deprecated coordinate system.  Please submit new jobs to use the new coordinates system."
                )
                xStart = round(
                    self.GetFloatPluginInfoEntryWithDefault(
                        "RegionXStart" + regionNumString, 0) * width)
                xEnd = round(
                    self.GetFloatPluginInfoEntryWithDefault(
                        "RegionXEnd" + regionNumString, 0) * width)
                yStart = round(
                    self.GetFloatPluginInfoEntryWithDefault(
                        "RegionYStart" + regionNumString, 0) * height)
                yEnd = round(
                    self.GetFloatPluginInfoEntryWithDefault(
                        "RegionYEnd" + regionNumString, 0) * height)

            renderarguments += " -region=%d;%d;%d;%d" % (xStart, yStart, xEnd,
                                                         yEnd)

        disableProgressColor = self.GetBooleanConfigEntryWithDefault(
            "DisableProgressColor", False)
        if disableProgressColor:
            renderarguments += " -DisableProgressColor=0"

        renderarguments += " " + self.GetPluginInfoEntryWithDefault(
            "CommandLineOptions", "")

        yetiSearchPaths = []
        searchPathIndex = 0
        while True:
            searchPath = self.GetPluginInfoEntryWithDefault(
                "YetiSearchPath" + str(searchPathIndex),
                "").replace("\\", "/")
            if not searchPath:
                break

            yetiSearchPaths.append(
                RepositoryUtils.CheckPathMapping(searchPath))

            searchPathIndex += 1

        if len(yetiSearchPaths) > 0:
            oldSearchPath = os.environ.get("PG_IMAGE_PATH")
            if oldSearchPath:
                yetiSearchPaths.append(oldSearchPath)

            yetiSepChar = ":"
            if SystemUtils.IsRunningOnWindows():
                yetiSepChar = ";"

            self.SetProcessEnvironmentVariable(
                "PG_IMAGE_PATH", yetiSepChar.join(yetiSearchPaths))

        return renderarguments
Esempio n. 13
0
    def PreRenderTasks(self):
        self.LogInfo("Starting V-Ray Task")

        # Get the scene file to render.
        sceneFilename = self.GetPluginInfoEntry("InputFilename")
        sceneFilename = RepositoryUtils.CheckPathMapping(sceneFilename)
        sceneFilename = PathUtils.ToPlatformIndependentPath(sceneFilename)

        # If we're rendering separate files per frame, need to get the vrscene file for the current frame.
        separateFilesPerFrame = self.GetBooleanPluginInfoEntryWithDefault(
            "SeparateFilesPerFrame", False)
        if separateFilesPerFrame:
            currPadding = FrameUtils.GetFrameStringFromFilename(sceneFilename)
            paddingSize = len(currPadding)
            newPadding = StringUtils.ToZeroPaddedString(
                self.GetStartFrame(), paddingSize, False)
            sceneFilename = sceneFilename.replace(currPadding, newPadding)

        # Check if we should be doing path mapping.
        slaveInfo = RepositoryUtils.GetSlaveInfo(self.GetSlaveName(), True)
        if self.GetBooleanConfigEntryWithDefault(
                "EnableVrscenePathMapping",
                True) or slaveInfo.IsAWSPortalInstance:
            self.LogInfo("Performing path mapping on vrscene file")

            tempSceneDirectory = self.CreateTempDirectory(
                "thread" + str(self.GetThreadNumber()))
            tempSceneFileName = Path.GetFileName(sceneFilename)
            self.tempSceneFilename = os.path.join(tempSceneDirectory,
                                                  tempSceneFileName)

            mappedFiles = set()
            filesToMap = [(sceneFilename, os.path.dirname(sceneFilename))]
            while filesToMap:
                curFile, originalSceneDirectory = filesToMap.pop()
                #Include directives normally contain relative paths but just to be safe we must run pathmapping again.
                curFile = RepositoryUtils.CheckPathMapping(curFile)

                if not os.path.isabs(curFile):
                    curFile = os.path.join(originalSceneDirectory, curFile)

                if not os.path.exists(curFile):
                    self.LogInfo("The include file %s does not exist." %
                                 curFile)
                    continue

                if os.path.basename(curFile) in mappedFiles:
                    self.LogInfo(
                        "The include file %s has already been mapped." %
                        curFile)
                    continue

                self.LogInfo("Starting to map %s" % curFile)

                mappedFiles.add(os.path.basename(curFile))
                tempFileName = os.path.join(tempSceneDirectory,
                                            os.path.basename(curFile))

                foundFiles = self.map_vrscene_includes_cancelable(
                    curFile, tempFileName)
                newOriginDirectory = os.path.dirname(curFile)
                for foundFile in foundFiles:
                    filesToMap.append((foundFile, newOriginDirectory))

                map_files_and_replace_slashes(tempFileName, tempFileName)
                if self.IsCanceled():
                    self.FailRender(
                        "Received cancel task command from Deadline.")

        else:
            self.tempSceneFilename = sceneFilename

        self.tempSceneFilename = PathUtils.ToPlatformIndependentPath(
            self.tempSceneFilename)
    def RenderArgument(self):
        if SystemUtils.IsRunningOnLinux(
        ) and self.GetBooleanConfigEntryWithDefault("SetLinuxEnvironment",
                                                    True):
            c4dDir = os.path.dirname(self.C4DExe)
            ldPath = os.environ.get("LD_LIBRARY_PATH", "")
            pyPath = os.environ.get("PYTHONPATH", "")
            path = os.environ.get("PATH", "")

            modLdPath = "%s/../lib64:%s/resource/modules/python/Python.linux64.framework/lib64:%s/resource/modules/embree.module/libs/linux64:%s" % (
                c4dDir, c4dDir, c4dDir, ldPath)
            modPyPath = "%s/resource/modules/python/Python.linux64.framework/lib/python2.7:%s/resource/modules/python/Python.linux64.framework/lib64/python2.7/lib-dynload:%s" % (
                c4dDir, c4dDir, pyPath)
            modPath = "%s:%s" % (path, c4dDir)

            self.LogInfo("[LD_LIBRARY_PATH] set to %s" % modLdPath)
            self.LogInfo("[PYTHONPATH] set to %s" % modPyPath)
            self.LogInfo("[PATH] set to %s" % modPath)

            self.SetEnvironmentVariable("LD_LIBRARY_PATH", modLdPath)
            self.SetEnvironmentVariable("PYTHONPATH", modPyPath)
            self.SetEnvironmentVariable("PATH", modPath)

        sceneFile = self.GetPluginInfoEntryWithDefault("SceneFile",
                                                       self.GetDataFilename())
        sceneFile = RepositoryUtils.CheckPathMapping(sceneFile)
        sceneFile = self.ProcessPath(sceneFile)

        activeTake = self.GetPluginInfoEntryWithDefault("Take", "")
        argument = ["-nogui"]

        # NOTE: Negate the "No OpenGL" plugin info option from the monitor submitter to make the logic below
        # easier to read
        self.loadOpenGL = not self.GetBooleanPluginInfoEntryWithDefault(
            "NoOpenGL", False)

        # If the integrated submitter has specified a renderer other than Hardware OpenGL
        # we can skip loading OpenGL
        renderer = self.GetPluginInfoEntryWithDefault("Renderer", "")
        if self.loadOpenGL and renderer not in ("", "ogl_hardware"):
            self.loadOpenGL = False

        if not self.loadOpenGL:
            argument.append("-noopengl")

        exportJob = "Export" in renderer
        if not exportJob:
            argument.append('-render "%s"' % sceneFile)
            argument.append('-frame %s %s' %
                            (self.GetStartFrame(), self.GetEndFrame()))
            if self.GetBooleanPluginInfoEntryWithDefault(
                    "EnableFrameStep", False):
                argument.append(
                    self.GetPluginInfoEntryWithDefault("FrameStep", "2"))

            if activeTake and self.GetIntegerPluginInfoEntryWithDefault(
                    "Version", 17) >= 17:
                argument.append('-take "%s"' % activeTake)

            threads = self.GetNumThreads()
            if threads > 0:
                argument.append("-threads %s" % threads)

            width = self.GetIntegerPluginInfoEntryWithDefault("Width", 0)
            height = self.GetIntegerPluginInfoEntryWithDefault("Height", 0)
            if width and height:
                argument.append("-oresolution %s %s" % (width, height))

            selectedGPUs = self.GetGpuOverrides()
            if selectedGPUs:
                for gpu in selectedGPUs:
                    argument.append("-redshift-gpu %s" % gpu)

            self.LocalRendering = self.GetBooleanPluginInfoEntryWithDefault(
                "LocalRendering", False)
            # Build the output filename from the path and prefix
            filepath = self.GetPluginInfoEntryWithDefault("FilePath",
                                                          "").strip()
            filepath = RepositoryUtils.CheckPathMapping(filepath)
            if filepath:
                filepath = self.ProcessPath(filepath)

                if self.LocalRendering:
                    self.NetworkFilePath, postTokens = self.SplitTokens(
                        filepath)
                    self.ValidateFilepath(self.NetworkFilePath)

                    filepath = self.CreateTempDirectory("c4dOutput")
                    filepath = self.ProcessPath(filepath)

                    self.LocalFilePath = filepath
                    self.ValidateFilepath(self.LocalFilePath)

                    filepath = os.path.join(filepath, postTokens)
                    filepath = self.ProcessPath(filepath)

                    self.LogInfo(
                        "Rendering main output to local drive, will copy files and folders to final location after render is complete"
                    )
                else:
                    pathBeforeTokens, _ = self.SplitTokens(filepath)
                    self.ValidateFilepath(pathBeforeTokens)

                    self.LogInfo("Rendering main output to network drive")

                fileprefix = self.GetPluginInfoEntryWithDefault(
                    "FilePrefix", "").strip()
                argument.append('-oimage "%s"' %
                                os.path.join(filepath, fileprefix))

            # Build the multipass output filename from the path and prefix
            multifilepath = self.GetPluginInfoEntryWithDefault(
                "MultiFilePath", "").strip()
            multifilepath = RepositoryUtils.CheckPathMapping(multifilepath)
            if multifilepath:
                multifilepath = self.ProcessPath(multifilepath)

                if self.LocalRendering:
                    self.NetworkMPFilePath, postTokens = self.SplitTokens(
                        multifilepath)
                    self.ValidateFilepath(self.NetworkMPFilePath)

                    multifilepath = self.CreateTempDirectory("c4dOutputMP")
                    multifilepath = self.ProcessPath(multifilepath)

                    self.LocalMPFilePath = multifilepath
                    self.ValidateFilepath(self.LocalMPFilePath)

                    multifilepath = os.path.join(multifilepath, postTokens)
                    multifilepath = self.ProcessPath(multifilepath)

                    self.LogInfo(
                        "Rendering multipass output to local drive, will copy files and folders to final location after render is complete"
                    )
                else:
                    pathBeforeTokens, _ = self.SplitTokens(multifilepath)
                    self.ValidateFilepath(pathBeforeTokens)

                    self.LogInfo("Rendering multipass output to network drive")

                multifileprefix = self.GetPluginInfoEntryWithDefault(
                    "MultiFilePrefix", "").strip()
                argument.append('-omultipass "%s"' %
                                os.path.join(multifilepath, multifileprefix))

            redshiftLogVerbosity = self.GetConfigEntryWithDefault(
                "RedshiftLogging", "Debug")
            if redshiftLogVerbosity != "None":
                argument.append("-redshift-log-console %s" %
                                redshiftLogVerbosity)

        elif renderer == "ArnoldExport":
            if activeTake and self.GetIntegerPluginInfoEntryWithDefault(
                    "Version", 17) >= 17:
                argument.append('-take "%s"' % activeTake)

            argument.append('-arnoldAssExport')
            # Arnold needs the rest of its command-line args to be bundled together inside quotes for their export
            # so that they can parse them out from the string, without needing to add more actual command-line flags.
            arnoldExportArgs = ['scene=%s' % sceneFile]
            exportFile = self.ProcessPath(
                self.GetPluginInfoEntryWithDefault("ExportFile", ""))
            if exportFile:
                self.ValidateFilepath(os.path.dirname(exportFile))
                arnoldExportArgs.append("filename=%s" % exportFile)

            arnoldExportArgs.append('startFrame=%s' % self.GetStartFrame())
            arnoldExportArgs.append('endFrame=%s' % self.GetEndFrame())

            argument.append('"%s"' % ";".join(arnoldExportArgs))

        return " ".join(argument)
    def PostRenderTasks(self):
        failures = 0

        if self.FailWithoutFinishedMessage:
            if not self.RenderSuccess:  # fail here if Succeed didn't get tripped.
                self.FailAERender(
                    "The composition was not rendered completely. Found NO \"Finished Composition\" notice. To disable this failure if applicable, ensure 'Fail Without Finished Message' is set to False in AE plugin configuration."
                )

        myRePath = self.getAERenderOnlyFileName()
        self.CleanupRenderEngineFile(myRePath)

        # Clean up the temp file if we did path mapping on the aepx project file.
        if (os.path.splitext(self.TempSceneFilename)[1]
            ).lower() == ".aepx" and self.GetBooleanConfigEntryWithDefault(
                "EnableAepxPathMapping", True):
            os.remove(self.TempSceneFilename)

        if self.DelayedFailure:
            self.FailRender(
                "There was an error but the message could not properly be extracted\n"
                + self.FailureMessage)
        else:
            # Since the output option is only valid when rendering a specific comp, we will only check
            # the output size in this case.
            comp = self.GetPluginInfoEntryWithDefault("Comp", "")
            if comp and not self.MultiMachine:
                if self.LocalRendering:
                    self.LogInfo("Moving output files and folders from " +
                                 self.LocalFilePath + " to " +
                                 self.NetworkFilePath)
                    self.VerifyAndMoveDirectory(self.LocalFilePath,
                                                self.NetworkFilePath, True, 0)

                outputDirectories = self.GetJob().JobOutputDirectories
                outputFilenames = self.GetJob().JobOutputFileNames
                minSizeInKB = self.GetIntegerPluginInfoEntryWithDefault(
                    "MinFileSize", 0)
                deleteFilesUnderMinSize = self.GetBooleanPluginInfoEntryWithDefault(
                    "DeleteFilesUnderMinSize", False)

                for outputDirectory, outputFilename in zip(
                        outputDirectories, outputFilenames):
                    outputFile = os.path.join(outputDirectory, outputFilename)
                    outputFile = RepositoryUtils.CheckPathMapping(outputFile)
                    outputFile = PathUtils.ToPlatformIndependentPath(
                        outputFile)

                    if outputFile and minSizeInKB > 0:
                        if outputFile.find("#") >= 0:
                            frames = range(self.GetStartFrame(),
                                           self.GetEndFrame() + 1)
                            for frame in frames:
                                currFile = FrameUtils.ReplacePaddingWithFrameNumber(
                                    outputFile, frame)
                                failures += self.CheckFileSize(
                                    currFile, minSizeInKB,
                                    deleteFilesUnderMinSize)

                        else:
                            failures += self.CheckFileSize(
                                outputFile, minSizeInKB,
                                deleteFilesUnderMinSize)

                        if failures != 0:
                            self.FailRender(
                                "There were 1 or more errors with the output")
                    else:
                        self.SetProgress(100)
                        self.SetStatusMessage("Finished Rendering " +
                                              str(self.GetEndFrame() -
                                                  self.GetStartFrame() + 1) +
                                              " frames")
            else:
                self.LogInfo(
                    "Skipping output file size check because a specific comp isn't being rendered or Multi-Machine rendering is enabled"
                )
    def PreRenderTasks(self):
        self.FailureMessage = ""
        self.Framecount = 0
        self.PreviousFrameTime = ""

        # Reset Slave Status Message between Tasks.
        self.SetStatusMessage("")

        # Check if we should be doing path mapping.
        sceneFilename = RepositoryUtils.CheckPathMapping(
            self.GetPluginInfoEntryWithDefault("SceneFile",
                                               self.GetDataFilename()))

        if SystemUtils.IsRunningOnMac():
            sceneFilename = sceneFilename.replace("\\", "/")
        else:
            sceneFilename = sceneFilename.replace("/", "\\")

        # We can only do path mapping on .aepx files (they're xml files).
        if (os.path.splitext(sceneFilename)[1]
            ).lower() == ".aepx" and self.GetBooleanConfigEntryWithDefault(
                "EnableAepxPathMapping", True):
            self.LogInfo("Performing path mapping on aepx project file")

            tempSceneDirectory = self.CreateTempDirectory(
                "thread" + str(self.GetThreadNumber()))
            tempSceneFileName = os.path.basename(sceneFilename)
            self.TempSceneFilename = os.path.join(tempSceneDirectory,
                                                  tempSceneFileName)

            if SystemUtils.IsRunningOnMac():
                RepositoryUtils.CheckPathMappingInFileAndReplace(
                    sceneFilename, self.TempSceneFilename,
                    ("\\", "platform=\"Win\""), ("/", "platform=\"MacPOSIX\""))
                os.chmod(self.TempSceneFilename,
                         os.stat(sceneFilename).st_mode)
            else:
                RepositoryUtils.CheckPathMappingInFileAndReplace(
                    sceneFilename, self.TempSceneFilename,
                    ("/", "platform=\"MacPOSIX\"", "\\>"),
                    ("\\", "platform=\"Win\"", "/>"))
                if SystemUtils.IsRunningOnLinux():
                    os.chmod(self.TempSceneFilename,
                             os.stat(sceneFilename).st_mode)
        else:
            self.TempSceneFilename = sceneFilename

        self.TempSceneFilename = PathUtils.ToPlatformIndependentPath(
            self.TempSceneFilename)

        # Get the path to the text file that forces After Effects to run the English version.
        if SystemUtils.IsRunningOnMac():
            myDocumentsPath = os.path.join(
                Environment.GetFolderPath(Environment.SpecialFolder.Personal),
                "Documents/ae_force_english.txt")
        else:
            myDocumentsPath = os.path.join(
                Environment.GetFolderPath(Environment.SpecialFolder.Personal),
                "ae_force_english.txt")

        # Check if we want to change After Effects to the English version. If we do, create the file.
        if self.GetBooleanConfigEntryWithDefault("ForceRenderingEnglish",
                                                 False):
            try:
                self.LogInfo(
                    "Attempting to create \"%s\" to force After Effects to run in English"
                    % myDocumentsPath)
                open(myDocumentsPath, 'w').close()
            except:
                self.LogWarning("Failed to create \"%s\" because %s" %
                                (myDocumentsPath, traceback.format_exc()))
        else:
            # If we don't want to force the English version, delete the file.
            if os.path.isfile(myDocumentsPath):
                try:
                    self.LogInfo(
                        "Attempting to delete \"%s\" to allow After Effects to run in the user's original language"
                        % myDocumentsPath)
                    os.remove(myDocumentsPath)
                except:
                    self.LogWarning("Failed to delete \"%s\" because %s" %
                                    (myDocumentsPath, traceback.format_exc()))

        myRePath = self.getAERenderOnlyFileName()

        # Check if we want to start After Effects in render engine mode. If we do, create the file. And important delete it later.
        if self.GetBooleanConfigEntryWithDefault("ForceRenderEngine", False):
            try:
                self.LogInfo(
                    "Attempting to create \"%s\" to force After Effects to run in Render Engine mode"
                    % myRePath)
                open(myRePath, 'w').close()
            except:
                self.LogWarning("Failed to create \"%s\" because %s" %
                                (myRePath, traceback.format_exc()))
        else:
            if self.GetBooleanConfigEntryWithDefault("DeleteRenderEngineFile",
                                                     False):
                # If we don't want to force in Render Engine mode, delete the file.
                if os.path.isfile(myRePath):
                    try:
                        self.LogInfo(
                            "Attempting to delete \"%s\" to allow After Effects to run in the workstation environment"
                            % myDocumentsPath)
                        os.remove(myRePath)
                    except:
                        self.LogWarning("Failed to delete \"%s\" because %s" %
                                        (myRePath, traceback.format_exc()))
    def RenderArgument(self):
        version = int(self.GetFloatPluginInfoEntry("Version"))
        self.MultiMachine = self.GetBooleanPluginInfoEntryWithDefault(
            "MultiMachineMode", False)
        if self.MultiMachine:
            self.MultiMachineStartFrame = self.GetIntegerPluginInfoEntryWithDefault(
                "MultiMachineStartFrame", -1)
            self.MultiMachineEndFrame = self.GetIntegerPluginInfoEntryWithDefault(
                "MultiMachineEndFrame", -1)

        renderarguments = "-project \"" + self.TempSceneFilename + "\""

        # See if we're rendering a specific comp. The -s, -e, and -output options are only valid in this case.
        comp = self.GetPluginInfoEntryWithDefault("Comp", "")
        if comp != "":
            self.HandleProgress = True

            renderarguments += " -comp \"" + comp + "\""

            if self.MultiMachine:
                self.LogInfo("Multi Machine Mode enabled")
            else:
                renderarguments += " -s " + str(self.GetStartFrame())
                renderarguments += " -e " + str(self.GetEndFrame())

            self.LocalRendering = False
            outputFile = self.GetPluginInfoEntryWithDefault("Output",
                                                            "").strip()
            outputFile = RepositoryUtils.CheckPathMapping(outputFile)
            outputFile = PathUtils.ToPlatformIndependentPath(outputFile)

            if outputFile != "":
                outputDir = os.path.dirname(outputFile)
                self.NetworkFilePath = outputDir

                if not self.MultiMachine:
                    self.LocalRendering = self.GetBooleanPluginInfoEntryWithDefault(
                        "LocalRendering", False)

                    if self.LocalRendering:
                        outputDir = self.CreateTempDirectory(
                            "AfterEffectsOutput")
                        self.LocalFilePath = outputDir

                        outputFile = os.path.join(outputDir,
                                                  os.path.basename(outputFile))

                        self.LogInfo(
                            "Rendering to local drive, will copy files and folders to final location after render is complete"
                        )
                    else:
                        self.LogInfo("Rendering to network drive")

                if SystemUtils.IsRunningOnMac():
                    outputFile = outputFile.replace("\\", "/")
                else:
                    outputFile = outputFile.replace("/", "\\")

                self.ValidateFilepath(self.NetworkFilePath)

                renderarguments += " -output \"" + outputFile + "\""
        else:
            self.HandleProgress = False

        # Check if we should use the memory management flag.
        memoryManagementString = self.GetBooleanPluginInfoEntryWithDefault(
            "MemoryManagement", False)
        if memoryManagementString:
            imageCache = self.GetIntegerPluginInfoEntryWithDefault(
                "ImageCachePercentage", 0)
            maxMemory = self.GetIntegerPluginInfoEntryWithDefault(
                "MaxMemoryPercentage", 0)
            if imageCache > 0 and maxMemory > 0:
                renderarguments = renderarguments + " -mem_usage " + str(
                    imageCache) + " " + str(maxMemory)

        # Check if we should use the multi-process flag (AE 8 and later).
        multiProcessString = self.GetBooleanPluginInfoEntryWithDefault(
            "MultiProcess", False)
        if multiProcessString:
            renderarguments = renderarguments + " -mp"

        continueOnMissingFootage = self.GetBooleanPluginInfoEntryWithDefault(
            "ContinueOnMissingFootage", False)
        if version >= 9 and continueOnMissingFootage:
            self.LogInfo("Continuing on missing footage")
            renderarguments = renderarguments + " -continueOnMissingFootage"

        if self.GetBooleanPluginInfoEntryWithDefault(
                "IgnoreMissingEffectReferencesErrors", False):
            self.LogInfo("Ignoring missing effect reference errors")
        if self.GetBooleanPluginInfoEntryWithDefault(
                "IgnoreMissingLayerDependenciesErrors", False):
            self.LogInfo("Ignoring missing layer dependency errors")
        if self.GetBooleanPluginInfoEntryWithDefault("FailOnWarnings", False):
            self.LogInfo("Failing on warning messages")

        # Ensure we always enforce StdOut/Err/render progress to be generated.
        if version >= 9:
            renderarguments += " -v ERRORS_AND_PROGRESS"

        renderarguments += " -close DO_NOT_SAVE_CHANGES"
        renderarguments += " -sound OFF"

        return renderarguments