1 /*******************************************************************************
2 * processrenderoptions.cpp
3 *
4 * ---------------------------------------------------------------------------
5 * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
6 * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
7 *
8 * POV-Ray is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as
10 * published by the Free Software Foundation, either version 3 of the
11 * License, or (at your option) any later version.
12 *
13 * POV-Ray is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * ---------------------------------------------------------------------------
21 * POV-Ray is based on the popular DKB raytracer version 2.12.
22 * DKBTrace was originally written by David K. Buck.
23 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
24 * ---------------------------------------------------------------------------
25 * $File: //depot/public/povray/3.x/source/frontend/processrenderoptions.cpp $
26 * $Revision: #1 $
27 * $Change: 6069 $
28 * $DateTime: 2013/11/06 11:59:40 $
29 * $Author: chrisc $
30 *******************************************************************************/
31
32 #include <cctype>
33 #include <cstdlib>
34
35 // configbase.h must always be the first POV file included within base *.cpp files
36 #include "base/configbase.h"
37 #include "base/types.h"
38 #include "base/povmscpp.h"
39 #include "base/fileinputoutput.h"
40 #include "base/stringutilities.h"
41 #include "base/textstream.h"
42 #include "base/povms.h"
43 #include "base/povmsgid.h"
44 #include "base/pov_err.h"
45
46 #include "frontend/configfrontend.h"
47 #include "frontend/processrenderoptions.h"
48
49 // this must be the last file included
50 #include "base/povdebug.h"
51
52 namespace pov_frontend
53 {
54
55 using namespace pov_base;
56
57 /*****************************************************************************
58 * Local preprocessor defines
59 ******************************************************************************/
60
61 #define kUseSpecialHandler kPOVMSType_WildCard
62 #define kNoParameter kPOVMSType_Null
63
64 /*****************************************************************************
65 * Local variables
66 ******************************************************************************/
67
68 #ifdef SYS_HAS_GRAYSCALE
69 #define SYS_GRAYSCALE_FLAG true
70 #else // SYS_HAS_GRAYSCALE
71 #define SYS_GRAYSCALE_FLAG false
72 #endif // SYS_HAS_GRAYSCALE
73
74 #ifdef SYS_HAS_ALPHA
75 #define SYS_ALPHA_FLAG true
76 #else // SYS_HAS_ALPHA
77 #define SYS_ALPHA_FLAG false
78 #endif // SYS_HAS_ALPHA
79
80 /*
81 Keyword table for the INI-file parser.
82 The parser converts the INI-file options into a POVMS object using
83 the specifications provided in this table. The first element is the
84 INI-file keyword, the second element is the POVMS object attribute
85 key, the third is the attribute type. Entries with a POVMS attribute
86 key of 0 are superceded options that will generate a warning that the
87 option no longer is supported and will generate an error in a later
88 (unspecified) version of POV.
89 */
90 struct ProcessOptions::INI_Parser_Table RenderOptions_INI_Table[] =
91 {
92 { "All_Console", kPOVAttrib_AllConsole, kPOVMSType_Bool },
93 { "All_File", kPOVAttrib_AllFile, kPOVMSType_UCS2String },
94 { "Antialias_Depth", kPOVAttrib_AntialiasDepth, kPOVMSType_Int },
95 { "Antialias", kPOVAttrib_Antialias, kPOVMSType_Bool },
96 { "Antialias_Threshold", kPOVAttrib_AntialiasThreshold, kPOVMSType_Float },
97 { "Antialias_Gamma", kPOVAttrib_AntialiasGamma, kPOVMSType_Float },
98 { "Append_File", kPOVAttrib_AppendConsoleFiles, kPOVMSType_Bool },
99
100 { "Bits_Per_Color", kPOVAttrib_BitsPerColor, kPOVMSType_Int },
101 { "Bits_Per_Colour", kPOVAttrib_BitsPerColor, kPOVMSType_Int },
102 { "Bounding", kPOVAttrib_Bounding, kPOVMSType_Bool },
103 { "Bounding_Method", kPOVAttrib_BoundingMethod, kPOVMSType_Int },
104 { "Bounding_Threshold", kPOVAttrib_BoundingThreshold, kPOVMSType_Int },
105 { "BSP_BaseAccessCost", kPOVAttrib_BSP_BaseAccessCost, kPOVMSType_Float },
106 { "BSP_ChildAccessCost", kPOVAttrib_BSP_ChildAccessCost,kPOVMSType_Float },
107 { "BSP_ISectCost", kPOVAttrib_BSP_ISectCost, kPOVMSType_Float },
108 { "BSP_MaxDepth", kPOVAttrib_BSP_MaxDepth, kPOVMSType_Int },
109 { "BSP_MissChance", kPOVAttrib_BSP_MissChance, kPOVMSType_Float },
110 { "Buffer_Output", 0, 0 },
111 { "Buffer_Size", 0, 0 },
112
113 { "Clock", kPOVAttrib_Clock, kPOVMSType_Float },
114 { "Clockless_Animation", kPOVAttrib_ClocklessAnimation, kPOVMSType_Bool },
115 { "Compression", kPOVAttrib_Compression, kPOVMSType_Int },
116 { "Continue_Trace", kPOVAttrib_ContinueTrace, kPOVMSType_Bool },
117 { "Create_Histogram", 0, 0 },
118 { "Create_Ini", kPOVAttrib_CreateIni, kPOVMSType_UCS2String },
119 { "Cyclic_Animation", kPOVAttrib_CyclicAnimation, kPOVMSType_Bool },
120
121 { "Debug_Console", kPOVAttrib_DebugConsole, kPOVMSType_Bool },
122 { "Debug_File", kPOVAttrib_DebugFile, kPOVMSType_UCS2String },
123 { "Declare", kPOVAttrib_Declare, kUseSpecialHandler },
124 { "Display", kPOVAttrib_Display, kPOVMSType_Bool },
125 { "Display_Gamma", kPOVAttrib_DisplayGamma, kUseSpecialHandler },
126 { "Dither", kPOVAttrib_Dither, kPOVMSType_Bool },
127 { "Dither_Method", kPOVAttrib_DitherMethod, kUseSpecialHandler },
128 { "Draw_Vistas", kPOVAttrib_DrawVistas, kPOVMSType_Bool },
129
130 { "End_Column", kPOVAttrib_Right, kPOVMSType_Float },
131 { "End_Row", kPOVAttrib_Bottom, kPOVMSType_Float },
132
133 { "Fatal_Console", kPOVAttrib_FatalConsole, kPOVMSType_Bool },
134 { "Fatal_Error_Command", kPOVAttrib_FatalErrorCommand, kUseSpecialHandler },
135 { "Fatal_Error_Return", kPOVAttrib_FatalErrorCommand, kUseSpecialHandler },
136 { "Fatal_File", kPOVAttrib_FatalFile, kPOVMSType_UCS2String },
137 { "Field_Render", kPOVAttrib_FieldRender, kPOVMSType_Bool },
138 { "File_Gamma", kPOVAttrib_FileGamma, kUseSpecialHandler },
139 { "Final_Clock", kPOVAttrib_FinalClock, kPOVMSType_Float },
140 { "Final_Frame", kPOVAttrib_FinalFrame, kPOVMSType_Int },
141 { "Frame_Step", kPOVAttrib_FrameStep, kPOVMSType_Int },
142
143 { "Grayscale_Output", kPOVAttrib_GrayscaleOutput, kPOVMSType_Bool },
144
145 { "Height", kPOVAttrib_Height, kPOVMSType_Int },
146 { "High_Reproducibility",kPOVAttrib_HighReproducibility,kPOVMSType_Bool },
147 { "Histogram_Name", 0, 0 },
148 { "Histogram_Grid_Size", 0, 0 },
149 { "Histogram_Type", 0, 0 },
150
151 { "Initial_Clock", kPOVAttrib_InitialClock, kPOVMSType_Float },
152 { "Initial_Frame", kPOVAttrib_InitialFrame, kPOVMSType_Int },
153 { "Input_File_Name", kPOVAttrib_InputFile, kPOVMSType_UCS2String },
154 { "Include_Header", kPOVAttrib_IncludeHeader, kPOVMSType_UCS2String },
155 { "Include_Ini", kPOVAttrib_IncludeIni, kUseSpecialHandler },
156
157 { "Jitter_Amount", kPOVAttrib_JitterAmount, kPOVMSType_Float },
158 { "Jitter", kPOVAttrib_Jitter, kPOVMSType_Bool },
159
160 { "Library_Path", kPOVAttrib_LibraryPath, kUseSpecialHandler },
161 { "Light_Buffer", kPOVAttrib_LightBuffer, kPOVMSType_Bool },
162
163 { "Max_Image_Buffer_Memory", kPOVAttrib_MaxImageBufferMem, kPOVMSType_Int },
164
165 { "Odd_Field", kPOVAttrib_OddField, kPOVMSType_Bool },
166 { "Output_Alpha", kPOVAttrib_OutputAlpha, kPOVMSType_Bool },
167 { "Output_File_Name", kPOVAttrib_OutputFile, kPOVMSType_UCS2String },
168 { "Output_File_Type", kPOVAttrib_OutputFileType, kUseSpecialHandler },
169 { "Output_To_File", kPOVAttrib_OutputToFile, kPOVMSType_Bool },
170
171 { "Palette", kPOVAttrib_Palette, kUseSpecialHandler },
172 { "Pause_When_Done", kPOVAttrib_PauseWhenDone, kPOVMSType_Bool },
173 { "Post_Frame_Command", kPOVAttrib_PostFrameCommand, kUseSpecialHandler },
174 { "Post_Frame_Return", kPOVAttrib_PostFrameCommand, kUseSpecialHandler },
175 { "Post_Scene_Command", kPOVAttrib_PostSceneCommand, kUseSpecialHandler },
176 { "Post_Scene_Return", kPOVAttrib_PostSceneCommand, kUseSpecialHandler },
177 { "Preview_End_Size", kPOVAttrib_PreviewEndSize, kPOVMSType_Int },
178 { "Preview_Start_Size", kPOVAttrib_PreviewStartSize, kPOVMSType_Int },
179 { "Pre_Frame_Command", kPOVAttrib_PreFrameCommand, kUseSpecialHandler },
180 { "Pre_Frame_Return", kPOVAttrib_PreFrameCommand, kUseSpecialHandler },
181 { "Pre_Scene_Command", kPOVAttrib_PreSceneCommand, kUseSpecialHandler },
182 { "Pre_Scene_Return", kPOVAttrib_PreSceneCommand, kUseSpecialHandler },
183
184 { "Quality", kPOVAttrib_Quality, kPOVMSType_Int },
185
186 { "Radiosity_File_Name", kPOVAttrib_RadiosityFileName, kPOVMSType_UCS2String },
187 { "Radiosity_From_File", kPOVAttrib_RadiosityFromFile, kPOVMSType_Bool },
188 { "Radiosity_To_File", kPOVAttrib_RadiosityToFile, kPOVMSType_Bool },
189 { "Radiosity_Vain_Pretrace", kPOVAttrib_RadiosityVainPretrace, kPOVMSType_Bool },
190 { "Real_Time_Raytracing",kPOVAttrib_RealTimeRaytracing, kPOVMSType_Bool },
191 { "Remove_Bounds", kPOVAttrib_RemoveBounds, kPOVMSType_Bool },
192 { "Render_Block_Size", kPOVAttrib_RenderBlockSize, kPOVMSType_Int },
193 { "Render_Block_Step", kPOVAttrib_RenderBlockStep, kPOVMSType_Int },
194 { "Render_Console", kPOVAttrib_RenderConsole, kPOVMSType_Bool },
195 { "Render_File", kPOVAttrib_RenderFile, kPOVMSType_UCS2String },
196 { "Render_Pattern", kPOVAttrib_RenderPattern, kPOVMSType_Int },
197
198 { "Sampling_Method", kPOVAttrib_SamplingMethod, kPOVMSType_Int },
199 { "Split_Unions", kPOVAttrib_SplitUnions, kPOVMSType_Bool },
200 { "Start_Column", kPOVAttrib_Left, kPOVMSType_Float },
201 { "Start_Row", kPOVAttrib_Top, kPOVMSType_Float },
202 { "Statistic_Console", kPOVAttrib_StatisticsConsole, kPOVMSType_Bool },
203 { "Statistic_File", kPOVAttrib_StatisticsFile, kPOVMSType_UCS2String },
204 { "Subset_End_Frame", kPOVAttrib_SubsetEndFrame, kPOVMSType_Float },
205 { "Subset_Start_Frame", kPOVAttrib_SubsetStartFrame, kPOVMSType_Float },
206
207 { "Test_Abort_Count", kPOVAttrib_TestAbortCount, kPOVMSType_Int },
208 { "Test_Abort", kPOVAttrib_TestAbort, kPOVMSType_Bool },
209
210 { "User_Abort_Command", kPOVAttrib_UserAbortCommand, kUseSpecialHandler },
211 { "User_Abort_Return", kPOVAttrib_UserAbortCommand, kUseSpecialHandler },
212
213 { "Verbose", kPOVAttrib_Verbose, kPOVMSType_Bool },
214 { "Version", kPOVAttrib_Version, kPOVMSType_Float },
215 { "Video_Mode", kPOVAttrib_VideoMode, kUseSpecialHandler },
216 { "Vista_Buffer", kPOVAttrib_VistaBuffer, kPOVMSType_Bool },
217
218 { "Warning_Console", kPOVAttrib_WarningConsole, kPOVMSType_Bool },
219 { "Warning_File", kPOVAttrib_WarningFile, kPOVMSType_UCS2String },
220 { "Warning_Level", kPOVAttrib_WarningLevel, kPOVMSType_Int },
221 { "Width", kPOVAttrib_Width, kPOVMSType_Int },
222 { "Work_Threads", kPOVAttrib_MaxRenderThreads, kPOVMSType_Int },
223
224 { NULL, 0, 0 }
225 };
226
227 /*
228 Keyword table for the command line parser.
229 The parser converts the command line options into a POVMS object using
230 the specifications provided in this table. The first element is the
231 command keyword, the second element is the POVMS object attribute key
232 of the parameter, the third is the attribute type and the last specifies
233 if the +/- switch is used as boolean parameter if an attribute key is
234 provided.
235 */
236 struct ProcessOptions::Cmd_Parser_Table RenderOptions_Cmd_Table[] =
237 {
238 { "AG", kPOVAttrib_AntialiasGamma, kPOVMSType_Float, kNoParameter },
239 { "AM", kPOVAttrib_SamplingMethod, kPOVMSType_Int, kNoParameter },
240 { "A0", kPOVAttrib_AntialiasThreshold, kPOVMSType_Float, kPOVAttrib_Antialias },
241 { "A", kNoParameter, kNoParameter, kPOVAttrib_Antialias },
242
243 { "BM", kPOVAttrib_BoundingMethod, kPOVMSType_Int, kNoParameter },
244 { "BS", kPOVAttrib_RenderBlockSize, kPOVMSType_Int, kNoParameter },
245 { "B", kNoParameter, kNoParameter, kPOVAttrib_Bounding },
246
247 { "C", kNoParameter, kNoParameter, kPOVAttrib_ContinueTrace },
248
249 { "D", kPOVAttrib_Display, kUseSpecialHandler, kPOVAttrib_Display },
250 { "D", kNoParameter, kNoParameter, kPOVAttrib_Display },
251
252 { "EC", kPOVAttrib_Right, kPOVMSType_Float, kNoParameter },
253 { "EF0", kPOVAttrib_SubsetEndFrame, kPOVMSType_Float, kNoParameter },
254 { "EF", kPOVAttrib_SubsetEndFrame, kPOVMSType_Int, kNoParameter },
255 { "EP", kPOVAttrib_PreviewEndSize, kPOVMSType_Int, kNoParameter },
256 { "ER", kPOVAttrib_Bottom, kPOVMSType_Float, kNoParameter },
257
258 { "F", kPOVAttrib_OutputFileType, kUseSpecialHandler, kPOVAttrib_OutputToFile },
259 { "F", kNoParameter, kNoParameter, kPOVAttrib_OutputToFile },
260
261 { "GA", kPOVAttrib_AllFile, kPOVMSType_UCS2String, kPOVAttrib_AllConsole },
262 { "GA", kNoParameter, kNoParameter, kPOVAttrib_AllConsole },
263 { "GD", kPOVAttrib_DebugFile, kPOVMSType_UCS2String, kPOVAttrib_DebugConsole },
264 { "GD", kNoParameter, kNoParameter, kPOVAttrib_DebugConsole },
265 { "GF", kPOVAttrib_FatalFile, kPOVMSType_UCS2String, kPOVAttrib_FatalConsole },
266 { "GF", kNoParameter, kNoParameter, kPOVAttrib_FatalConsole },
267 { "GI", kPOVAttrib_CreateIni, kPOVMSType_UCS2String, kNoParameter },
268 { "GP", kNoParameter, kNoParameter, kPOVAttrib_AppendConsoleFiles },
269 { "GR", kPOVAttrib_RenderFile, kPOVMSType_UCS2String, kPOVAttrib_RenderConsole },
270 { "GR", kNoParameter, kNoParameter, kPOVAttrib_RenderConsole },
271 { "GS", kPOVAttrib_StatisticsFile, kPOVMSType_UCS2String, kPOVAttrib_StatisticsConsole },
272 { "GS", kNoParameter, kNoParameter, kPOVAttrib_StatisticsConsole },
273 { "GW", kPOVAttrib_WarningFile, kPOVMSType_UCS2String, kPOVAttrib_WarningConsole },
274 { "GW", kNoParameter, kNoParameter, kPOVAttrib_WarningConsole },
275
276 { "HI", kPOVAttrib_IncludeHeader, kPOVMSType_UCS2String, kNoParameter },
277 { "HR", kNoParameter, kNoParameter, kPOVAttrib_HighReproducibility },
278 { "H", kPOVAttrib_Height, kPOVMSType_Int, kNoParameter },
279
280 { "I", kPOVAttrib_InputFile, kPOVMSType_UCS2String, kNoParameter },
281
282 { "J", kPOVAttrib_JitterAmount, kPOVMSType_Float, kPOVAttrib_Jitter },
283 { "J", kNoParameter, kNoParameter, kPOVAttrib_Jitter },
284
285 { "KC", kNoParameter, kNoParameter, kPOVAttrib_CyclicAnimation },
286 { "KI", kPOVAttrib_InitialClock, kPOVMSType_Float, kNoParameter },
287 { "KFF", kPOVAttrib_FinalFrame, kPOVMSType_Int, kNoParameter },
288 { "KFI", kPOVAttrib_InitialFrame, kPOVMSType_Int, kNoParameter },
289 { "KF", kPOVAttrib_FinalClock, kPOVMSType_Float, kNoParameter },
290 { "KLA", kNoParameter, kNoParameter, kPOVAttrib_ClocklessAnimation },
291 { "K", kPOVAttrib_Clock, kPOVMSType_Float, kNoParameter },
292
293 { "L", kPOVAttrib_LibraryPath, kUseSpecialHandler, kNoParameter },
294
295 { "MB", kPOVAttrib_BoundingThreshold, kPOVMSType_Int, kPOVAttrib_Bounding },
296 { "MB", kNoParameter, kNoParameter, kPOVAttrib_Bounding },
297 { "MI", kPOVAttrib_MaxImageBufferMem, kPOVMSType_Int, kNoParameter },
298 { "MV", kPOVAttrib_Version, kPOVMSType_Float, kNoParameter },
299
300 { "O", kPOVAttrib_OutputFile, kPOVMSType_UCS2String, kNoParameter },
301
302 { "P", kNoParameter, kNoParameter, kPOVAttrib_PauseWhenDone },
303
304 { "Q", kPOVAttrib_Quality, kPOVMSType_Int, kNoParameter },
305
306 { "RFI", kNoParameter, kNoParameter, kPOVAttrib_RadiosityFromFile },
307 { "RFO", kNoParameter, kNoParameter, kPOVAttrib_RadiosityToFile },
308 { "RF", kPOVAttrib_RadiosityFileName, kPOVMSType_UCS2String, kNoParameter },
309 { "RS", kPOVAttrib_RenderBlockStep, kPOVMSType_Int, kNoParameter },
310 { "RP", kPOVAttrib_RenderPattern, kPOVMSType_Int, kNoParameter },
311 { "RTR", kNoParameter, kNoParameter, kPOVAttrib_RealTimeRaytracing },
312 { "RVP", kNoParameter, kNoParameter, kPOVAttrib_RadiosityVainPretrace },
313 { "R", kPOVAttrib_AntialiasDepth, kPOVMSType_Int, kNoParameter },
314
315 { "SC", kPOVAttrib_Left, kPOVMSType_Float, kNoParameter },
316 { "SF0", kPOVAttrib_SubsetStartFrame, kPOVMSType_Float, kNoParameter },
317 { "SF", kPOVAttrib_SubsetStartFrame, kPOVMSType_Int, kNoParameter },
318 { "SP", kPOVAttrib_PreviewStartSize, kPOVMSType_Int, kNoParameter },
319 { "SR", kPOVAttrib_Top, kPOVMSType_Float, kNoParameter },
320 { "STP", kPOVAttrib_FrameStep, kPOVMSType_Int, kNoParameter },
321 { "SU", kNoParameter, kNoParameter, kPOVAttrib_SplitUnions },
322
323 { "TH", kPOVAttrib_DitherMethod, kUseSpecialHandler, kPOVAttrib_Dither },
324 { "TH", kNoParameter, kNoParameter, kPOVAttrib_Dither },
325
326 { "UA", kNoParameter, kNoParameter, kPOVAttrib_OutputAlpha },
327 { "UD", kNoParameter, kNoParameter, kPOVAttrib_DrawVistas },
328 { "UF", kNoParameter, kNoParameter, kPOVAttrib_FieldRender },
329 { "UL", kNoParameter, kNoParameter, kPOVAttrib_LightBuffer },
330 { "UO", kNoParameter, kNoParameter, kPOVAttrib_OddField },
331 { "UR", kNoParameter, kNoParameter, kPOVAttrib_RemoveBounds },
332 { "UV", kNoParameter, kNoParameter, kPOVAttrib_VistaBuffer },
333
334 { "V", kNoParameter, kNoParameter, kPOVAttrib_Verbose },
335
336 { "WL", kPOVAttrib_WarningLevel, kPOVMSType_Int, kNoParameter },
337 { "WT", kPOVAttrib_MaxRenderThreads, kPOVMSType_Int, kNoParameter },
338 { "W", kPOVAttrib_Width, kPOVMSType_Int, kNoParameter },
339
340 { "X", kPOVAttrib_TestAbortCount, kUseSpecialHandler, kPOVAttrib_TestAbort },
341 { "X", kNoParameter, kNoParameter, kPOVAttrib_TestAbort },
342
343 { NULL, 0, 0, 0 }
344 };
345
346 // TODO FIXME - The following are hacks of some sort, no idea what they are good for. They certainly use wrong types and probably contain other mistakes [trf]
347 extern struct ProcessRenderOptions::Parameter_Code_Table DitherMethodTable[];
348
ProcessRenderOptions()349 ProcessRenderOptions::ProcessRenderOptions() : ProcessOptions(RenderOptions_INI_Table, RenderOptions_Cmd_Table)
350 {
351 }
352
~ProcessRenderOptions()353 ProcessRenderOptions::~ProcessRenderOptions()
354 {
355 }
356
ReadSpecialOptionHandler(INI_Parser_Table * option,char * param,POVMSObjectPtr obj)357 int ProcessRenderOptions::ReadSpecialOptionHandler(INI_Parser_Table *option, char *param, POVMSObjectPtr obj)
358 {
359 POVMSAttributeList list;
360 double floatval = 0.0;
361 int intval = 0;
362 int intval2 = 0;
363 int err = kNoErr;
364
365 switch(option->key)
366 {
367 case kPOVAttrib_Palette:
368 case kPOVAttrib_VideoMode:
369 while(isspace(*param))
370 param++;
371 err = POVMSUtil_SetInt(obj, option->key, tolower(*param));
372 break;
373 case kPOVAttrib_DitherMethod:
374 while(isspace(*param))
375 param++;
376 err = ParseParameterCode(DitherMethodTable, param, &intval);
377 if (err == kNoErr)
378 err = POVMSUtil_SetInt(obj, option->key, intval);
379 else
380 ParseError("Unrecognized dither method '%s'.", param);
381 break;
382 case kPOVAttrib_OutputFileType:
383 while(isspace(*param))
384 param++;
385 err = ParseFileType(*param, option->key, &intval);
386 if (err == kNoErr)
387 err = POVMSUtil_SetInt(obj, option->key, intval);
388 break;
389 case kPOVAttrib_IncludeIni:
390 case kPOVAttrib_LibraryPath:
391 POVMSAttribute attr;
392
393 if(err == kNoErr)
394 {
395 // parse INI file (recursive)
396 if(option->key == kPOVAttrib_IncludeIni)
397 err = ParseFile(param, obj);
398
399 // create list if it isn't there
400 if(err == kNoErr)
401 {
402 if(POVMSObject_Exist(obj, option->key) == kFalseErr)
403 err = POVMSAttrList_New(&list);
404 else if(POVMSObject_Exist(obj, option->key) != kNoErr)
405 err = kObjectAccessErr;
406 else
407 err = POVMSObject_Get(obj, &list, option->key);
408 }
409 }
410 else
411 {
412 ParseError("File name or path parameter expected for option '%s', found '%s'.", option->keyword, param);
413 err = kParamErr;
414 }
415
416 // add path or file to list
417 if(err == kNoErr)
418 err = POVMSAttr_New(&attr);
419 if(err == kNoErr)
420 {
421 err = POVMSAttr_SetUTF8String(&attr, kPOVMSType_UCS2String, param);
422 if(err == kNoErr)
423 err = POVMSAttrList_Append(&list, &attr);
424 else
425 err = POVMSAttr_Delete(&attr);
426 }
427 if(err == kNoErr)
428 err = POVMSObject_Set(obj, &list, option->key);
429 break;
430 case kPOVAttrib_Declare:
431 POVMSObject decobj;
432
433 // create list if it isn't there
434 if(POVMSObject_Exist(obj, option->key) == kFalseErr)
435 err = POVMSAttrList_New(&list);
436 else if(POVMSObject_Exist(obj, option->key) != kNoErr)
437 err = kObjectAccessErr;
438 else
439 err = POVMSObject_Get(obj, &list, option->key);
440
441 // add value to list
442 if(err == kNoErr)
443 err = POVMSObject_New(&decobj, kPOVMSType_WildCard);
444 if(err == kNoErr)
445 {
446 char *ptr = NULL;
447
448 err = POVMSUtil_SetString(&decobj, kPOVAttrib_Identifier, strtok(param, "="));
449 if(err == kNoErr)
450 {
451 ptr = strtok(NULL, "");
452 if(ptr == NULL)
453 err = kParseErr;
454 }
455 if(err == kNoErr)
456 {
457 if(strchr(ptr, '"') != NULL)
458 {
459 ptr = strchr(ptr, '"') + 1;
460 strtok(ptr, "\"");
461 err = POVMSUtil_SetString(&decobj, kPOVAttrib_Value, ptr);
462 }
463 else
464 err = POVMSUtil_SetFloat(&decobj, kPOVAttrib_Value, std::atof(ptr));
465 }
466 if(err == kNoErr)
467 err = POVMSAttrList_Append(&list, &decobj);
468 else
469 err = POVMSObject_Delete(&decobj);
470 }
471 if(err == kNoErr)
472 err = POVMSObject_Set(obj, &list, option->key);
473 break;
474 case kPOVAttrib_FatalErrorCommand:
475 case kPOVAttrib_PostFrameCommand:
476 case kPOVAttrib_PostSceneCommand:
477 case kPOVAttrib_PreFrameCommand:
478 case kPOVAttrib_PreSceneCommand:
479 case kPOVAttrib_UserAbortCommand:
480 POVMSObject cmdobj;
481
482 if(POVMSObject_Exist(obj, option->key) == kNoErr)
483 err = POVMSObject_Get(obj, &cmdobj, option->key);
484 else
485 err = POVMSObject_New(&cmdobj, kPOVMSType_WildCard);
486 if(toupper(*(option->keyword + strlen(option->keyword) - 1)) == 'D')
487 {
488 if(err == kNoErr)
489 err = POVMSUtil_SetString(&cmdobj, kPOVAttrib_CommandString, param);
490 }
491 else
492 {
493 if(err == kNoErr)
494 {
495 int i = 0;
496
497 if((*param == '-') || (*param == '!'))
498 i = toupper(*(param + 1)); // use upper-case to indicate negation of process result
499 else
500 i = tolower(*param); // lower-case for normal interpretation of process result
501 err = POVMSUtil_SetInt(&cmdobj, kPOVAttrib_ReturnAction, i);
502 }
503 }
504 if(err == kNoErr)
505 err = POVMSObject_Set(obj, &cmdobj, option->key);
506 break;
507 case kPOVAttrib_AntialiasGamma:
508 case kPOVAttrib_DisplayGamma:
509 case kPOVAttrib_FileGamma:
510 POVMSType typeKey;
511 switch (option->key)
512 {
513 case kPOVAttrib_AntialiasGamma: typeKey = kPOVAttrib_AntialiasGammaType; break;
514 case kPOVAttrib_DisplayGamma: typeKey = kPOVAttrib_DisplayGammaType; break;
515 case kPOVAttrib_FileGamma: typeKey = kPOVAttrib_FileGammaType; break;
516 }
517 floatval = std::atof(param);
518 if (floatval == 1.0)
519 intval = kPOVList_GammaType_Neutral;
520 else if (floatval > 0)
521 intval = kPOVList_GammaType_PowerLaw;
522 else
523 err = ParseGammaType(param, &intval);
524
525 if (err == kNoErr)
526 err = POVMSUtil_SetFloat(obj, option->key, fabs(floatval));
527 if (err == kNoErr)
528 err = POVMSUtil_SetInt(obj, typeKey, intval);
529 break;
530 }
531
532 return err;
533 }
534
ReadSpecialSwitchHandler(Cmd_Parser_Table * option,char * param,POVMSObjectPtr obj,bool)535 int ProcessRenderOptions::ReadSpecialSwitchHandler(Cmd_Parser_Table *option, char *param, POVMSObjectPtr obj, bool)
536 {
537 int intval = 0;
538 int intval2 = 0;
539 int err = 0;
540 char chr = 0;
541 char file_type;
542 bool has16BitGrayscale;
543
544 switch(option->key)
545 {
546 case kPOVAttrib_Display:
547 if(param[0] != '\0')
548 {
549 err = POVMSUtil_SetInt(obj, kPOVAttrib_VideoMode, (int)toupper(param[0]));
550 if((param[1] != '\0') && (err == 0))
551 err = POVMSUtil_SetInt(obj, kPOVAttrib_Palette, (int)toupper(param[1]));
552 }
553 break;
554 case kPOVAttrib_DitherMethod:
555 err = ParseParameterCode(DitherMethodTable, param, &intval);
556 if (err == kNoErr)
557 err = POVMSUtil_SetInt(obj, option->key, intval);
558 else
559 ParseError("Unrecognized dither method '%s'.", param);
560 break;
561 case kPOVAttrib_OutputFileType:
562 err = ParseFileType(*param, option->key, &intval, &has16BitGrayscale);
563 if (err == kNoErr)
564 {
565 err = POVMSUtil_SetInt(obj, option->key, intval);
566 file_type = *param++;
567 }
568 if ((err == kNoErr) && (*param > ' '))
569 {
570 if (tolower(*param) == 'g')
571 {
572 if(!has16BitGrayscale)
573 {
574 ParseError("Grayscale not currently supported with output file format '%c'.", file_type);
575 err = kParamErr;
576 }
577 else
578 {
579 if ((err = POVMSUtil_SetBool(obj, kPOVAttrib_GrayscaleOutput, true)) == kNoErr && *++param > ' ')
580 {
581 ParseError("Unexpected '%s' following grayscale flag in +F%c option.", param, file_type);
582 err = kParamErr;
583 }
584 }
585 }
586 else if (isdigit(*param) != 0)
587 {
588 if (sscanf(param, "%d%n", &intval, &intval2) == 1)
589 {
590 if ((err = POVMSUtil_SetInt(obj, kPOVAttrib_BitsPerColor, intval)) == kNoErr)
591 {
592 param += intval2;
593 if (*param > ' ')
594 {
595 ParseError("Unexpected '%s' following bits per color in +F%c option.", param, file_type);
596 err = kParamErr;
597 }
598 }
599 }
600 else
601 {
602 ParseError("Invalid bits per color '%s' found in +F%c option.", param, file_type);
603 err = kParamErr;
604 }
605 }
606 else
607 {
608 ParseError("Invalid modifier '%s' following +F%c option.", param, file_type);
609 err = kParamErr;
610 }
611 }
612 break;
613 case kPOVAttrib_LibraryPath:
614 POVMSAttributeList list;
615 POVMSAttribute attr;
616
617 if(err == kNoErr)
618 {
619 // create list if it isn't there
620 if(POVMSObject_Exist(obj, option->key) == kFalseErr)
621 err = POVMSAttrList_New(&list);
622 else if(POVMSObject_Exist(obj, option->key) != kNoErr)
623 err = kObjectAccessErr;
624 else
625 err = POVMSObject_Get(obj, &list, option->key);
626 }
627 else
628 {
629 ParseError("File name or path parameter expected for switch '%s', found '%s'.", option->command, param);
630 err = kParamErr;
631 }
632
633 // add path or file to list
634 if(err == kNoErr)
635 err = POVMSAttr_New(&attr);
636 if(err == kNoErr)
637 {
638 err = POVMSAttr_SetUTF8String(&attr, kPOVMSType_UCS2String, param);
639 if(err == kNoErr)
640 err = POVMSAttrList_Append(&list, &attr);
641 else
642 err = POVMSAttr_Delete(&attr);
643 }
644 if(err == kNoErr)
645 err = POVMSObject_Set(obj, &list, option->key);
646 break;
647 case kPOVAttrib_TestAbortCount:
648 if((*param) == 0)
649 break;
650 if(sscanf(param, "%d", &intval) == 1)
651 err = POVMSUtil_SetInt(obj, option->key, intval);
652 else
653 {
654 ParseError("No or integer parameter expected for switch '%s', found '%s'.", option->command, param);
655 err = kParamErr;
656 }
657 break;
658 }
659
660 return err;
661 }
662
WriteSpecialOptionHandler(INI_Parser_Table * option,POVMSObjectPtr obj,OTextStream * file)663 int ProcessRenderOptions::WriteSpecialOptionHandler(INI_Parser_Table *option, POVMSObjectPtr obj, OTextStream *file)
664 {
665 POVMSAttributeList list;
666 POVMSFloat floatval;
667 POVMSInt intval;
668 int err = 0;
669 int l;
670 int i,imax;
671 POVMSAttribute item;
672 char *bufptr;
673 char chr;
674
675 switch(option->key)
676 {
677 case kPOVAttrib_Palette:
678 case kPOVAttrib_VideoMode:
679 if(POVMSUtil_GetInt(obj, option->key, &intval) == 0)
680 {
681 chr = intval;
682 if(chr > 32)
683 file->printf("%s=%c\n", option->keyword, chr);
684 }
685 break;
686 case kPOVAttrib_OutputFileType:
687 if(POVMSUtil_GetInt(obj, option->key, &intval) == 0)
688 {
689 chr = UnparseFileType(intval);
690 if(chr > 32)
691 file->printf("%s=%c\n", option->keyword, chr);
692 }
693 break;
694 case kPOVAttrib_IncludeIni:
695 break;
696 case kPOVAttrib_Declare:
697 POVMSObject decobj;
698
699 err = POVMSObject_Get(obj, &list, option->key);
700 if(err != 0)
701 break;
702
703 l = 0;
704 err = POVMSAttrList_Count(&list, &l);
705 if(err != 0)
706 break;
707 if(l == 0)
708 break;
709
710 imax = l;
711 for(i = 1; i <= imax; i++)
712 {
713 err = POVMSAttrList_GetNth(&list, i, &decobj);
714 if(err == 0)
715 err = POVMSObject_Get(&decobj, &item, kPOVAttrib_Identifier);
716 if(err == 0)
717 {
718 l = 0;
719 err = POVMSAttr_Size(&item, &l);
720 if(l > 0)
721 {
722 bufptr = new char[l];
723 bufptr[0] = 0;
724 if((POVMSUtil_GetFloat(&decobj, kPOVAttrib_Value, &floatval) == 0) &&
725 (POVMSAttr_Get(&item, kPOVMSType_CString, bufptr, &l) == 0))
726 file->printf("%s=%s=%g\n", option->keyword, bufptr, (float)floatval);
727 delete[] bufptr;
728 }
729 (void)POVMSAttr_Delete(&item);
730 }
731 }
732 break;
733 case kPOVAttrib_LibraryPath:
734 err = POVMSObject_Get(obj, &list, option->key);
735 if(err != 0)
736 break;
737
738 l = 0;
739 err = POVMSAttrList_Count(&list, &l);
740 if(err != 0)
741 break;
742 if(l == 0)
743 break;
744
745 imax = l;
746 for(i = 1; i <= imax; i++)
747 {
748 err = POVMSAttrList_GetNth(&list, i, &item);
749 if(err == 0)
750 {
751 l = 0;
752 err = POVMSAttr_Size(&item, &l);
753 if(l > 0)
754 {
755 bufptr = new char[l * 3];
756 bufptr[0] = 0;
757 if(POVMSAttr_GetUTF8String(&item, kPOVMSType_UCS2String, bufptr, &l) == 0)
758 file->printf("%s=\"%s\"\n", option->keyword, bufptr);
759 delete[] bufptr;
760 }
761 (void)POVMSAttr_Delete(&item);
762 }
763 }
764 break;
765 case kPOVAttrib_FatalErrorCommand:
766 case kPOVAttrib_PostFrameCommand:
767 case kPOVAttrib_PostSceneCommand:
768 case kPOVAttrib_PreFrameCommand:
769 case kPOVAttrib_PreSceneCommand:
770 case kPOVAttrib_UserAbortCommand:
771 POVMSObject cmdobj;
772
773 err = POVMSObject_Get(obj, &cmdobj, option->key);
774 if(err != 0)
775 break;
776
777 err = POVMSObject_Get(&cmdobj, &item, kPOVAttrib_CommandString);
778 if(err == 0)
779 {
780 if(toupper(*(option->keyword + strlen(option->keyword) - 1)) == 'D')
781 {
782 l = 0;
783 err = POVMSAttr_Size(&item, &l);
784 if(l > 0)
785 {
786 bufptr = new char[l];
787 bufptr[0] = 0;
788 if(POVMSAttr_Get(&item, kPOVMSType_CString, bufptr, &l) == 0)
789 file->printf("%s=%s\n", option->keyword, bufptr);
790 delete[] bufptr;
791 }
792 }
793 else
794 {
795 if(POVMSUtil_GetInt(&cmdobj, kPOVAttrib_ReturnAction, &intval) == 0)
796 {
797 if(intval < 0)
798 {
799 chr = -intval;
800 file->printf("%s=!%c\n", option->keyword, chr);
801 }
802 else
803 {
804 chr = intval;
805 file->printf("%s=%c\n", option->keyword, chr);
806 }
807 }
808 }
809 }
810 if(err == 0)
811 err = POVMSObject_Delete(&cmdobj);
812 break;
813 }
814
815 return err;
816 }
817
WriteOptionFilter(INI_Parser_Table * table)818 bool ProcessRenderOptions::WriteOptionFilter(INI_Parser_Table *table)
819 {
820 // So that we don't get both Bits_Per_Color and Bits_Per_Colour in the INI file.
821 return (strcmp(table->keyword, "Bits_Per_Colour") != 0);
822 }
823
ProcessUnknownString(char * str,POVMSObjectPtr obj)824 int ProcessRenderOptions::ProcessUnknownString(char *str, POVMSObjectPtr obj)
825 {
826 POVMSAttributeList list;
827 POVMSAttribute attr;
828 int state = 0; // INI file
829 int err = kNoErr;
830
831 if(str == NULL)
832 {
833 ParseError("Expected filename, nothing was found.");
834 return kParamErr;
835 }
836
837 // add filename or path
838
839 // see if it is a POV file
840 if(state == 0)
841 {
842 char *ptr = strrchr(str, '.');
843 if(ptr != NULL)
844 {
845 if(pov_stricmp(ptr, ".pov") == 0)
846 state = 1; // POV file
847 }
848 }
849
850 // see if it is a path
851 if(state == 0)
852 {
853 if(strlen(str) > 0)
854 {
855 if(str[strlen(str) - 1] == POV_FILE_SEPARATOR)
856 state = 2; // library path
857 #ifdef POV_FILE_SEPARATOR_2
858 else if(str[strlen(str) - 1] == POV_FILE_SEPARATOR_2)
859 state = 2; // library path
860 #endif
861 }
862 }
863
864 switch(state)
865 {
866 // INI file
867 case 0:
868 // parse INI file (recursive)
869 err = ParseFile(str, obj);
870 if(err == kNoErr)
871 {
872 // create list if it isn't there
873 if(POVMSObject_Exist(obj, kPOVAttrib_IncludeIni) == kFalseErr)
874 err = POVMSAttrList_New(&list);
875 else if(POVMSObject_Exist(obj, kPOVAttrib_IncludeIni) != kNoErr)
876 err = kObjectAccessErr;
877 else
878 err = POVMSObject_Get(obj, &list, kPOVAttrib_IncludeIni);
879 }
880
881 // add INI file to list
882 if(err == kNoErr)
883 err = POVMSAttr_New(&attr);
884 if(err == kNoErr)
885 {
886 err = POVMSAttr_SetUTF8String(&attr, kPOVMSType_UCS2String, str);
887 if(err == kNoErr)
888 err = POVMSAttrList_Append(&list, &attr);
889 else
890 err = POVMSAttr_Delete(&attr);
891 }
892 if(err == kNoErr)
893 err = POVMSObject_Set(obj, &list, kPOVAttrib_IncludeIni);
894 break;
895 // POV file
896 case 1:
897 // set POV file
898 err = POVMSUtil_SetUTF8String(obj, kPOVAttrib_InputFile, str);
899 break;
900 // library path
901 case 2:
902 // create list if it isn't there
903 if(POVMSObject_Exist(obj, kPOVAttrib_LibraryPath) == kFalseErr)
904 err = POVMSAttrList_New(&list);
905 else if(POVMSObject_Exist(obj, kPOVAttrib_LibraryPath) != kNoErr)
906 err = kObjectAccessErr;
907 else
908 err = POVMSObject_Get(obj, &list, kPOVAttrib_LibraryPath);
909
910 // add library path to list
911 if(err == kNoErr)
912 err = POVMSAttr_New(&attr);
913 if(err == kNoErr)
914 {
915 err = POVMSAttr_SetUTF8String(&attr, kPOVMSType_UCS2String, str);
916 if(err == kNoErr)
917 err = POVMSAttrList_Append(&list, &attr);
918 else
919 err = POVMSAttr_Delete(&attr);
920 }
921 if(err == kNoErr)
922 err = POVMSObject_Set(obj, &list, kPOVAttrib_LibraryPath);
923 break;
924 }
925
926 return err;
927 }
928
OpenFileForRead(const char * filename,POVMSObjectPtr obj)929 ITextStream *ProcessRenderOptions::OpenFileForRead(const char *filename, POVMSObjectPtr obj)
930 {
931 return OpenINIFileStream(filename, pov_base::POV_File_Text_INI, obj);
932 }
933
OpenFileForWrite(const char * filename,POVMSObjectPtr)934 OTextStream *ProcessRenderOptions::OpenFileForWrite(const char *filename, POVMSObjectPtr)
935 {
936 return new OTextStream(ASCIItoUCS2String(filename).c_str(), pov_base::POV_File_Text_INI);
937 }
938
OpenINIFileStream(const char * filename,unsigned int stype,POVMSObjectPtr obj)939 ITextStream *ProcessRenderOptions::OpenINIFileStream(const char *filename, unsigned int stype, POVMSObjectPtr obj) // TODO FIXME - Use new Path class!
940 {
941 // TODO FIXME - we should join forces with SceneData::FindFile()
942 // TODO FIXME - use proper C++ strings instead of C character arrays
943
944 int i,ii,l[POV_FILE_EXTENSIONS_PER_TYPE];
945 char pathname[1024];
946 char file[1024];
947 char file_x[POV_FILE_EXTENSIONS_PER_TYPE][1024];
948 int cnt = 0;
949 int ll;
950 POVMSAttribute attr, item;
951 const char *xstr = strrchr(filename, '.');
952 bool hasextension = ((xstr != NULL) && (strlen(xstr) <= 4)); // TODO FIXME - we shouldn't rely on extensions being at most 1+3 chars long
953
954 if(POV_ALLOW_FILE_READ(ASCIItoUCS2String(filename).c_str(),stype) == 0) // TODO FIXME - Remove dependency on this macro!!! [trf]
955 return NULL;
956
957 for(i = 0; i < POV_FILE_EXTENSIONS_PER_TYPE; i++)
958 {
959 if((l[i] = strlen(pov::gPOV_File_Extensions[stype].ext[i])) > 0)
960 {
961 strcpy(file_x[i], filename);
962 strcat(file_x[i], pov::gPOV_File_Extensions[stype].ext[i]);
963 }
964 }
965
966 // Check the current directory first
967
968 if((hasextension == true) && (CheckIfFileExists(filename) == true))
969 {
970 return new ITextStream(ASCIItoUCS2String(filename).c_str(), stype);
971 }
972
973 for(i = 0; i < POV_FILE_EXTENSIONS_PER_TYPE; i++)
974 {
975 if(l[i])
976 {
977 if(CheckIfFileExists(file_x[i]) == true)
978 {
979 return new ITextStream(ASCIItoUCS2String(file_x[i]).c_str(), stype);
980 }
981 }
982 }
983
984 if(POVMSObject_Get(obj, &attr, kPOVAttrib_LibraryPath) != 0)
985 return NULL;
986
987 if(POVMSAttrList_Count(&attr, &cnt) != 0)
988 {
989 (void)POVMSAttrList_Delete(&attr);
990 return NULL;
991 }
992
993 for (i = 1; i <= cnt; i++)
994 {
995 (void)POVMSAttr_New(&item);
996 if(POVMSAttrList_GetNth(&attr, i, &item) != 0)
997 continue;
998 ll = 0;
999 if(POVMSAttr_Size(&item, &ll) != 0)
1000 {
1001 (void)POVMSAttr_Delete(&item);
1002 continue;
1003 }
1004 if(ll <= 0)
1005 {
1006 (void)POVMSAttr_Delete(&item);
1007 continue;
1008 }
1009 if(POVMSAttr_GetUTF8String(&item, kPOVMSType_UCS2String, file, &ll) != 0) // TODO FIXME!!!
1010 {
1011 (void)POVMSAttr_Delete(&item);
1012 continue;
1013 }
1014 (void)POVMSAttr_Delete(&item);
1015
1016 file[strlen(file)+1] = '\0';
1017 file[strlen(file)] = POV_FILE_SEPARATOR;
1018
1019 strcpy(pathname, file);
1020 strcat(pathname, filename);
1021 if((hasextension == true) && (CheckIfFileExists(pathname) == true))
1022 {
1023 (void)POVMSAttrList_Delete(&attr);
1024 return new ITextStream(ASCIItoUCS2String(pathname).c_str(), stype);
1025 }
1026
1027 for(ii = 0; ii < POV_FILE_EXTENSIONS_PER_TYPE; ii++)
1028 {
1029 if(l[ii])
1030 {
1031 strcpy(pathname, file);
1032 strcat(pathname, file_x[ii]);
1033 if(CheckIfFileExists(pathname) == true)
1034 {
1035 (void)POVMSAttrList_Delete(&attr);
1036 return new ITextStream(ASCIItoUCS2String(pathname).c_str(), stype);
1037 }
1038 }
1039 }
1040 }
1041
1042 (void)POVMSAttrList_Delete(&attr);
1043
1044 if(l[0])
1045 ParseError("Could not find file '%s%s'", filename, pov::gPOV_File_Extensions[stype].ext[0]);
1046 else
1047 ParseError("Could not find file '%s'", filename);
1048
1049 return NULL;
1050 }
1051
1052 // TODO - the following code might need reviewing, according to trf
1053
1054 /* Supported output file types */
1055 struct ProcessRenderOptions::Output_FileType_Table FileTypeTable[] =
1056 {
1057 // attribute-specific file types (must go first)
1058 // code, attribute, internalId, has16BitGrayscale hasAlpha
1059 // { 'C', kPOVAttrib_HistogramFileType, kPOVList_FileType_CSV, false, false },
1060
1061 // generic file types
1062 // code, attribute, internalId, has16BitGrayscale hasAlpha
1063 { 'T', 0, kPOVList_FileType_Targa, false, true },
1064 { 'C', 0, kPOVList_FileType_CompressedTarga, false, true },
1065 { 'N', 0, kPOVList_FileType_PNG, true, true },
1066 { 'J', 0, kPOVList_FileType_JPEG, false, false },
1067 { 'P', 0, kPOVList_FileType_PPM, true, false },
1068 { 'B', 0, kPOVList_FileType_BMP, false, false /*[1]*/ },
1069 { 'E', 0, kPOVList_FileType_OpenEXR, false /*[2]*/, true },
1070 { 'H', 0, kPOVList_FileType_RadianceHDR, false, false },
1071 #ifdef SYS_TO_STANDARD
1072 { 'S', 0, kPOVList_FileType_System, SYS_GRAYSCALE_FLAG, SYS_ALPHA_FLAG },
1073 #endif // SYS_TO_STANDARD
1074
1075 // [1] Alpha support for BMP uses an inofficial extension to the BMP file format, which is not recognized by
1076 // most image pocessing software.
1077
1078 // [2] While OpenEXR does support greyscale output at >8 bits, the variants currently supported by POV-Ray
1079 // use 16-bit floating-point values with 10 bit mantissa, which might be insufficient for various purposes
1080 // such as height fields.
1081
1082 // end-of-list marker
1083 { '\0', 0, 0, false }
1084 };
1085
1086 /* Supported special gamma types */
1087 struct ProcessRenderOptions::Parameter_Code_Table GammaTypeTable[] =
1088 {
1089
1090 // code, internalId,
1091 { "SRGB", kPOVList_GammaType_SRGB },
1092
1093 // end-of-list marker
1094 { NULL, 0 }
1095 };
1096
1097 /* Supported dither types */
1098 struct ProcessRenderOptions::Parameter_Code_Table DitherMethodTable[] =
1099 {
1100
1101 // code, internalId,
1102 { "B2", kPOVList_DitherMethod_Bayer2x2 },
1103 { "B3", kPOVList_DitherMethod_Bayer3x3 },
1104 { "B4", kPOVList_DitherMethod_Bayer4x4 },
1105 { "D1", kPOVList_DitherMethod_Diffusion1D },
1106 { "D2", kPOVList_DitherMethod_Diffusion2D },
1107 { "FS", kPOVList_DitherMethod_FloydSteinberg },
1108
1109 // end-of-list marker
1110 { NULL, 0 }
1111 };
1112
ParseFileType(char code,POVMSType attribute,int * pInternalId,bool * pHas16BitGreyscale)1113 int ProcessRenderOptions::ParseFileType(char code, POVMSType attribute, int* pInternalId, bool* pHas16BitGreyscale)
1114 {
1115 *pInternalId = kPOVList_FileType_Unknown;
1116 int err = kNoErr;
1117 for (int i = 0; FileTypeTable[i].code != '\0'; i ++)
1118 {
1119 if ( (toupper(code) == FileTypeTable[i].code) &&
1120 ((FileTypeTable[i].attribute == 0) || (FileTypeTable[i].attribute == attribute )) )
1121 {
1122 if (pHas16BitGreyscale != NULL)
1123 *pHas16BitGreyscale = FileTypeTable[i].has16BitGrayscale;
1124 *pInternalId = FileTypeTable[i].internalId;
1125 break;
1126 }
1127 }
1128 #ifdef OPENEXR_MISSING
1129 if (*pInternalId == kPOVList_FileType_OpenEXR)
1130 {
1131 ParseError(
1132 "This unofficial POV-Ray binary was built without support for the OpenEXR \
1133 file format. You must either use an official POV-Ray binary or recompile \
1134 the POV-Ray sources on a system providing you with the OpenEXR library \
1135 to make use of this facility. Alternatively, you may use any of the \
1136 following built-in formats: HDR."
1137 );
1138 err = kParamErr;
1139 }
1140 #endif // OPENEXR_MISSING
1141 if (*pInternalId == kPOVList_FileType_Unknown)
1142 {
1143 ParseError("Unrecognized output file format %c.", code);
1144 err = kParamErr;
1145 }
1146 return err;
1147 }
1148
UnparseFileType(int fileType)1149 char ProcessRenderOptions::UnparseFileType(int fileType)
1150 {
1151 for (int i = 0; FileTypeTable[i].code != '\0'; i ++)
1152 if (fileType == FileTypeTable[i].internalId)
1153 return FileTypeTable[i].code;
1154 return '\0';
1155 }
1156
ParseGammaType(char * code,int * pInternalId)1157 int ProcessRenderOptions::ParseGammaType(char* code, int* pInternalId)
1158 {
1159 *pInternalId = kPOVList_GammaType_Unknown;
1160 int err = ParseParameterCode(GammaTypeTable, code, pInternalId);
1161 if (err == kParamErr)
1162 ParseError("Unrecognized gamma setting '%s'.", code);
1163 return err;
1164 }
1165
UnparseGammaType(int gammaType)1166 const char* ProcessRenderOptions::UnparseGammaType(int gammaType)
1167 {
1168 return UnparseParameterCode(GammaTypeTable, gammaType);
1169 }
1170
ParseParameterCode(const ProcessRenderOptions::Parameter_Code_Table * codeTable,char * code,int * pInternalId)1171 int ProcessRenderOptions::ParseParameterCode(const ProcessRenderOptions::Parameter_Code_Table* codeTable, char* code, int* pInternalId)
1172 {
1173 for (int i = 0; code[i] != '\0'; i ++)
1174 code[i] = toupper(code[i]);
1175 for (int i = 0; codeTable[i].code != NULL; i ++)
1176 {
1177 if ( strcmp(code, codeTable[i].code) == 0 )
1178 {
1179 *pInternalId = codeTable[i].internalId;
1180 return kNoErr;
1181 }
1182 }
1183 return kParamErr;
1184 }
1185
UnparseParameterCode(const ProcessRenderOptions::Parameter_Code_Table * codeTable,int internalId)1186 const char* ProcessRenderOptions::UnparseParameterCode(const ProcessRenderOptions::Parameter_Code_Table* codeTable, int internalId)
1187 {
1188 for (int i = 0; codeTable[i].code != NULL; i ++)
1189 if (internalId == codeTable[i].internalId)
1190 return codeTable[i].code;
1191 return NULL;
1192 }
1193
1194 }
1195