Ejemplo n.º 1
0
def replaceSlashesByOS(value):
    if SystemUtils.IsRunningOnWindows():
        value = value.replace('/', '\\')
    else:
        value = value.replace("\\", "/")

    return value
Ejemplo n.º 2
0
def map_files_and_replace_slashes(inputFile, outputFile):
    if SystemUtils.IsRunningOnWindows():
        RepositoryUtils.CheckPathMappingInFileAndReplaceSeparator(
            inputFile, outputFile, "/", "\\")
    else:
        RepositoryUtils.CheckPathMappingInFileAndReplaceSeparator(
            inputFile, outputFile, "\\", "/")
        os.chmod(outputFile, os.stat(inputFile).st_mode)
 def ProcessPath(self, filepath):
     if SystemUtils.IsRunningOnWindows():
         filepath = filepath.replace("/", "\\")
         if filepath.startswith("\\") and not filepath.startswith("\\\\"):
             filepath = "\\" + filepath
     else:
         filepath = filepath.replace("\\", "/")
     return filepath
Ejemplo n.º 4
0
    def PopulatePath(self, *args):
        commandPath = ""

        self.LogMessage("Starting PreRender script")

        if SystemUtils.IsRunningOnMac():
            commandPath = self.GetConfigEntryWithDefault("MacOSPath", "")
        elif SystemUtils.IsRunningOnWindows():
            commandPath = self.GetConfigEntryWithDefault("WindowsPath", "")
        elif SystemUtils.IsRunningOnLinux():
            commandPath = self.GetConfigEntryWithDefault("LinuxPath", "")

        if commandPath == "":
            self.LogWarning("No command set")
        else:
            self.ExecuteScript(commandPath)

        self.LogMessage("PreRender script finished")
Ejemplo n.º 5
0
 def process_path(self, filepath):
     """Handle slashes in file paths."""
     if SystemUtils.IsRunningOnWindows():
         filepath = filepath.replace("/", "\\")
         if filepath.startswith("\\") and not filepath.startswith("\\\\"):
             filepath = "\\" + filepath
     else:
         filepath = filepath.replace("\\", "/")
     return filepath
Ejemplo n.º 6
0
    def map_vrscene_includes_cancelable(self, filename, outputfilename):
        vrsceneThread = map_vrscene_includes_threaded(filename, outputfilename)
        while not vrsceneThread.is_complete():
            SystemUtils.Sleep(1000)
            if self.IsCanceled():
                vrsceneThread.cancel()
            self.LogInfo("Mapping %s Include Directives: %02d%%" %
                         (filename, vrsceneThread.get_progress() * 100))

        return vrsceneThread.get_results()
    def getAERenderOnlyFileName(self):
        # Get the path to the text file that forces After Effects to run in Render Engine mode.
        outputPath = os.path.join(
            Environment.GetFolderPath(Environment.SpecialFolder.Personal),
            "ae_render_only_node.txt")
        if SystemUtils.IsRunningOnMac():
            outputPath = os.path.join(
                Environment.GetFolderPath(Environment.SpecialFolder.Personal),
                "Documents/ae_render_only_node.txt")

        return outputPath
Ejemplo n.º 8
0
    def pre_render_tasks(self):
        """Load config file and do remapping."""
        self.LogInfo("OpenPype Tile Assembler starting...")
        scene_filename = self.GetDataFilename()

        temp_scene_directory = self.CreateTempDirectory(
            "thread" + str(self.GetThreadNumber()))
        temp_scene_filename = Path.GetFileName(scene_filename)
        self.config_file = Path.Combine(temp_scene_directory,
                                        temp_scene_filename)

        if SystemUtils.IsRunningOnWindows():
            RepositoryUtils.CheckPathMappingInFileAndReplaceSeparator(
                scene_filename, self.config_file, "/", "\\")
        else:
            RepositoryUtils.CheckPathMappingInFileAndReplaceSeparator(
                scene_filename, self.config_file, "\\", "/")
            os.chmod(self.config_file, os.stat(self.config_file).st_mode)
Ejemplo 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("\\", "/")
    def RenderExecutable(self):
        version = self.GetIntegerPluginInfoEntryWithDefault("Version", 18)
        C4DExeList = self.GetConfigEntry("C4D_" + str(version) +
                                         "_RenderExecutable")

        build = self.GetPluginInfoEntryWithDefault("Build",
                                                   "None").lower().strip()

        if SystemUtils.IsRunningOnWindows():
            if build == "32bit":
                self.LogInfo("Enforcing 32 bit build of Cinema 4D")
                self.C4DExe = FileUtils.SearchFileListFor32Bit(C4DExeList)
                if self.C4DExe == "":
                    self.LogWarning(
                        "32 bit Cinema 4D " + str(version) +
                        " render executable was not found in the semicolon separated list \""
                        + C4DExeList +
                        "\".  Checking for any executable that exists instead."
                    )
            elif build == "64bit":
                self.LogInfo("Enforcing 64 bit build of Cinema 4D")
                self.C4DExe = FileUtils.SearchFileListFor64Bit(C4DExeList)
                if self.C4DExe == "":
                    self.LogWarning(
                        "64 bit Cinema 4D " + str(version) +
                        " render executable was not found in the semicolon separated list \""
                        + C4DExeList +
                        "\".  Checking for any executable that exists instead."
                    )

        if self.C4DExe == "":
            self.LogInfo("Not enforcing a build of Cinema 4D")
            self.C4DExe = FileUtils.SearchFileList(C4DExeList)
            if self.C4DExe == "":
                self.FailRender(
                    "Cinema 4D " + str(version) +
                    " render executable was not found in the semicolon separated list \""
                    + C4DExeList +
                    "\". The path to the render executable can be configured from the Plugin Configuration in the Deadline Monitor."
                )

        return self.C4DExe
Ejemplo n.º 11
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
    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
    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)