ShelloutAction::ShelloutAction(const ShelloutProcessing *sp, unsigned int attribID, POVMS_Object& opts): returnAction(ignore), returnNegate(false), isSet(false) { if (opts.Exist(attribID)) { POVMS_Object attr; opts.Get(attribID, attr); if (attr.Exist(kPOVAttrib_CommandString)) { rawCommand = attr.GetString(kPOVAttrib_CommandString); if (sp->ExtractCommand(rawCommand, command, rawParameters)) { int action = attr.TryGetInt(kPOVAttrib_ReturnAction, (int) ignore); switch (tolower(action)) { case ignore: case skipOne: case skipAll: case quit: case abort: case fatal: returnAction = (Action) tolower(action); returnNegate = isupper(action); isSet = true; break; default: break; } } } } }
// Sets the options to be used on the next render. Accepts a vfeRenderOptions // instance as its only parameter, and returns any one of a number of possible // error codes (and sets m_LastError), as documented below: // // vfeFailedToInitObject - this is an internal error // vfeFailedToSetMaxThreads - self-explanatory // vfeFailedToParseINI - an INI file specified could not be parsed // vfeFailedToSetSource - the source file specified could not be set // vfeFailedToParseCommand - a command-line option was invalid // vfeNoInputFile - no input file specified either directly or via INI // vfeRenderBlockSizeTooSmall - self-explanatory // vfeFailedToWriteINI - a request to write the render options to an INI file failed // vfeUnsupportedOptionCombination - unsupported option combination // // If vfeRenderOptions explicitly specifies a source file, it will override // any set via a parsed INI file. Furthermore, any source file set via a // command-line option overrides both of the above. // // Note that it is your responsibility to add any default INI files that should // be processed to the INI file list; neither SetOptions() nor any other part // of the VFE or POV-Ray code will do that for you. This includes non-platform // specific files such as a potential povray.ini in the CWD. int vfeSession::SetOptions (vfeRenderOptions& opts) { int err; UCS2 str [MAX_PATH]; POVMSObject obj; vfeProcessRenderOptions options(this); m_OutputToFileSet = false; m_UsingAlpha = false; m_RenderingAnimation = false; m_RealTimeRaytracing = false; m_ClocklessAnimation = false; m_RenderWidth = m_RenderHeight = 0; ClearOptions(); if ((err = POVMSObject_New (&obj, kPOVObjectClass_RenderOptions)) != kNoErr) return (m_LastError = vfeFailedToInitObject) ; if ((err = POVMSUtil_SetInt (&obj, kPOVAttrib_MaxRenderThreads, opts.m_ThreadCount)) != kNoErr) return (m_LastError = vfeFailedToSetMaxThreads) ; // we set this here for potential use by the IO permissions path checking code m_InputFilename = opts.m_SourceFile; // most likely povray.ini will be the first INI file processed here (as it's included by default) for (vector<UCS2String>::iterator i = opts.m_IniFiles.begin(); i != opts.m_IniFiles.end(); i++) { // we call TestAccessAllowed() here, even though ParseFile() will do it also, since if // access is denied, the reason will not be obvious (ParseFile() just returns kCannotOpenFileErr). if (!TestAccessAllowed (Path(*i), false)) return (m_LastError = vfeIORestrictionDeny); if ((err = options.ParseFile (UCS2toASCIIString(*i).c_str(), &obj)) != kNoErr) return (m_LastError = vfeFailedToParseINI) ; // we keep this up to date since the IO permissions feature will use the current input // filename to determine the path for default read/write permission in the scene dir. int n = sizeof (str) ; if ((err = POVMSUtil_GetUCS2String (&obj, kPOVAttrib_InputFile, str, &n)) == kNoErr) if (m_InputFilename != str) m_InputFilename = str; } // m_SourceFile overrides any source file set by the INI files if (opts.m_SourceFile.empty() == false) { m_InputFilename = opts.m_SourceFile; if ((err = POVMSUtil_SetUCS2String (&obj, kPOVAttrib_InputFile, opts.m_SourceFile.c_str())) != kNoErr) return (m_LastError = vfeFailedToSetSource); } // any source file set on the command-line overrides a source file set another way for (vector<string>::iterator i = opts.m_Commands.begin(); i != opts.m_Commands.end(); i++) { if ((err = options.ParseString (i->c_str(), &obj)) != kNoErr) return (m_LastError = vfeFailedToParseCommand) ; int n = sizeof (str) ; if ((err = POVMSUtil_GetUCS2String (&obj, kPOVAttrib_InputFile, str, &n)) == kNoErr) if (m_InputFilename != str) m_InputFilename = str; } int n = sizeof (str) ; if ((err = POVMSUtil_GetUCS2String (&obj, kPOVAttrib_InputFile, str, &n)) != kNoErr) return (m_LastError = vfeNoInputFile); m_InputFilename = str; POVMSUtil_GetInt (&obj, kPOVAttrib_Width, &m_RenderWidth) ; POVMSUtil_GetInt (&obj, kPOVAttrib_Height, &m_RenderHeight) ; std::list<Path> libpaths; POVMS_Object ropts (obj) ; if (ropts.Exist (kPOVAttrib_LibraryPath)) { POVMS_List pathlist; ropts.Get (kPOVAttrib_LibraryPath, pathlist) ; // we take the opportunity to remove any duplicates that are in the path list. // it's cleaner to do that here, rather than in the INI parser, since it's table- // driven and doesn't have an explicit function for adding library paths per se. // // we use the Path equivalence operator rather than a string compare since // using Path should handle platform-specific issues like case-sensitivity (or, // rather, lack thereof). note that at the time of writing, the Path class did // not yet implement case-insensitive comparisions. // // NB while it would of course be more efficient to sort the list so searches are // faster, we'd have to make a copy of it to do that, as we can't change the order // of existing entries (that would change the include path search order). it's not // common to have a lot of include paths, so we just use linear searches. for (int i = 1; i <= pathlist.GetListSize(); i++) { POVMS_Attribute lp; pathlist.GetNth(i, lp); Path path(lp.GetUCS2String()); if (find(libpaths.begin(), libpaths.end(), path) == libpaths.end()) libpaths.push_back(path); } } if (opts.m_LibraryPaths.empty() == false) { for (vector<UCS2String>::const_iterator i = opts.m_LibraryPaths.begin(); i != opts.m_LibraryPaths.end(); i++) { Path path(*i); if (find(libpaths.begin(), libpaths.end(), path) == libpaths.end()) libpaths.push_back(path); } } if (libpaths.empty() == false) { POVMS_List pathlist; for (list<Path>::iterator i = libpaths.begin(); i != libpaths.end(); i++) { POVMS_Attribute attr((*i)().c_str()); pathlist.Append(attr); } ropts.Set (kPOVAttrib_LibraryPath, pathlist) ; } if (ropts.TryGetBool(kPOVAttrib_RealTimeRaytracing, false) == true) ropts.SetBool(kPOVAttrib_OutputToFile, false); m_OutputToFileSet = ropts.TryGetBool(kPOVAttrib_OutputToFile, true); // this is a bit messy: Grayscale_Output or OutputAlpha may be specified // in an INI file or elsewhere prior to the output file type being set. // so we can't check to see if it is supported with that file type // until all options have been parsed. if (m_OutputToFileSet) { int oft = ropts.TryGetInt(kPOVAttrib_OutputFileType, DEFAULT_OUTPUT_FORMAT); bool has16BitGrayscale = false; bool hasAlpha = false; for (int i = 0; FileTypeTable[i].internalId != 0; i ++) { if (oft == FileTypeTable[i].internalId) { has16BitGrayscale = FileTypeTable[i].has16BitGrayscale; hasAlpha = FileTypeTable[i].hasAlpha; break; } } if (ropts.TryGetBool(kPOVAttrib_GrayscaleOutput, false) && !has16BitGrayscale) { AppendStatusMessage ("Grayscale output not currently supported with selected output file type."); AppendErrorMessage ("Grayscale output not currently supported with selected output file type.") ; return (m_LastError = vfeUnsupportedOptionCombination); } if (ropts.TryGetBool(kPOVAttrib_OutputAlpha, false) && !hasAlpha) { AppendWarningMessage ("Warning: Alpha channel output currently not (or not officially) supported with selected output file type.") ; } } if (ropts.TryGetInt(kPOVAttrib_RenderBlockSize, 32) < 4) return (m_LastError = vfeRenderBlockSizeTooSmall); if ((ropts.TryGetInt(kPOVAttrib_DisplayGammaType, DEFAULT_DISPLAY_GAMMA_TYPE) == kPOVList_GammaType_PowerLaw) && (ropts.TryGetFloat(kPOVAttrib_DisplayGamma, DEFAULT_DISPLAY_GAMMA) < 0.001f)) return (m_LastError = vfeDisplayGammaTooSmall); if ((ropts.TryGetInt(kPOVAttrib_FileGammaType, DEFAULT_FILE_GAMMA_TYPE) == kPOVList_GammaType_PowerLaw) && (ropts.TryGetFloat(kPOVAttrib_FileGamma, DEFAULT_FILE_GAMMA) < 0.001f)) return (m_LastError = vfeFileGammaTooSmall); n = sizeof (str) ; if ((err = POVMSUtil_GetUCS2String (&obj, kPOVAttrib_CreateIni, str, &n)) == kNoErr && str [0] != 0) if ((err = options.WriteFile (UCS2toASCIIString(str).c_str(), &obj)) != kNoErr) return (m_LastError = vfeFailedToWriteINI); opts.m_Options = ropts; m_RenderOptions = opts ; m_OptionsSet = true; return (m_LastError = vfeNoError) ; }
void Scene::StartParser(POVMS_Object& parseOptions) { size_t seed = 0; // TODO // A scene can only be parsed once if (parserControlThread == nullptr) parserControlThread = new std::thread(boost::bind(&Scene::ParserControlThread, this)); else return; if (parseOptions.Exist(kPOVAttrib_Version)) { sceneData->languageVersion = clip(int(parseOptions.GetFloat(kPOVAttrib_Version) * 100.0f + .5f), 100, 10000); sceneData->languageVersionSet = true; } sceneData->warningLevel = clip(parseOptions.TryGetInt(kPOVAttrib_WarningLevel, 9), 0, 9); sceneData->inputFile = parseOptions.TryGetUCS2String(kPOVAttrib_InputFile, "object.pov"); sceneData->headerFile = parseOptions.TryGetUCS2String(kPOVAttrib_IncludeHeader, ""); DBL outputWidth = parseOptions.TryGetFloat(kPOVAttrib_Width, 160); DBL outputHeight = parseOptions.TryGetFloat(kPOVAttrib_Height, 120); sceneData->aspectRatio = outputWidth / outputHeight; sceneData->defaultFileType = parseOptions.TryGetInt(kPOVAttrib_OutputFileType, DEFAULT_OUTPUT_FORMAT); // TODO - should get DEFAULT_OUTPUT_FORMAT from the front-end sceneData->clocklessAnimation = parseOptions.TryGetBool(kPOVAttrib_ClocklessAnimation, false); // TODO - experimental code sceneData->splitUnions = parseOptions.TryGetBool(kPOVAttrib_SplitUnions, false); sceneData->removeBounds = parseOptions.TryGetBool(kPOVAttrib_RemoveBounds, true); sceneData->boundingMethod = clip<int>(parseOptions.TryGetInt(kPOVAttrib_BoundingMethod, 1), 1, 2); if(parseOptions.TryGetBool(kPOVAttrib_Bounding, true) == false) sceneData->boundingMethod = 0; sceneData->outputAlpha = parseOptions.TryGetBool(kPOVAttrib_OutputAlpha, false); if (!sceneData->outputAlpha) // if we're not outputting an alpha channel, precompose the scene background against a black "background behind the background" // (NB: Here, background color is still at its default of <0,0,0,0,1> = full transparency; we're changing that to opaque black.) sceneData->backgroundColour.Clear(); // NB a value of '0' for any of the BSP parameters tells the BSP code to use its internal default sceneData->bspMaxDepth = parseOptions.TryGetInt(kPOVAttrib_BSP_MaxDepth, 0); sceneData->bspObjectIsectCost = clip<float>(parseOptions.TryGetFloat(kPOVAttrib_BSP_ISectCost, 0.0f), 0.0f, HUGE_VAL); sceneData->bspBaseAccessCost = clip<float>(parseOptions.TryGetFloat(kPOVAttrib_BSP_BaseAccessCost, 0.0f), 0.0f, HUGE_VAL); sceneData->bspChildAccessCost = clip<float>(parseOptions.TryGetFloat(kPOVAttrib_BSP_ChildAccessCost, 0.0f), 0.0f, HUGE_VAL); sceneData->bspMissChance = clip<float>(parseOptions.TryGetFloat(kPOVAttrib_BSP_MissChance, 0.0f), 0.0f, 1.0f - EPSILON); sceneData->realTimeRaytracing = parseOptions.TryGetBool(kPOVAttrib_RealTimeRaytracing, false); if(parseOptions.Exist(kPOVAttrib_Declare) == true) { POVMS_List ds; parseOptions.Get(kPOVAttrib_Declare, ds); for(int i = 1; i <= ds.GetListSize(); i++) { std::ostringstream sstr; POVMS_Attribute a; POVMS_Object d; ds.GetNth(i, d); d.Get(kPOVAttrib_Value, a); switch (a.Type()) { case kPOVMSType_CString: sstr << "\"" + d.TryGetString(kPOVAttrib_Value, "") + "\""; break; case kPOVMSType_Float: sstr << d.TryGetFloat(kPOVAttrib_Value, 0.0); break; default: // shouldn't happen unless we make a coding error throw POV_EXCEPTION(kParamErr, "Invalid type passed in declare list"); } sceneData->declaredVariables.insert(make_pair(d.GetString(kPOVAttrib_Identifier), sstr.str())); } } // do parsing sceneThreadData.push_back(dynamic_cast<TraceThreadData *>(parserTasks.AppendTask(new ParserTask( sceneData, pov_parser::ParserOptions(bool(parseOptions.Exist(kPOVAttrib_Clock)), parseOptions.TryGetFloat(kPOVAttrib_Clock, 0.0), seed) )))); // wait for parsing parserTasks.AppendSync(); // do bounding - we always call this even if the bounding is turned off // because it also generates object statistics sceneThreadData.push_back(dynamic_cast<TraceThreadData *>(parserTasks.AppendTask(new BoundingTask( sceneData, clip<int>(parseOptions.TryGetInt(kPOVAttrib_BoundingThreshold, DEFAULT_AUTO_BOUNDINGTHRESHOLD),1,SIGNED16_MAX), seed )))); // wait for bounding parserTasks.AppendSync(); // wait for bounding to finish parserTasks.AppendSync(); // send statistics parserTasks.AppendFunction(boost::bind(&Scene::SendStatistics, this, _1)); // send done message and compatibility data parserTasks.AppendFunction(boost::bind(&Scene::SendDoneMessage, this, _1)); }