1 //******************************************************************************
2 ///
3 /// @file frontend/renderfrontend.cpp
4 ///
5 /// @todo   What's in here?
6 ///
7 /// @copyright
8 /// @parblock
9 ///
10 /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
11 /// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
12 ///
13 /// POV-Ray is free software: you can redistribute it and/or modify
14 /// it under the terms of the GNU Affero General Public License as
15 /// published by the Free Software Foundation, either version 3 of the
16 /// License, or (at your option) any later version.
17 ///
18 /// POV-Ray is distributed in the hope that it will be useful,
19 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
20 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 /// GNU Affero General Public License for more details.
22 ///
23 /// You should have received a copy of the GNU Affero General Public License
24 /// along with this program.  If not, see <http://www.gnu.org/licenses/>.
25 ///
26 /// ----------------------------------------------------------------------------
27 ///
28 /// POV-Ray is based on the popular DKB raytracer version 2.12.
29 /// DKBTrace was originally written by David K. Buck.
30 /// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
31 ///
32 /// @endparblock
33 ///
34 //******************************************************************************
35 
36 // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config)
37 #include "frontend/renderfrontend.h"
38 
39 // Standard C++ header files
40 #include <memory>
41 
42 // POV-Ray header files (base module)
43 #include "base/platformbase.h"
44 #include "base/textstream.h"
45 #include "base/textstreambuffer.h"
46 #include "base/image/dither.h"
47 #include "base/image/encoding.h"
48 
49 // POV-Ray header files (POVMS module)
50 #include "povms/povmsid.h"
51 
52 // POV-Ray header files (frontend module)
53 #include "frontend/console.h"
54 #include "frontend/processoptions.h"
55 #include "frontend/processrenderoptions.h"
56 
57 // this must be the last file included
58 #include "base/povdebug.h"
59 
60 namespace pov_frontend
61 {
62 
63 const int gStreamTypeUtilDataCount = 6;
64 
65 static const POVMSType gStreamTypeUtilData[gStreamTypeUtilDataCount] =
66 {
67     kPOVAttrib_DebugFile,
68     kPOVAttrib_FatalFile,
69     kPOVAttrib_RenderFile,
70     kPOVAttrib_StatisticsFile,
71     kPOVAttrib_WarningFile,
72     kPOVAttrib_AllFile
73 };
74 
75 static const char *gStreamDefaultFile[gStreamTypeUtilDataCount] =
76 {
77     "debug.out",
78     "fatal.out",
79     "render.out",
80     "stats.out",
81     "warning.out",
82     "alltext.out"
83 };
84 
85 static const int gStreamNumber[gStreamTypeUtilDataCount] =
86 {
87     DEBUG_STREAM,
88     FATAL_STREAM,
89     RENDER_STREAM,
90     STATISTIC_STREAM,
91     WARNING_STREAM,
92     ALL_STREAM
93 };
94 
95 namespace Message2Console
96 {
97 
98 void InitInfo(POVMS_Object& cppmsg, TextStreamBuffer *tsb);
99 
100 void FileMessage(TextStreamBuffer *tsb, int stream, POVMSObjectPtr msg);
101 const char *GetOptionSwitchString(POVMSObjectPtr msg, POVMSType key, bool defaultstate);
102 
103 }
104 
105 class FileTextStreamBuffer : public TextStreamBuffer
106 {
107     public:
FileTextStreamBuffer(const UCS2 * filename,bool append)108         FileTextStreamBuffer(const UCS2 *filename, bool append) : stream(filename, POV_File_Text_Stream, append) { }
~FileTextStreamBuffer()109         virtual ~FileTextStreamBuffer() { flush(); stream.flush(); }
110     protected:
lineoutput(const char * str,unsigned int chars)111         virtual void lineoutput(const char *str, unsigned int chars) { stream.printf("%s\n", string(str, chars).c_str()); stream.flush(); }
112     private:
113         OTextStream stream;
114 };
115 
RenderFrontendBase(POVMSContext ctx)116 RenderFrontendBase::RenderFrontendBase(POVMSContext ctx) :
117     POVMS_MessageReceiver(ctx),
118     context(ctx)
119 {
120     InstallFront(kPOVMsgClass_BackendControl, kPOVMsgIdent_Failed, this, &RenderFrontendBase::HandleMessage);
121 
122     InstallFront(kPOVMsgClass_SceneOutput, kPOVMsgIdent_ParserStatistics, this, &RenderFrontendBase::HandleMessage);
123     InstallFront(kPOVMsgClass_SceneOutput, kPOVMsgIdent_Warning, this, &RenderFrontendBase::HandleMessage);
124     InstallFront(kPOVMsgClass_SceneOutput, kPOVMsgIdent_Error, this, &RenderFrontendBase::HandleMessage);
125     InstallFront(kPOVMsgClass_SceneOutput, kPOVMsgIdent_FatalError, this, &RenderFrontendBase::HandleMessage);
126     InstallFront(kPOVMsgClass_SceneOutput, kPOVMsgIdent_Debug, this, &RenderFrontendBase::HandleMessage);
127     InstallFront(kPOVMsgClass_SceneOutput, kPOVMsgIdent_Progress, this, &RenderFrontendBase::HandleMessage);
128     InstallFront(kPOVMsgClass_SceneOutput, kPOVMsgIdent_Done, this, &RenderFrontendBase::HandleMessage);
129     InstallFront(kPOVMsgClass_SceneOutput, kPOVMsgIdent_Failed, this, &RenderFrontendBase::HandleMessage);
130 
131     InstallFront(kPOVMsgClass_ViewOutput, kPOVMsgIdent_RenderStatistics, this, &RenderFrontendBase::HandleMessage);
132     InstallFront(kPOVMsgClass_ViewOutput, kPOVMsgIdent_Warning, this, &RenderFrontendBase::HandleMessage);
133     InstallFront(kPOVMsgClass_ViewOutput, kPOVMsgIdent_Error, this, &RenderFrontendBase::HandleMessage);
134     InstallFront(kPOVMsgClass_ViewOutput, kPOVMsgIdent_FatalError, this, &RenderFrontendBase::HandleMessage);
135     InstallFront(kPOVMsgClass_ViewOutput, kPOVMsgIdent_Debug, this, &RenderFrontendBase::HandleMessage);
136     InstallFront(kPOVMsgClass_ViewOutput, kPOVMsgIdent_Progress, this, &RenderFrontendBase::HandleMessage);
137     InstallFront(kPOVMsgClass_ViewOutput, kPOVMsgIdent_Done, this, &RenderFrontendBase::HandleMessage);
138     InstallFront(kPOVMsgClass_ViewOutput, kPOVMsgIdent_Failed, this, &RenderFrontendBase::HandleMessage);
139 
140     InstallFront(kPOVMsgClass_ViewImage, kPOVMsgIdent_PixelSet, this, &RenderFrontendBase::HandleMessage);
141     InstallFront(kPOVMsgClass_ViewImage, kPOVMsgIdent_PixelBlockSet, this, &RenderFrontendBase::HandleMessage);
142     InstallFront(kPOVMsgClass_ViewImage, kPOVMsgIdent_PixelRowSet, this, &RenderFrontendBase::HandleMessage);
143     InstallFront(kPOVMsgClass_ViewImage, kPOVMsgIdent_RectangleFrameSet, this, &RenderFrontendBase::HandleMessage);
144     InstallFront(kPOVMsgClass_ViewImage, kPOVMsgIdent_FilledRectangleSet, this, &RenderFrontendBase::HandleMessage);
145 
146     InstallFront(kPOVMsgClass_FileAccess, kPOVMsgIdent_FindFile, this, &RenderFrontendBase::HandleMessage);
147     InstallFront(kPOVMsgClass_FileAccess, kPOVMsgIdent_ReadFile, this, &RenderFrontendBase::HandleMessage);
148     InstallFront(kPOVMsgClass_FileAccess, kPOVMsgIdent_CreatedFile, this, &RenderFrontendBase::HandleMessage);
149 }
150 
~RenderFrontendBase()151 RenderFrontendBase::~RenderFrontendBase()
152 {
153     // nothing to do
154 }
155 
ConnectToBackend(POVMSAddress backendaddress,POVMS_Object & obj,POVMS_Object * resultobj,shared_ptr<Console> & console)156 void RenderFrontendBase::ConnectToBackend(POVMSAddress backendaddress, POVMS_Object& obj, POVMS_Object *resultobj, shared_ptr<Console>& console)
157 {
158     POVMS_Message msg(obj, kPOVMsgClass_BackendControl, kPOVMsgIdent_InitInfo);
159     POVMS_Message result(kPOVObjectClass_ResultData);
160 
161     msg.SetDestinationAddress(backendaddress);
162 
163     POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
164 
165     if(result.GetIdentifier() != kPOVMsgIdent_Done)
166         throw POV_EXCEPTION_CODE(result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr));
167 
168     backendaddresses.insert(backendaddress);
169 
170     if(resultobj != nullptr)
171         *resultobj = result;
172 
173     if(console != nullptr)
174         Message2Console::InitInfo(result, console.get());
175 }
176 
DisconnectFromBackend(POVMSAddress backendaddress)177 void RenderFrontendBase::DisconnectFromBackend(POVMSAddress backendaddress)
178 {
179     POVMS_Message msg(kPOVObjectClass_ControlData, kPOVMsgClass_BackendControl, kPOVMsgIdent_Done);
180     POVMS_Message result(kPOVObjectClass_ResultData);
181 
182     // Do not check here, the backend will check if the request to disconnect is valid! [trf]
183     backendaddresses.erase(backendaddress);
184 
185     msg.SetDestinationAddress(backendaddress);
186 
187     POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
188 
189     if(result.GetIdentifier() != kPOVMsgIdent_Done)
190         throw POV_EXCEPTION_CODE(result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr));
191 }
192 
CreateScene(SceneData & shd,POVMSAddress backendaddress,POVMS_Object & obj)193 RenderFrontendBase::SceneId RenderFrontendBase::CreateScene(SceneData& shd, POVMSAddress backendaddress, POVMS_Object& obj)
194 {
195     if(backendaddresses.find(backendaddress) == backendaddresses.end())
196         throw POV_EXCEPTION_STRING("TODO"); // TODO FIXME
197 
198     POVMS_Message msg(kPOVObjectClass_ControlData, kPOVMsgClass_BackendControl, kPOVMsgIdent_CreateScene);
199     POVMS_Message result(kPOVObjectClass_ResultData);
200 
201     msg.SetDestinationAddress(backendaddress);
202 
203     POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
204 
205     if(result.GetIdentifier() == kPOVMsgIdent_Done)
206     {
207         shd.scenepath = Path(obj.TryGetUCS2String(kPOVAttrib_InputFile, ""));
208         shd.scenepath.SetFile("");
209 
210         shd.outputpath = Path(obj.TryGetUCS2String(kPOVAttrib_OutputPath, ""));
211         // TODO FIXME BEGIN - this should not be needed, determine reason and fix [trf]
212         if (shd.outputpath.Empty() == true)
213         {
214             shd.outputpath = Path(obj.TryGetUCS2String(kPOVAttrib_OutputFile, ""));
215             shd.outputpath.SetFile("");
216             if (shd.outputpath.Empty() == false)
217                 obj.SetUCS2String(kPOVAttrib_OutputPath, shd.outputpath().c_str());
218         }
219         // TODO FIXME END
220 
221         shd.verbose = obj.TryGetBool(kPOVAttrib_Verbose, true);
222 
223         for(size_t i = 0; i < MAX_STREAMS; i++)
224         {
225             shd.consoleoutput[i] = true;
226             shd.streams[i].reset();
227         }
228 
229         shd.consoleoutput[ALL_STREAM] = false;
230 
231         if(obj.Exist(kPOVAttrib_AllConsole))
232         {
233             bool b = obj.GetBool(kPOVAttrib_AllConsole);
234             // NEVERE disable copyright banner BANNER_STREAM stream! [trf]
235             shd.consoleoutput[DEBUG_STREAM] = b;
236             shd.consoleoutput[FATAL_STREAM] = b;
237             shd.consoleoutput[RENDER_STREAM] = b;
238             shd.consoleoutput[STATISTIC_STREAM] = b;
239             shd.consoleoutput[WARNING_STREAM] = b;
240         }
241         else
242         {
243             if(obj.Exist(kPOVAttrib_DebugConsole))
244                 shd.consoleoutput[DEBUG_STREAM] = obj.GetBool(kPOVAttrib_DebugConsole);
245             if(obj.Exist(kPOVAttrib_FatalConsole))
246                 shd.consoleoutput[FATAL_STREAM] = obj.GetBool(kPOVAttrib_FatalConsole);
247             if(obj.Exist(kPOVAttrib_RenderConsole))
248                 shd.consoleoutput[RENDER_STREAM] = obj.GetBool(kPOVAttrib_RenderConsole);
249             if(obj.Exist(kPOVAttrib_StatisticsConsole))
250                 shd.consoleoutput[STATISTIC_STREAM] = obj.GetBool(kPOVAttrib_StatisticsConsole);
251             if(obj.Exist(kPOVAttrib_WarningConsole))
252                 shd.consoleoutput[WARNING_STREAM] = obj.GetBool(kPOVAttrib_WarningConsole);
253         }
254 
255         for(size_t i = 0; i < gStreamTypeUtilDataCount; i++)
256         {
257             if(obj.Exist(gStreamTypeUtilData[i]) == true)
258             {
259                 shd.streamnames[gStreamNumber[i]] = obj.GetUCS2String(gStreamTypeUtilData[i]);
260                 if(ProcessOptions::IsTrue(UCS2toASCIIString(shd.streamnames[gStreamNumber[i]]).c_str()) == true)
261                     shd.streamnames[gStreamNumber[i]] = ASCIItoUCS2String(gStreamDefaultFile[i]);
262             }
263         }
264 
265         // append to the stream if this is a continued trace or animation.
266         bool append = obj.TryGetBool(kPOVAttrib_ContinueTrace, false) || obj.TryGetBool(kPOVAttrib_AppendConsoleFiles, false);
267 
268         for(size_t i = 0; i < MAX_STREAMS; i++)
269         {
270             if(shd.streamnames[i].empty() == false)
271             {
272                 Path tmp(shd.streamnames[i]);
273 #if 1
274                 // allow only pure file names
275                 if (tmp.HasVolume() || !tmp.GetFolder().empty())
276                     throw POV_EXCEPTION(kParamErr, "Stream output files must reside in same directory as image output file.");
277                 Path path(shd.outputpath, tmp);
278 #elif 0
279                 // allow arbitrary relative file names, but no absolute file names
280                 if (tmp.HasVolume())
281                     throw POV_EXCEPTION(kParamErr, "Stream output file names must be specified relative to the output file directory.");
282                 Path path(shd.outputpath, tmp);
283 #else
284                 // allow arbitrary file names
285                 Path path;
286                 if (tmp.HasVolume())
287                     // file name is absolute
288                     path = tmp;
289                 else
290                     // file name is relative
291                     path = Path(shd.outputpath, tmp);
292 #endif
293                 shd.streams[i].reset(new FileTextStreamBuffer(path().c_str(), append));
294                 if (append && i != DEBUG_STREAM)
295                 {
296                     shd.streams[i]->puts("\n"
297                                          "==============================================================================\n"
298                                          "=                       Appending to stream output file                      =\n"
299                                          "==============================================================================\n");
300                 }
301             }
302         }
303 
304         if(obj.Exist(kPOVAttrib_LibraryPath) == true)
305         {
306             POVMS_List lps;
307 
308             obj.Get(kPOVAttrib_LibraryPath, lps);
309             for(int i = 1; i <= lps.GetListSize(); i++)
310             {
311                 POVMS_Attribute lp;
312 
313                 lps.GetNth(i, lp);
314                 UCS2String str = lp.GetUCS2String();
315                 if (str.empty() == true)
316                     continue;
317                 if (!POV_IS_PATH_SEPARATOR(*str.rbegin()))
318                     str += POV_PATH_SEPARATOR;
319                 shd.searchpaths.push_back(Path(str));
320             }
321         }
322 
323         return SceneId(backendaddress, result.GetInt(kPOVAttrib_SceneId));
324     }
325     else
326         throw POV_EXCEPTION_CODE(result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr));
327 }
328 
CloseScene(SceneData & shd,SceneId sid)329 void RenderFrontendBase::CloseScene(SceneData& shd, SceneId sid)
330 {
331     if(sid == Id())
332         return;
333 
334     try
335     {
336         POVMS_Message msg(kPOVObjectClass_ControlData, kPOVMsgClass_BackendControl, kPOVMsgIdent_CloseScene);
337         POVMS_Message result(kPOVObjectClass_ResultData);
338 
339         msg.SetDestinationAddress(sid.GetAddress());
340         msg.SetInt(kPOVAttrib_SceneId, sid.GetIdentifier());
341 
342         POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
343 
344         if(result.GetIdentifier() != kPOVMsgIdent_Done)
345             throw POV_EXCEPTION_CODE(result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr));
346     }
347     catch(pov_base::Exception&)
348     {
349         shd.state = SceneData::Scene_Invalid; // Cannot recover from error! - Current state of backend scene invalid! [trf]
350         throw;
351     }
352 }
353 
StartParser(SceneData & shd,SceneId sid,POVMS_Object & obj)354 void RenderFrontendBase::StartParser(SceneData& shd, SceneId sid, POVMS_Object& obj)
355 {
356     if(shd.state != SceneData::Scene_Created)
357         throw POV_EXCEPTION_CODE(kNotNowErr);
358 
359     POVMS_Message msg(obj, kPOVMsgClass_SceneControl, kPOVMsgIdent_StartParser);
360 
361     msg.SetDestinationAddress(sid.GetAddress());
362     msg.SetInt(kPOVAttrib_SceneId, sid.GetIdentifier());
363 
364     POVMS_SendMessage(context, msg, nullptr, kPOVMSSendMode_NoReply);
365 
366     shd.state = SceneData::Scene_Parsing;
367 }
368 
PauseParser(SceneData & shd,SceneId sid)369 void RenderFrontendBase::PauseParser(SceneData& shd, SceneId sid)
370 {
371     if(shd.state != SceneData::Scene_Parsing)
372         throw POV_EXCEPTION_CODE(kNotNowErr);
373 
374     POVMS_Message msg(kPOVObjectClass_ControlData, kPOVMsgClass_SceneControl, kPOVMsgIdent_PauseParser);
375     POVMS_Message result(kPOVObjectClass_ResultData);
376 
377     msg.SetDestinationAddress(sid.GetAddress());
378     msg.SetInt(kPOVAttrib_SceneId, sid.GetIdentifier());
379 
380     POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
381 
382     if(result.GetIdentifier() != kPOVMsgIdent_Done)
383     {
384         int err = result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr);
385 
386         if((err != kNoErr) && (err != kNotNowErr))
387             throw POV_EXCEPTION_CODE(err);
388     }
389 
390     shd.state = SceneData::Scene_Paused;
391 }
392 
ResumeParser(SceneData & shd,SceneId sid)393 void RenderFrontendBase::ResumeParser(SceneData& shd, SceneId sid)
394 {
395     if(shd.state != SceneData::Scene_Paused)
396         throw POV_EXCEPTION_CODE(kNotNowErr);
397 
398     POVMS_Message msg(kPOVObjectClass_ControlData, kPOVMsgClass_SceneControl, kPOVMsgIdent_ResumeParser);
399     POVMS_Message result(kPOVObjectClass_ResultData);
400 
401     msg.SetDestinationAddress(sid.GetAddress());
402     msg.SetInt(kPOVAttrib_SceneId, sid.GetIdentifier());
403 
404     POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
405 
406     if(result.GetIdentifier() != kPOVMsgIdent_Done)
407     {
408         int err = result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr);
409 
410         if((err != kNoErr) && (err != kNotNowErr))
411             throw POV_EXCEPTION_CODE(err);
412     }
413 
414     shd.state = SceneData::Scene_Parsing;
415 }
416 
StopParser(SceneData & shd,SceneId sid)417 void RenderFrontendBase::StopParser(SceneData& shd, SceneId sid)
418 {
419     if((shd.state != SceneData::Scene_Parsing) && (shd.state != SceneData::Scene_Paused))
420         throw POV_EXCEPTION_CODE(kNotNowErr);
421 
422     POVMS_Message msg(kPOVObjectClass_ControlData, kPOVMsgClass_SceneControl, kPOVMsgIdent_StopParser);
423     POVMS_Message result(kPOVObjectClass_ResultData);
424 
425     msg.SetDestinationAddress(sid.GetAddress());
426     msg.SetInt(kPOVAttrib_SceneId, sid.GetIdentifier());
427 
428     shd.state = SceneData::Scene_Stopping;
429 
430     POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
431 
432     if(result.GetIdentifier() != kPOVMsgIdent_Done)
433     {
434         int err = result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr);
435 
436         if((err != kNoErr) && (err != kNotNowErr))
437             throw POV_EXCEPTION_CODE(err);
438     }
439 }
440 
CreateView(SceneData & shd,ViewData & vhd,SceneId sid,POVMS_Object & obj)441 RenderFrontendBase::ViewId RenderFrontendBase::CreateView(SceneData& shd, ViewData& vhd, SceneId sid, POVMS_Object& obj)
442 {
443     POVMS_Message msg(obj, kPOVMsgClass_SceneControl, kPOVMsgIdent_CreateView);
444     POVMS_Message result(kPOVObjectClass_ResultData);
445 
446     msg.SetDestinationAddress(sid.GetAddress());
447     msg.SetInt(kPOVAttrib_SceneId, sid.GetIdentifier());
448 
449     POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
450 
451     if(result.GetIdentifier() == kPOVMsgIdent_Done)
452         return ViewId(sid.GetAddress(), result.GetInt(kPOVAttrib_ViewId));
453     else
454         throw POV_EXCEPTION_CODE(result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr));
455 }
456 
CloseView(ViewData & vhd,ViewId vid)457 void RenderFrontendBase::CloseView(ViewData& vhd, ViewId vid)
458 {
459     if(vid == Id())
460         return;
461 
462     try
463     {
464         POVMS_Message msg(kPOVObjectClass_ControlData, kPOVMsgClass_SceneControl, kPOVMsgIdent_CloseView);
465         POVMS_Message result(kPOVObjectClass_ResultData);
466 
467         msg.SetDestinationAddress(vid.GetAddress());
468         msg.SetInt(kPOVAttrib_ViewId, vid.GetIdentifier());
469 
470         POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
471 
472         if(result.GetIdentifier() != kPOVMsgIdent_Done)
473             throw POV_EXCEPTION_CODE(result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr));
474     }
475     catch(pov_base::Exception&)
476     {
477         vhd.state = ViewData::View_Invalid; // Cannot recover from error! - Current state of backend view invalid! [trf]
478         throw;
479     }
480 }
481 
StartRender(ViewData & vhd,ViewId vid,POVMS_Object & obj)482 void RenderFrontendBase::StartRender(ViewData& vhd, ViewId vid, POVMS_Object& obj)
483 {
484     if((vhd.state != ViewData::View_Created) && (vhd.state != ViewData::View_Rendered))
485         throw POV_EXCEPTION_CODE(kNotNowErr);
486 
487     POVMS_Message msg(obj, kPOVMsgClass_ViewControl, kPOVMsgIdent_StartRender);
488 
489     msg.SetDestinationAddress(vid.GetAddress());
490     msg.SetInt(kPOVAttrib_ViewId, vid.GetIdentifier());
491 
492     POVMS_SendMessage(context, msg, nullptr, kPOVMSSendMode_NoReply);
493 
494     vhd.state = ViewData::View_Rendering;
495 }
496 
PauseRender(ViewData & vhd,ViewId vid)497 void RenderFrontendBase::PauseRender(ViewData& vhd, ViewId vid)
498 {
499     if(vhd.state != ViewData::View_Rendering)
500         throw POV_EXCEPTION_CODE(kNotNowErr);
501 
502     POVMS_Message msg(kPOVObjectClass_ControlData, kPOVMsgClass_ViewControl, kPOVMsgIdent_PauseRender);
503     POVMS_Message result(kPOVObjectClass_ResultData);
504 
505     msg.SetDestinationAddress(vid.GetAddress());
506     msg.SetInt(kPOVAttrib_ViewId, vid.GetIdentifier());
507 
508     POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
509 
510     if(result.GetIdentifier() != kPOVMsgIdent_Done)
511     {
512         int err = result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr);
513 
514         if((err != kNoErr) && (err != kNotNowErr))
515             throw POV_EXCEPTION_CODE(err);
516     }
517 
518     vhd.state = ViewData::View_Paused;
519 }
520 
ResumeRender(ViewData & vhd,ViewId vid)521 void RenderFrontendBase::ResumeRender(ViewData& vhd, ViewId vid)
522 {
523     if(vhd.state != ViewData::View_Paused)
524         throw POV_EXCEPTION_CODE(kNotNowErr);
525 
526     POVMS_Message msg(kPOVObjectClass_ControlData, kPOVMsgClass_ViewControl, kPOVMsgIdent_ResumeRender);
527     POVMS_Message result(kPOVObjectClass_ResultData);
528 
529     msg.SetDestinationAddress(vid.GetAddress());
530     msg.SetInt(kPOVAttrib_ViewId, vid.GetIdentifier());
531 
532     POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
533 
534     if(result.GetIdentifier() != kPOVMsgIdent_Done)
535     {
536         int err = result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr);
537 
538         if((err != kNoErr) && (err != kNotNowErr))
539             throw POV_EXCEPTION_CODE(err);
540     }
541 
542     vhd.state = ViewData::View_Rendering;
543 }
544 
StopRender(ViewData & vhd,ViewId vid)545 void RenderFrontendBase::StopRender(ViewData& vhd, ViewId vid)
546 {
547     if((vhd.state != ViewData::View_Rendering) && (vhd.state != ViewData::View_Paused))
548         throw POV_EXCEPTION_CODE(kNotNowErr);
549 
550     POVMS_Message msg(kPOVObjectClass_ControlData, kPOVMsgClass_ViewControl, kPOVMsgIdent_StopRender);
551     POVMS_Message result(kPOVObjectClass_ResultData);
552 
553     msg.SetDestinationAddress(vid.GetAddress());
554     msg.SetInt(kPOVAttrib_ViewId, vid.GetIdentifier());
555 
556     vhd.state = ViewData::View_Stopping;
557 
558     POVMS_SendMessage(context, msg, &result, kPOVMSSendMode_WaitReply);
559 
560     if(result.GetIdentifier() != kPOVMsgIdent_Done)
561     {
562         int err = result.TryGetInt(kPOVAttrib_ErrorNumber, kNoErr);
563 
564         if((err != kNoErr) && (err != kNotNowErr))
565             throw POV_EXCEPTION_CODE(err);
566     }
567 }
568 
HandleMessage(POVMS_Message & msg,POVMS_Message & result,int)569 void RenderFrontendBase::HandleMessage(POVMS_Message& msg, POVMS_Message& result, int)
570 {
571     POVMSType ident = msg.GetIdentifier();
572 
573     switch(msg.GetClass())
574     {
575         case kPOVMsgClass_BackendControl:
576             if(msg.Exist(kPOVAttrib_ErrorNumber) == true)
577                 OutputFatalError(msg.TryGetString(kPOVAttrib_EnglishText, "Unknown failure in backend!"), msg.GetInt(kPOVAttrib_ErrorNumber));
578             else
579                 OutputFatalError(msg.TryGetString(kPOVAttrib_EnglishText, "Unknown failure in backend!"), 0);
580             break;
581         case kPOVMsgClass_SceneOutput:
582             HandleParserMessage(SceneId(msg.GetSourceAddress(), msg.GetInt(kPOVAttrib_SceneId)), ident, msg);
583             break;
584         case kPOVMsgClass_ViewOutput:
585             HandleRenderMessage(ViewId(msg.GetSourceAddress(), msg.GetInt(kPOVAttrib_ViewId)), ident, msg);
586             break;
587         case kPOVMsgClass_ViewImage:
588             HandleImageMessage(ViewId(msg.GetSourceAddress(), msg.GetInt(kPOVAttrib_ViewId)), ident, msg);
589             break;
590         case kPOVMsgClass_FileAccess:
591             HandleFileMessage(ViewId(msg.GetSourceAddress(), msg.GetInt(kPOVAttrib_SceneId)), ident, msg, result);
592             break;
593     }
594 }
595 
MakeBackupPath(POVMS_Object & ropts,ViewData & vd,const Path & outputpath)596 void RenderFrontendBase::MakeBackupPath(POVMS_Object& ropts, ViewData& vd, const Path& outputpath)
597 {
598     vd.imageBackupFile = outputpath;
599     vd.imageBackupFile.SetFile((Path(ropts.TryGetUCS2String(kPOVAttrib_OutputFile, ""))).GetFile());
600     if(vd.imageBackupFile.GetFile().empty() == true)
601         vd.imageBackupFile.SetFile(ropts.TryGetUCS2String(kPOVAttrib_InputFile, "object.pov"));
602 
603     vd.imageBackupFile.SetFile(GetFileName(Path(vd.imageBackupFile.GetFile())) + ASCIItoUCS2String(".pov-state"));
604 }
605 
NewBackup(POVMS_Object & ropts,ViewData & vd,const Path & outputpath)606 void RenderFrontendBase::NewBackup(POVMS_Object& ropts, ViewData& vd, const Path& outputpath)
607 {
608     vd.imageBackup.reset();
609 
610     MakeBackupPath(ropts, vd, outputpath);
611     if (!pov_base::PlatformBase::GetInstance().AllowLocalFileAccess (vd.imageBackupFile(), POV_File_Data_Backup, true))
612         throw POV_EXCEPTION(kCannotOpenFileErr, "Permission denied to create render state output file.");
613     vd.imageBackup = shared_ptr<OStream>(new OStream(vd.imageBackupFile().c_str()));
614     if(vd.imageBackup != nullptr)
615     {
616         Backup_File_Header hdr;
617 
618         if(!*vd.imageBackup)
619             throw POV_EXCEPTION(kCannotOpenFileErr, "Cannot create render state output file.");
620         memcpy(hdr.sig, RENDER_STATE_SIG, sizeof(hdr.sig));
621         memcpy(hdr.ver, RENDER_STATE_VER, sizeof(hdr.ver));
622         if(vd.imageBackup->write(&hdr, sizeof(hdr)) == false)
623             throw POV_EXCEPTION(kFileDataErr, "Cannot write header to render state output file.");
624         vd.imageBackup->flush();
625 
626         // we remove the file now since if the render doesn't complete and the file
627         // already exists, an attempt to do a continue later on will skip the render.
628         UCS2String filename = ropts.TryGetUCS2String(kPOVAttrib_OutputFile, "");
629         if(filename.length() > 0)
630         {
631             // we do this test even if the file doesn't exist as we need to write there
632             // eventually anyhow. might as well test if before the render starts ...
633             if(CheckIfFileExists(filename.c_str()))
634                 PlatformBase::GetInstance().DeleteLocalFile (filename.c_str());
635         }
636     }
637     else
638         throw POV_EXCEPTION(kCannotOpenFileErr, "Cannot create render state output file.");
639 }
640 
ContinueBackup(POVMS_Object & ropts,ViewData & vd,ViewId vid,POVMSInt & serial,vector<POVMSInt> & skip,const Path & outputpath)641 void RenderFrontendBase::ContinueBackup(POVMS_Object& ropts, ViewData& vd, ViewId vid, POVMSInt& serial, vector<POVMSInt>& skip, const Path& outputpath)
642 {
643     bool outputToFile = ropts.TryGetBool(kPOVAttrib_OutputToFile, true);
644 
645     // Note: due to the fact that tellg() only returns a 32-bit int on some platforms,
646     // currently this code will only work properly with a state file that is < 4gb in
647     // size, which works out to a render of roughly 16k*16k pixels.
648 
649     serial = 0;
650     vd.imageBackup.reset();
651     MakeBackupPath(ropts, vd, outputpath);
652 
653     std::unique_ptr<IStream> inbuffer(new IFileStream(vd.imageBackupFile().c_str()));
654 
655     size_t pos = sizeof(Backup_File_Header);
656 
657     if (inbuffer != nullptr)
658     {
659         Backup_File_Header hdr;
660 
661         if(*inbuffer)
662         {
663             // IOBase::eof() only is based on feof() and will only return
664             // true if we have attempted to read past the end of the file.
665             // therefore msg.Read() will throw an exception when we try to
666             // read from the end of the file, which isn't harmful per se but
667             // makes debugging more difficult since it is caught by the VC++
668             // IDE, and we don't want to disable catching pov_base::Exception
669             // since they are generally useful. therefore we explicitly check
670             // for the end of the file.
671             inbuffer->seekg (0, IOBase::seek_end);
672             POV_OFF_T end = inbuffer->tellg();
673             inbuffer->seekg (0, IOBase::seek_set);
674 
675             if (inbuffer->read (&hdr, sizeof (hdr)) == false)
676                 throw POV_EXCEPTION(kFileDataErr, "Cannot read header from render state file.");
677             if (memcmp (hdr.sig, RENDER_STATE_SIG, sizeof (hdr.sig)) != 0)
678                 throw POV_EXCEPTION(kFileDataErr, "Render state file header appears to be invalid.");
679             if (memcmp (hdr.ver, RENDER_STATE_VER, sizeof (hdr.ver)) != 0)
680                 throw POV_EXCEPTION(kFileDataErr, "Render state file was written by another version of POV-Ray.");
681 
682             while(pos < end && inbuffer->eof() == false)
683             {
684                 POVMS_Message msg;
685 
686                 try
687                 {
688                     msg.Read(*(inbuffer.get()));
689 
690                     // do not render complete blocks again
691                     if(msg.Exist(kPOVAttrib_PixelId) == true)
692                     {
693                         POVMSInt pid = msg.GetInt(kPOVAttrib_PixelId);
694 
695                         if(pid > serial)
696                             skip.push_back(pid);
697                         else
698                             serial++;
699                     }
700 
701                     HandleImageMessage(vid, msg.GetIdentifier(), msg);
702                 }
703                 catch(pov_base::Exception&)
704                 {
705                     // ignore all problems, just assume file is broken from last message on
706                     break;
707                 }
708                 pos = inbuffer->tellg();
709             }
710         }
711         else
712         {
713             // file doesn't exist, we create it via NewBackup
714             if (outputToFile == true)
715                 NewBackup(ropts, vd, outputpath);
716             return;
717         }
718     }
719     else
720         throw POV_EXCEPTION(kCannotOpenFileErr, "Cannot open state file from previous render.");
721 
722     // make sure the input file is closed since we're about to write to it
723     inbuffer.reset();
724 
725     // if there isn't going to be an output file, we don't write to the state file
726     if(outputToFile == true)
727     {
728         vd.imageBackup = shared_ptr<OStream>(new OStream(vd.imageBackupFile().c_str(), IOBase::append));
729         if(vd.imageBackup != nullptr)
730         {
731             if(!*vd.imageBackup)
732                 throw POV_EXCEPTION(kCannotOpenFileErr, "Cannot append to state output file.");
733 
734             vd.imageBackup->seekg(0, IOBase::seek_end);
735             vd.imageBackup->seekg(min((POV_OFF_T)pos, vd.imageBackup->tellg()), IOBase::seek_set);
736         }
737         else
738             throw POV_EXCEPTION(kCannotOpenFileErr, "Cannot create state output file stream.");
739     }
740 }
741 
742 namespace Message2Console
743 {
744 
InitInfo(POVMS_Object & cppmsg,TextStreamBuffer * tsb)745 void InitInfo(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
746 {
747     POVMSObject msgobj(cppmsg());
748     POVMSObjectPtr msg = &msgobj;
749     const int NUMBER_OF_AUTHORS_ACROSS = 4;
750     const char* FORMAT_OF_AUTHORS_ITEM = "  %-18s";
751     POVMSAttributeList attrlist;
752     POVMSAttribute item;
753     char charbuf[1024];
754     int h, i, j;
755     int cnt;
756     int l;
757     std::string generation;
758 
759     l = 1024;
760     charbuf[0] = 0;
761     if(POVMSUtil_GetString(msg, kPOVAttrib_CoreVersion, charbuf, &l) == kNoErr)
762         tsb->printf("%s\n", charbuf);
763 
764     l = 1024;
765     charbuf[0] = 0;
766     if (POVMSUtil_GetString(msg, kPOVAttrib_CoreGeneration, charbuf, &l) == kNoErr)
767         generation = charbuf;
768 
769     l = 1024;
770     charbuf[0] = 0;
771     if(POVMSUtil_GetString(msg, kPOVAttrib_EnglishText, charbuf, &l) == kNoErr)
772         tsb->printf("%s\n", charbuf);
773 
774     tsb->printf("\n");
775 
776     tsb->printf("Primary %s Architects/Developers: (Alphabetically)\n", generation.c_str());
777     if(POVMSObject_Get(msg, &attrlist, kPOVAttrib_PrimaryDevs) == kNoErr)
778     {
779         cnt = 0;
780 
781         if(POVMSAttrList_Count(&attrlist, &cnt) == kNoErr)
782         {
783             for(i = 0, h = 1; h <= cnt; i++)
784             {
785                 for(j = 0; (j < NUMBER_OF_AUTHORS_ACROSS) && (h <= cnt); j++, h++)
786                 {
787                     if(POVMSAttrList_GetNth(&attrlist, h, &item) == kNoErr)
788                     {
789                         l = 1023;
790                         charbuf[0] = 0;
791                         if(POVMSAttr_Get(&item, kPOVMSType_CString, charbuf, &l) == kNoErr)
792                             tsb->printf(FORMAT_OF_AUTHORS_ITEM, charbuf);
793 
794                         (void)POVMSAttr_Delete(&item);
795                     }
796                 }
797                 tsb->printf("\n");
798             }
799         }
800 
801         (void)POVMSAttrList_Delete(&attrlist);
802     }
803 
804     tsb->printf("\n");
805     tsb->printf("With Assistance From: (Alphabetically)\n");
806     if(POVMSObject_Get(msg, &attrlist, kPOVAttrib_AssistingDevs) == kNoErr)
807     {
808         cnt = 0;
809 
810         if(POVMSAttrList_Count(&attrlist, &cnt) == kNoErr)
811         {
812             for(i = 0, h = 1; h <= cnt; i++)
813             {
814                 for(j = 0; (j < NUMBER_OF_AUTHORS_ACROSS) && (h <= cnt); j++, h++)
815                 {
816                     if(POVMSAttrList_GetNth(&attrlist, h, &item) == kNoErr)
817                     {
818                         l = 1023;
819                         charbuf[0] = 0;
820                         if(POVMSAttr_Get(&item, kPOVMSType_CString, charbuf, &l) == kNoErr)
821                             tsb->printf(FORMAT_OF_AUTHORS_ITEM, charbuf);
822 
823                         (void)POVMSAttr_Delete(&item);
824                     }
825                 }
826                 tsb->printf("\n");
827             }
828         }
829 
830         (void)POVMSAttrList_Delete(&attrlist);
831     }
832 
833     tsb->printf("\n");
834     tsb->printf("Past Contributors: (Alphabetically)\n");
835     if(POVMSObject_Get(msg, &attrlist, kPOVAttrib_ContributingDevs) == kNoErr)
836     {
837         cnt = 0;
838 
839         if(POVMSAttrList_Count(&attrlist, &cnt) == kNoErr)
840         {
841             for(i = 0, h = 1; h <= cnt; i++)
842             {
843                 for(j = 0; (j < NUMBER_OF_AUTHORS_ACROSS) && (h <= cnt); j++, h++)
844                 {
845                     if(POVMSAttrList_GetNth(&attrlist, h, &item) == kNoErr)
846                     {
847                         l = 1023;
848                         charbuf[0] = 0;
849                         if(POVMSAttr_Get(&item, kPOVMSType_CString, charbuf, &l) == kNoErr)
850                             tsb->printf(FORMAT_OF_AUTHORS_ITEM, charbuf);
851 
852                         (void)POVMSAttr_Delete(&item);
853                     }
854                 }
855                 tsb->printf("\n");
856             }
857         }
858 
859         (void)POVMSAttrList_Delete(&attrlist);
860     }
861 
862     tsb->printf("\n");
863     tsb->printf("Other contributors are listed in the documentation.\n");
864 
865     if(POVMSObject_Get(msg, &attrlist, kPOVAttrib_ImageLibVersions) == kNoErr)
866     {
867         cnt = 0;
868 
869         if(POVMSAttrList_Count(&attrlist, &cnt) == kNoErr)
870         {
871             if(cnt > 0)
872             {
873                 tsb->printf("\n");
874                 tsb->printf("Support libraries used by POV-Ray:\n");
875 
876                 for(i = 1; i <= cnt; i++)
877                 {
878                     if(POVMSAttrList_GetNth(&attrlist, i, &item) == kNoErr)
879                     {
880                         l = 1023;
881                         charbuf[0] = 0;
882                         if(POVMSAttr_Get(&item, kPOVMSType_CString, charbuf, &l) == kNoErr)
883                             tsb->printf("  %s\n", charbuf);
884 
885                         (void)POVMSAttr_Delete(&item);
886                     }
887                 }
888             }
889         }
890 
891         (void)POVMSAttrList_Delete(&attrlist);
892     }
893 
894     l = 1024;
895     charbuf[0] = 0;
896     std::string cpuInfo;
897     if (POVMSUtil_GetString(msg, kPOVAttrib_CPUInfo, charbuf, &l) == kNoErr)
898         cpuInfo = charbuf;
899 #if POV_CPUINFO_DEBUG
900     l = 1024;
901     std::string cpuDetails;
902     if (POVMSUtil_GetString(msg, kPOVAttrib_CPUInfoDetails, charbuf, &l) == kNoErr)
903         cpuDetails = charbuf;
904 #endif
905 
906     if (POVMSObject_Get(msg, &attrlist, kPOVAttrib_Optimizations) == kNoErr)
907     {
908         cnt = 0;
909 
910         if (POVMSAttrList_Count(&attrlist, &cnt) == kNoErr)
911         {
912             if (cnt > 0)
913             {
914                 tsb->printf("\n");
915                 tsb->printf("Dynamic optimizations:\n");
916 
917                 if (!cpuInfo.empty())
918                     tsb->printf("  CPU detected: %s\n", cpuInfo.c_str());
919 #if POV_CPUINFO_DEBUG
920                 if (!cpuDetails.empty())
921                     tsb->printf("  CPU details: %s\n", cpuDetails.c_str());
922 #endif
923 
924                 for (i = 1; i <= cnt; i++)
925                 {
926                     if (POVMSAttrList_GetNth(&attrlist, i, &item) == kNoErr)
927                     {
928                         l = 1023;
929                         charbuf[0] = 0;
930                         if (POVMSAttr_Get(&item, kPOVMSType_CString, charbuf, &l) == kNoErr)
931                             tsb->printf("  %s\n", charbuf);
932 
933                         (void)POVMSAttr_Delete(&item);
934                     }
935                 }
936             }
937         }
938 
939         (void)POVMSAttrList_Delete(&attrlist);
940     }
941 
942     POVMSObject_Delete(msg);
943 }
944 
ParserOptions(POVMS_Object & cppmsg,TextStreamBuffer * tsb)945 void ParserOptions(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
946 {
947     POVMSObject msgobj(cppmsg());
948     POVMSObjectPtr msg = &msgobj;
949     POVMSAttribute attr;
950     POVMSFloat f;
951     UCS2 ucs2buf[1024];
952     int l;
953 
954     tsb->printf("Parser Options\n");
955 
956     f = 0.0;
957     l = sizeof (ucs2buf);
958     ucs2buf[0] = 0;
959     (void)POVMSUtil_GetUCS2String(msg, kPOVAttrib_InputFile, ucs2buf, &l);
960     if(POVMSUtil_GetFloat(msg, kPOVAttrib_Version, &f) != kNoErr)
961         tsb->printf("  Input file: %s\n", UCS2toASCIIString(ucs2buf).c_str());
962     else
963         tsb->printf("  Input file: %s (compatible to version %1.2f)\n", UCS2toASCIIString(ucs2buf).c_str(), (double)f);
964     tsb->printf("  Remove bounds.......%s\n  Split unions........%s\n",
965                   GetOptionSwitchString(msg, kPOVAttrib_RemoveBounds, true),
966                   GetOptionSwitchString(msg, kPOVAttrib_SplitUnions, false));
967 
968     tsb->printf("  Library paths:\n");
969     if(POVMSObject_Get(msg, &attr, kPOVAttrib_LibraryPath) == kNoErr)
970     {
971         int cnt = 0;
972 
973         if(POVMSAttrList_Count(&attr, &cnt) == kNoErr)
974         {
975             POVMSAttribute item;
976             int ii;
977 
978             for(ii = 1; ii <= cnt; ii++)
979             {
980                 if(POVMSAttrList_GetNth(&attr, ii, &item) == kNoErr)
981                 {
982                     l = sizeof(ucs2buf);
983                     ucs2buf[0] = 0;
984                     (void)POVMSAttr_Get(&item, kPOVMSType_UCS2String, ucs2buf, &l);
985                     tsb->printf("    %s\n", UCS2toASCIIString(ucs2buf).c_str());
986 
987                     (void)POVMSAttr_Delete(&item);
988                 }
989             }
990         }
991 
992         (void)POVMSAttr_Delete(&attr);
993     }
994 
995     POVMSObject_Delete(msg);
996     AnimationOptions(cppmsg,tsb);
997 }
998 
RenderOptions(POVMS_Object & obj,TextStreamBuffer * tsb)999 void RenderOptions(POVMS_Object& obj, TextStreamBuffer *tsb)
1000 {
1001     tsb->printf("----------------------------------------------------------------------------\n");
1002     tsb->printf("Render Options\n");
1003 
1004     tsb->printf("  Quality: %2d\n", clip(obj.TryGetInt(kPOVAttrib_Quality, 9), 0, 9));
1005 
1006     if(obj.TryGetBool (kPOVAttrib_Bounding, true))
1007         tsb->printf("  Bounding boxes.......On   Bounding threshold: %d\n",
1008                     clip<int>(obj.TryGetInt(kPOVAttrib_BoundingThreshold,DEFAULT_AUTO_BOUNDINGTHRESHOLD),1,SIGNED16_MAX));
1009     else
1010         tsb->printf("  Bounding boxes.......Off\n");
1011 
1012     /*
1013     tsb->printf("  Light Buffer........%s\n", GetOptionSwitchString(msg, kPOVAttrib_LightBuffer, true));
1014     tsb->printf("  Vista Buffer........%-3s", GetOptionSwitchString(msg, kPOVAttrib_VistaBuffer, true));
1015     b = false;
1016     (void)POVMSUtil_GetBool(msg, kPOVAttrib_VistaBuffer, &b);
1017     if(b == true)
1018         tsb->printf("  Draw Vista Buffer...%s", GetOptionSwitchString(msg, kPOVAttrib_DrawVistas, false));
1019     tsb->printf("\n");
1020 */
1021 
1022     if(obj.TryGetBool(kPOVAttrib_Antialias, false) == true)
1023     {
1024         int method = 0;
1025         if(obj.TryGetBool(kPOVAttrib_Antialias, false) == true)
1026             method = clip(obj.TryGetInt(kPOVAttrib_SamplingMethod, 1), 0, 3); // TODO FIXME - magic number in clip
1027         int depth = clip(obj.TryGetInt(kPOVAttrib_AntialiasDepth, 3), 1, 9); // TODO FIXME - magic number in clip
1028         float threshold = clip(obj.TryGetFloat(kPOVAttrib_AntialiasThreshold, 0.3f), 0.0f, 1.0f);
1029         float aagamma = obj.TryGetFloat(kPOVAttrib_AntialiasGamma, 2.5f);
1030         float jitter = 0.0f;
1031         if(obj.TryGetBool(kPOVAttrib_Jitter, true))
1032             jitter = clip(obj.TryGetFloat(kPOVAttrib_JitterAmount, 1.0f), 0.0f, 1.0f);
1033         if(jitter > 0.0f)
1034             tsb->printf("  Antialiasing.........On  (Method %d, Threshold %.3f, Depth %d, Jitter %.2f, Gamma %.2f)\n",
1035                            method, threshold, depth, jitter, aagamma);
1036         else
1037             tsb->printf("  Antialiasing.........On  (Method %d, Threshold %.3f, Depth %d, Jitter Off, Gamma %.2f)\n",
1038                            method, threshold, depth, aagamma);
1039     }
1040     else
1041         tsb->printf("  Antialiasing.........Off\n");
1042 }
1043 
OutputOptions(POVMS_Object & cppmsg,TextStreamBuffer * tsb)1044 void OutputOptions(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
1045 {
1046     POVMSObject msgobj(cppmsg());
1047     POVMSObjectPtr msg = &msgobj;
1048     POVMSInt i, i2;
1049     POVMSFloat f, f2, f3, f4;
1050     int startRow, startCol, endRow, endCol;
1051     POVMSBool b;
1052     UCS2 ucs2buf[1024];
1053     const char *t;
1054     int outputQuality = 8; // default bits per pixel channel // TODO FIXME: Default values shouldn't be hard-coded in here!
1055     int outputCompression;
1056     int l;
1057     int outputFormat = kPOVList_FileType_PNG; // TODO FIXME: Default values shouldn't be hard-coded in here!
1058     bool outputGrayscale = false;
1059 
1060     tsb->printf("Image Output Options\n");
1061 
1062     if (POVMSUtil_GetInt(msg, kPOVAttrib_Width, &i) != kNoErr)
1063         i = 160;
1064     if (POVMSUtil_GetInt(msg, kPOVAttrib_Height, &i2) != kNoErr)
1065         i2 = 120;
1066     if (POVMSUtil_GetFloat(msg, kPOVAttrib_StartRow, &f) != kNoErr)
1067         f = 0.0;
1068     if (POVMSUtil_GetFloat(msg, kPOVAttrib_EndRow, &f2) != kNoErr)
1069         f2 = (POVMSFloat)i2;
1070     if (POVMSUtil_GetFloat(msg, kPOVAttrib_StartColumn, &f3) != kNoErr)
1071         f3 = 0.0;
1072     if (POVMSUtil_GetFloat(msg, kPOVAttrib_EndColumn, &f4) != kNoErr)
1073         f4 = (POVMSFloat)i;
1074 
1075     // TODO FIXME - interpretation of the render rectangle (integer vs float) should be implemented elsewhere;
1076     // currently there is redundancy with View::StartRender(...) in view.cpp
1077 
1078     if((f3 >= 0.0) && (f3 < 1.0))
1079         startCol = int(DBL(i) * f3);
1080     else
1081         startCol = int(f3) - 1;
1082 
1083     if((f >= 0.0) && (f < 1.0))
1084         startRow = int(DBL(i2) * f);
1085     else
1086         startRow = int(f - 1);
1087 
1088     if((f4 >= 0.0) && (f4 <= 1.0))
1089         endCol = int(DBL(i) * f4) - 1;
1090     else
1091         endCol = int(f4 - 1);
1092 
1093     if((f2 >= 0.0) && (f2 <= 1.0))
1094         endRow = int(DBL(i2) * f2) - 1;
1095     else
1096         endRow = int(f2 - 1);
1097 
1098     tsb->printf("  Image resolution.....%u by %u (rows %d to %d, columns %d to %d).\n",
1099                 (int)i, (int)i2, (int)(startRow+1), (int)(endRow+1), (int)(startCol+1), (int)(endCol+1));
1100 
1101     if(POVMSUtil_GetInt(msg, kPOVAttrib_OutputFileType, &i) == kNoErr)
1102         outputFormat = i;
1103     if(POVMSUtil_GetInt(msg, kPOVAttrib_BitsPerColor, &i) == kNoErr)
1104         outputQuality = i;
1105     if(POVMSUtil_GetBool(msg, kPOVAttrib_GrayscaleOutput, &b) == kNoErr)
1106         outputGrayscale = b;
1107 
1108     b = false;
1109     if(POVMSUtil_GetBool(msg, kPOVAttrib_OutputToFile, &b) != kNoErr || b == true) // TODO FIXME: Defaults (in this case b=true) shouldn't be hard-coded in here!
1110     {
1111         const char *al = "";
1112 
1113         l = 1023;
1114         ucs2buf[0] = 0;
1115         (void)POVMSUtil_GetUCS2String(msg, kPOVAttrib_OutputFile, ucs2buf, &l);
1116 
1117         if(outputFormat == kPOVList_FileType_JPEG)
1118         {
1119             outputQuality = 85; // Default from base/image/jpeg.cpp // TODO FIXME: Default values shouldn't be hard-coded in here!
1120             if(POVMSUtil_GetInt(msg, kPOVAttrib_Compression, &i) == kNoErr)
1121             {
1122                 outputQuality = i>1?i:85; // Catching default 0 & 1 from base/image/jpeg.cpp // TODO FIXME: Default values shouldn't be hard-coded in here!
1123                 outputQuality = max(0, outputQuality);
1124                 outputQuality = min(100, outputQuality);
1125             }
1126             outputCompression = outputQuality;
1127             outputQuality = 8;
1128         }
1129 
1130         b = false;
1131         (void)POVMSUtil_GetBool(msg, kPOVAttrib_OutputAlpha, &b);
1132         if(b == true)
1133         {
1134             outputQuality *= 4;
1135             al = " with alpha";
1136         }
1137         else
1138             outputQuality *= 3;
1139 
1140         switch(outputFormat)
1141         {
1142             // TODO FIXME - for easier maintenance, this should probably be part of the FileTypeTable.
1143             case kPOVList_FileType_Targa:           t = "Targa";           break;
1144             case kPOVList_FileType_CompressedTarga: t = "RLE Targa";       break;
1145             case kPOVList_FileType_PNG:             t = "PNG";             break;
1146             case kPOVList_FileType_JPEG:            t = "JPEG";            break;
1147             case kPOVList_FileType_PPM:             t = "PPM";             break;
1148             case kPOVList_FileType_BMP:             t = "BMP";             break;
1149             case kPOVList_FileType_OpenEXR:         t = "EXR";             break;
1150             case kPOVList_FileType_RadianceHDR:     t = "HDR";             break;
1151             case kPOVList_FileType_System:          t = "(system format)"; break;
1152             default:                                t = "(none)";          break;
1153         }
1154 
1155         if(outputFormat == kPOVList_FileType_JPEG)
1156             tsb->printf("  Output file..........%s, %d bpp, quality %d%s%s %s\n", UCS2toASCIIString(ucs2buf).c_str(), outputQuality, outputCompression, "%", al, t);
1157         else if (outputGrayscale)
1158             tsb->printf("  Output file..........%s, grayscale%s %s\n", UCS2toASCIIString(ucs2buf).c_str(), al, t);
1159         else
1160             tsb->printf("  Output file..........%s, %d bpp%s %s\n", UCS2toASCIIString(ucs2buf).c_str(), outputQuality, al, t);
1161 
1162         if ((outputFormat != kPOVList_FileType_JPEG) && (outputFormat != kPOVList_FileType_OpenEXR))
1163         {
1164             b = false;
1165             (void)POVMSUtil_GetBool(msg, kPOVAttrib_Dither, &b);
1166             if (b)
1167             {
1168                 i = int(DitherMethodId::kBlueNoise);
1169                 (void)POVMSUtil_GetInt(msg, kPOVAttrib_DitherMethod, &i);
1170                 t = ProcessRenderOptions::GetDitherMethodText(i);
1171                 tsb->printf("  Dithering............%s\n", t);
1172             }
1173             else
1174                 tsb->printf("  Dithering............Off\n");
1175         }
1176     }
1177     else
1178         tsb->printf("  Output file: Disabled\n");
1179 
1180     b = false;
1181     (void)POVMSUtil_GetBool(msg, kPOVAttrib_Display, &b);
1182     if(b == true)
1183     {
1184         i = DEFAULT_DISPLAY_GAMMA_TYPE;
1185         (void)POVMSUtil_GetInt(msg, kPOVAttrib_DisplayGammaType, &i);
1186         f = DEFAULT_DISPLAY_GAMMA;
1187         (void)POVMSUtil_GetFloat(msg, kPOVAttrib_DisplayGamma, &f);
1188         switch (i)
1189         {
1190             case kPOVList_GammaType_Neutral:
1191                 tsb->printf("  Graphic display......On  (gamma: 1.0)\n");
1192                 break;
1193             case kPOVList_GammaType_PowerLaw:
1194                 tsb->printf("  Graphic display......On  (gamma: %g)\n", (float)f);
1195                 break;
1196             default:
1197                 t = ProcessRenderOptions::GetGammaTypeText(i);
1198                 tsb->printf("  Graphic display......On  (gamma: %s)\n", t);
1199                 break;
1200         }
1201     }
1202     else
1203         tsb->printf("  Graphic display......Off\n");
1204 
1205     i = 0;
1206     (void)POVMSUtil_GetInt(msg, kPOVAttrib_PreviewStartSize, &i);
1207     if(i > 1)
1208     {
1209         i2 = 0;
1210         (void)POVMSUtil_GetInt(msg, kPOVAttrib_PreviewEndSize, &i2);
1211         tsb->printf("  Mosaic preview.......On  (pixel sizes %d to %d)\n", (int)i, (int)i2);
1212     }
1213     else
1214         tsb->printf("  Mosaic preview.......Off\n");
1215 
1216     tsb->printf("  Continued trace.....%s\n", GetOptionSwitchString(msg, kPOVAttrib_ContinueTrace, false));
1217 
1218     tsb->printf("Information Output Options\n");
1219 
1220     tsb->printf("  All Streams to console.........%s", GetOptionSwitchString(msg, kPOVAttrib_AllConsole, true));
1221 //  if (streamnames[ALL_STREAM] != nullptr)
1222 //      tsb->printf("  and file %s\n", streamnames[ALL_STREAM]);
1223 //  else
1224         tsb->printf("\n");
1225 
1226     tsb->printf("  Debug Stream to console........%s", GetOptionSwitchString(msg, kPOVAttrib_DebugConsole, true));
1227 //  if (streamnames[DEBUG_STREAM] != nullptr)
1228 //      tsb->printf("  and file %s\n", streamnames[DEBUG_STREAM]);
1229 //  else
1230         tsb->printf("\n");
1231 
1232     tsb->printf("  Fatal Stream to console........%s", GetOptionSwitchString(msg, kPOVAttrib_FatalConsole, true));
1233 //  if (streamnames[FATAL_STREAM] != nullptr)
1234 //      tsb->printf("  and file %s\n", streamnames[FATAL_STREAM]);
1235 //  else
1236         tsb->printf("\n");
1237 
1238     tsb->printf("  Render Stream to console.......%s", GetOptionSwitchString(msg, kPOVAttrib_RenderConsole, true));
1239 //  if (streamnames[RENDER_STREAM] != nullptr)
1240 //      tsb->printf("  and file %s\n", streamnames[RENDER_STREAM]);
1241 //  else
1242         tsb->printf("\n");
1243 
1244     tsb->printf("  Statistics Stream to console...%s", GetOptionSwitchString(msg, kPOVAttrib_StatisticsConsole, true));
1245 //  if (streamnames[STATISTIC_STREAM] != nullptr)
1246 //      tsb->printf("  and file %s\n", streamnames[STATISTIC_STREAM]);
1247 //  else
1248         tsb->printf("\n");
1249 
1250     tsb->printf("  Warning Stream to console......%s", GetOptionSwitchString(msg, kPOVAttrib_WarningConsole, true));
1251 //  if (streamnames[WARNING_STREAM] != nullptr)
1252 //      tsb->printf("  and file %s\n", streamnames[WARNING_STREAM]);
1253 //  else
1254         tsb->printf("\n");
1255 
1256     POVMSObject_Delete(msg);
1257 }
1258 
AnimationOptions(POVMS_Object & cppmsg,TextStreamBuffer * tsb)1259 void AnimationOptions(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
1260 {
1261     POVMSObject msgobj(cppmsg());
1262     POVMSObjectPtr msg = &msgobj;
1263     POVMSInt i, i2;
1264     POVMSFloat f, f2;
1265 
1266     i = 1;
1267     i2 = 1;
1268     f = 0.0;
1269     (void)POVMSUtil_GetInt(msg, kPOVAttrib_InitialFrame, &i);
1270     (void)POVMSUtil_GetInt(msg, kPOVAttrib_FinalFrame, &i2);
1271     (void)POVMSUtil_GetFloat(msg, kPOVAttrib_Clock, &f);
1272     if((i != 1) || (i2 != 1) || (i != i2) || (f != 0.0))
1273     {
1274         tsb->printf("Animation Options\n");
1275         tsb->printf("  Initial Frame: %8d  Final Frame: %8d\n", (int)i, (int)i2);
1276         i2 = 1; // POVMSUtil_GetInt might fail, default to 1
1277         (void)POVMSUtil_GetInt(msg, kPOVAttrib_FrameStep, &i2);
1278         i2=max(1,i2);
1279         tsb->printf("  Frame Step: %11d\n",i2);
1280         f = 0.0;
1281         f2 = 0.0;
1282         (void)POVMSUtil_GetFloat(msg, kPOVAttrib_InitialClock, &f);
1283         (void)POVMSUtil_GetFloat(msg, kPOVAttrib_FinalClock, &f2);
1284         tsb->printf("  Initial Clock: %8.3f  Final Clock: %8.3f\n", (float)f, (float)f2);
1285         tsb->printf("  Cyclic Animation....%s  Field render........%s  Odd lines/frames....%s",
1286                       GetOptionSwitchString(msg, kPOVAttrib_CyclicAnimation, false),
1287                       GetOptionSwitchString(msg, kPOVAttrib_FieldRender, false),
1288                       GetOptionSwitchString(msg, kPOVAttrib_OddField, false));
1289     }
1290     else
1291         tsb->printf("  Clock value: %8.3f  (Animation off)", (float)f);
1292     tsb->printf("\n");
1293 
1294     POVMSObject_Delete(msg);
1295 }
1296 
ParserStatistics(POVMS_Object & cppmsg,TextStreamBuffer * tsb)1297 void ParserStatistics(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
1298 {
1299     POVMSLong ll = 0;
1300     int l = 0;
1301     int s = 0;
1302     int i = 0;
1303 
1304     tsb->printf("----------------------------------------------------------------------------\n");
1305     tsb->printf("Parser Statistics\n");
1306     tsb->printf("----------------------------------------------------------------------------\n");
1307 
1308     s = cppmsg.TryGetInt(kPOVAttrib_FiniteObjects, 0);
1309     i = cppmsg.TryGetInt(kPOVAttrib_InfiniteObjects, 0);
1310     l = cppmsg.TryGetInt(kPOVAttrib_LightSources, 0);
1311 
1312     tsb->printf("Finite Objects:   %10d\n", s);
1313     tsb->printf("Infinite Objects: %10d\n", i);
1314     tsb->printf("Light Sources:    %10d\n", l);
1315     tsb->printf("Total:            %10d\n", s + i + l);
1316 
1317     if(cppmsg.Exist(kPOVAttrib_BSPNodes) == true)
1318     {
1319         tsb->printf("----------------------------------------------------------------------------\n");
1320         tsb->printf("BSP Split Nodes:  %10d\n", cppmsg.TryGetInt(kPOVAttrib_BSPSplitNodes, 0));
1321         tsb->printf("BSP Object Nodes: %10d\n", cppmsg.TryGetInt(kPOVAttrib_BSPObjectNodes, 0));
1322         tsb->printf("BSP Empty Nodes:  %10d\n", cppmsg.TryGetInt(kPOVAttrib_BSPEmptyNodes, 0));
1323         tsb->printf("BSP Total Nodes:  %10d\n", cppmsg.TryGetInt(kPOVAttrib_BSPNodes, 0));
1324         tsb->printf("----------------------------------------------------------------------------\n");
1325         tsb->printf("BSP Objects/Node Average:       %8.2f          Maximum:      %10d\n",
1326                     cppmsg.TryGetFloat(kPOVAttrib_BSPAverageObjects, 0.0f), cppmsg.TryGetInt(kPOVAttrib_BSPMaxObjects, 0));
1327         tsb->printf("BSP Tree Depth Average:         %8.2f          Maximum:      %10d\n",
1328                     cppmsg.TryGetFloat(kPOVAttrib_BSPAverageDepth, 0.0f), cppmsg.TryGetInt(kPOVAttrib_BSPMaxDepth, 0));
1329         tsb->printf("BSP Max Depth Stopped Nodes:  %10d (%3.1f%%)   Objects/Node:   %8.2f\n",
1330                     cppmsg.TryGetInt(kPOVAttrib_BSPAborts, 0), cppmsg.TryGetFloat(kPOVAttrib_BSPAverageAborts, 0.0f) * 100.0f,
1331                     cppmsg.TryGetFloat(kPOVAttrib_BSPAverageAbortObjects, 0.0f));
1332     }
1333 
1334     tsb->printf("----------------------------------------------------------------------------\n");
1335 }
1336 
RenderStatistics(POVMS_Object & cppmsg,TextStreamBuffer * tsb)1337 void RenderStatistics(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
1338 {
1339     POVMSObject msgobj(cppmsg());
1340     POVMSObjectPtr msg = &msgobj;
1341     POVMSAttribute attr;
1342     POVMSLong l, l2, l3;
1343     POV_LONG Pixels_In_Image;
1344     int i, i2;
1345 
1346     tsb->printf("----------------------------------------------------------------------------\n");
1347 
1348     (void)POVMSUtil_GetInt(msg, kPOVAttrib_Width, &i);
1349     (void)POVMSUtil_GetInt(msg, kPOVAttrib_Height, &i2);
1350     Pixels_In_Image = (POV_LONG)i * (POV_LONG)i2;
1351 
1352     (void)POVMSUtil_GetLong(msg, kPOVAttrib_Pixels, &l);
1353     if(Pixels_In_Image > POVMSLongToCDouble(l))
1354         tsb->printf("Render Statistics (Partial Image Rendered)\n");
1355     else
1356         tsb->printf("Render Statistics\n");
1357 
1358     tsb->printf("Image Resolution %d x %d\n", i, i2);
1359 
1360     tsb->printf("----------------------------------------------------------------------------\n");
1361 
1362     (void)POVMSUtil_GetLong(msg, kPOVAttrib_Pixels, &l);
1363     (void)POVMSUtil_GetLong(msg, kPOVAttrib_PixelSamples, &l2);
1364     if(POVMSLongToCDouble(l) > 0.5)
1365         tsb->printf("Pixels:  %15.0f   Samples: %15.0f   Smpls/Pxl: %.2f\n",
1366                     POVMSLongToCDouble(l), POVMSLongToCDouble(l2), POVMSLongToCDouble(l2) / POVMSLongToCDouble(l));
1367     else
1368         tsb->printf("Pixels:  %15.0f   Samples: %15.0f   Smpls/Pxl: -\n",
1369                     POVMSLongToCDouble(l), POVMSLongToCDouble(l2));
1370 
1371     (void)POVMSUtil_GetLong(msg, kPOVAttrib_Rays, &l);
1372     (void)POVMSUtil_GetLong(msg, kPOVAttrib_RaysSaved, &l2);
1373     (void)POVMSUtil_GetInt(msg, kPOVAttrib_TraceLevel, &i);
1374     (void)POVMSUtil_GetInt(msg, kPOVAttrib_MaxTraceLevel, &i2);
1375     tsb->printf("Rays:    %15.0f   Saved:   %15.0f   Max Level: %d/%d\n",
1376                 POVMSLongToCDouble(l), POVMSLongToCDouble(l2), i, i2);
1377 
1378     tsb->printf("----------------------------------------------------------------------------\n");
1379     tsb->printf("Ray->Shape Intersection          Tests       Succeeded  Percentage\n");
1380     tsb->printf("----------------------------------------------------------------------------\n");
1381 
1382     if(POVMSObject_Get(msg, &attr, kPOVAttrib_ObjectIStats) == kNoErr)
1383     {
1384         int cnt = 0;
1385 
1386         if(POVMSAttrList_Count(&attr, &cnt) == kNoErr)
1387         {
1388             POVMSObject obj;
1389             int ii, len;
1390             char str[40];
1391 
1392             for(ii = 1; ii <= cnt; ii++)
1393             {
1394                 if(POVMSAttrList_GetNth(&attr, ii, &obj) == kNoErr)
1395                 {
1396                     len = 40;
1397                     str[0] = 0;
1398                     (void)POVMSUtil_GetString(&obj, kPOVAttrib_ObjectName, str, &len);
1399                     (void)POVMSUtil_GetLong(&obj, kPOVAttrib_ISectsTests, &l);
1400                     (void)POVMSUtil_GetLong(&obj, kPOVAttrib_ISectsSucceeded, &l2);
1401 
1402                     if(POVMSLongToCDouble(l) > 0.5)
1403                     {
1404                         tsb->printf("%-22s  %14.0f  %14.0f  %8.2f\n", str,
1405                                       POVMSLongToCDouble(l), POVMSLongToCDouble(l2),
1406                                       100.0 * POVMSLongToCDouble(l2) / POVMSLongToCDouble(l));
1407                     }
1408 
1409                     (void)POVMSAttr_Delete(&obj);
1410                 }
1411             }
1412         }
1413 
1414         (void)POVMSAttr_Delete(&attr);
1415     }
1416 
1417     (void)POVMSUtil_GetLong(msg, kPOVAttrib_IsoFindRoot, &l);
1418     (void)POVMSUtil_GetLong(msg, kPOVAttrib_FunctionVMCalls, &l2);
1419     if((POVMSLongToCDouble(l) > 0.5) || (POVMSLongToCDouble(l2) > 0.5))
1420     {
1421         tsb->printf("----------------------------------------------------------------------------\n");
1422         if(POVMSLongToCDouble(l) > 0.5)
1423             tsb->printf("Isosurface roots:   %15.0f\n", POVMSLongToCDouble(l));
1424         if(POVMSLongToCDouble(l2) > 0.5)
1425             tsb->printf("Function VM calls:  %15.0f\n", POVMSLongToCDouble(l2));
1426     }
1427 
1428     (void)POVMSUtil_GetLong(msg, kPOVAttrib_CrackleCacheTest, &l);
1429     (void)POVMSUtil_GetLong(msg, kPOVAttrib_CrackleCacheTestSuc, &l2);
1430     if((POVMSLongToCDouble(l) > 0.5) || (POVMSLongToCDouble(l2) > 0.5))
1431     {
1432         tsb->printf("----------------------------------------------------------------------------\n");
1433             if(POVMSLongToCDouble(l) > 0.5)
1434                 tsb->printf("Crackle Cache Queries: %15.0f\n", POVMSLongToCDouble(l));
1435             if(POVMSLongToCDouble(l2) > 0.5)
1436                 tsb->printf("Crackle Cache Hits:    %15.0f (%3.0f percent)\n", POVMSLongToCDouble(l2),
1437                             100.0 * POVMSLongToCDouble(l2) / POVMSLongToCDouble(l));
1438     }
1439 
1440     tsb->printf("----------------------------------------------------------------------------\n");
1441 
1442     (void)POVMSUtil_GetLong(msg, kPOVAttrib_PolynomTest, &l);
1443     if(POVMSLongToCDouble(l) > 0.5)
1444     {
1445         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RootsEliminated, &l2);
1446         tsb->printf("Roots tested:       %15.0f   eliminated:      %15.0f\n",
1447                       POVMSLongToCDouble(l), POVMSLongToCDouble(l2));
1448     }
1449 
1450     // TODO FIXME
1451     //(void)POVMSUtil_GetLong(msg, kPOVAttrib_CallsToNoise, &l);
1452     //(void)POVMSUtil_GetLong(msg, kPOVAttrib_CallsToDNoise, &l2);
1453     //tsb->printf("Calls to Noise:     %15.0f   Calls to DNoise: %15.0f\n",
1454     //              POVMSLongToCDouble(l), POVMSLongToCDouble(l2));
1455     // tsb->printf("----------------------------------------------------------------------------\n");
1456 
1457     (void)POVMSUtil_GetLong(msg, kPOVAttrib_MediaIntervals, &l);
1458     if(POVMSLongToCDouble(l) > 0.5)
1459     {
1460         (void)POVMSUtil_GetLong(msg, kPOVAttrib_MediaSamples, &l2);
1461         tsb->printf("Media Intervals:    %15.0f   Media Samples:   %15.0f (%4.2f)\n",
1462                       POVMSLongToCDouble(l), POVMSLongToCDouble(l2), POVMSLongToCDouble(l2) / POVMSLongToCDouble(l));
1463     }
1464 
1465     (void)POVMSUtil_GetLong(msg, kPOVAttrib_ShadowTest, &l);
1466     if(POVMSLongToCDouble(l) > 0.5)
1467     {
1468         (void)POVMSUtil_GetLong(msg, kPOVAttrib_ShadowTestSuc, &l2);
1469 
1470         tsb->printf("Shadow Ray Tests:   %15.0f   Succeeded:       %15.0f\n",
1471                       POVMSLongToCDouble(l), POVMSLongToCDouble(l2));
1472 
1473         (void)POVMSUtil_GetLong(msg, kPOVAttrib_ShadowCacheHits, &l);
1474         if(POVMSLongToCDouble(l) > 0.5)
1475             tsb->printf("Shadow Cache Hits:  %15.0f\n", POVMSLongToCDouble(l));
1476     }
1477 
1478     (void)POVMSUtil_GetLong(msg, kPOVAttrib_ReflectedRays, &l);
1479     if(POVMSLongToCDouble(l) > 0.5)
1480     {
1481         (void)POVMSUtil_GetLong(msg, kPOVAttrib_InnerReflectedRays, &l2);
1482         if(POVMSLongToCDouble(l2) > 0)
1483             tsb->printf("Reflected Rays:     %15.0f   Total Internal:  %15.0f\n",
1484                           POVMSLongToCDouble(l), POVMSLongToCDouble(l2));
1485         else
1486             tsb->printf("Reflected Rays:     %15.0f\n", POVMSLongToCDouble(l));
1487     }
1488 
1489     (void)POVMSUtil_GetLong(msg, kPOVAttrib_RefractedRays, &l);
1490     if(POVMSLongToCDouble(l) > 0.5)
1491         tsb->printf("Refracted Rays:     %15.0f\n", POVMSLongToCDouble(l));
1492 
1493     (void)POVMSUtil_GetLong(msg, kPOVAttrib_TransmittedRays, &l);
1494     if(POVMSLongToCDouble(l) > 0.5)
1495         tsb->printf("Transmitted Rays:   %15.0f\n", POVMSLongToCDouble(l));
1496 /*
1497     (void)POVMSUtil_GetLong(msg, kPOVAttrib_BoundingQueues, &l);
1498     if(POVMSLongToCDouble(l) > 0.5)
1499     {
1500         tsb->printf("Bounding Queues:    %15.0f\n", POVMSLongToCDouble(l));
1501         (void)POVMSUtil_GetLong(msg, kPOVAttrib_BoundingQueueResets, &l);
1502         (void)POVMSUtil_GetLong(msg, kPOVAttrib_BoundingQueueResizes, &l2);
1503         tsb->printf("Queue Resets:       %15.0f   Queue Resizes:   %15.0f\n",
1504                       POVMSLongToCDouble(l), POVMSLongToCDouble(l2));
1505     }
1506 */
1507     (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadGatherCount, &l);
1508     (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadReuseCount, &l2);
1509     if((POVMSLongToCDouble(l) > 0.5) || (POVMSLongToCDouble(l2) > 0.5))
1510     {
1511         tsb->printf("----------------------------------------------------------------------------\n");
1512         tsb->printf("Radiosity samples calculated:  %15.0f (%.2f %%)\n", POVMSLongToCDouble(l), 100.0 * POVMSLongToCDouble(l) / (POVMSLongToCDouble(l) + POVMSLongToCDouble(l2)));
1513 
1514         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadUnsavedCount, &l3);
1515         if(POVMSLongToCDouble(l3) > 0.5)
1516         {
1517             l -= l3;
1518             tsb->printf("  discarded due to low quality:%15.0f\n", POVMSLongToCDouble(l3));
1519             tsb->printf("  retained for re-use:         %15.0f\n", POVMSLongToCDouble(l));
1520         }
1521 
1522         tsb->printf("Radiosity samples reused:      %15.0f\n", POVMSLongToCDouble(l2));
1523 
1524         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadRayCount, &l3);
1525         if(POVMSLongToCDouble(l3) > 0.5)
1526         {
1527             tsb->printf("Radiosity sample rays shot:    %15.0f\n", POVMSLongToCDouble(l3));
1528         }
1529 
1530         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadOctreeNodes, &l2);
1531         if(POVMSLongToCDouble(l2) > 0.5)
1532         {
1533             tsb->printf("Radiosity octree nodes:        %15.0f\n", POVMSLongToCDouble(l2));
1534             tsb->printf("Radiosity octree samples/node: %15.2f\n", POVMSLongToCDouble(l) / POVMSLongToCDouble(l2));
1535         }
1536 
1537         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadOctreeLookups, &l);
1538         if(POVMSLongToCDouble(l) > 0.5)
1539             tsb->printf("Radiosity blocks examined:     %15.0f\n", POVMSLongToCDouble(l));
1540         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadOctreeAccepts0, &l2);
1541         if(POVMSLongToCDouble(l2) > 0.5)
1542             tsb->printf("Radiosity blocks passed test 0:%15.0f (%.2f %%)\n", POVMSLongToCDouble(l2), 100.0 * POVMSLongToCDouble(l2) / POVMSLongToCDouble(l));
1543         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadOctreeAccepts1, &l2);
1544         if(POVMSLongToCDouble(l2) > 0.5)
1545             tsb->printf("Radiosity blocks passed test 1:%15.0f (%.2f %%)\n", POVMSLongToCDouble(l2), 100.0 * POVMSLongToCDouble(l2) / POVMSLongToCDouble(l));
1546         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadOctreeAccepts2, &l2);
1547         if(POVMSLongToCDouble(l2) > 0.5)
1548             tsb->printf("Radiosity blocks passed test 2:%15.0f (%.2f %%)\n", POVMSLongToCDouble(l2), 100.0 * POVMSLongToCDouble(l2) / POVMSLongToCDouble(l));
1549         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadOctreeAccepts3, &l2);
1550         if(POVMSLongToCDouble(l2) > 0.5)
1551             tsb->printf("Radiosity blocks passed test 3:%15.0f (%.2f %%)\n", POVMSLongToCDouble(l2), 100.0 * POVMSLongToCDouble(l2) / POVMSLongToCDouble(l));
1552         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadOctreeAccepts4, &l2);
1553         if(POVMSLongToCDouble(l2) > 0.5)
1554             tsb->printf("Radiosity blocks passed test 4:%15.0f (%.2f %%)\n", POVMSLongToCDouble(l2), 100.0 * POVMSLongToCDouble(l2) / POVMSLongToCDouble(l));
1555         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadOctreeAccepts5, &l2);
1556         if(POVMSLongToCDouble(l2) > 0.5)
1557             tsb->printf("Radiosity blocks passed test 5:%15.0f (%.2f %%)\n", POVMSLongToCDouble(l2), 100.0 * POVMSLongToCDouble(l2) / POVMSLongToCDouble(l));
1558         l3 = l - l2;
1559         if(POVMSLongToCDouble(l3) > 0.5)
1560             tsb->printf("Radiosity blocks rejected:     %15.0f (%.2f %%)\n", POVMSLongToCDouble(l3), 100.0 * POVMSLongToCDouble(l3) / POVMSLongToCDouble(l));
1561 
1562         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadTopLevelGatherCount, &l);
1563         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadTopLevelReuseCount, &l2);
1564         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadTopLevelRayCount, &l3);
1565         tsb->printf("----------------------------------------------------------------------------\n");
1566         tsb->printf("Radiosity Depth 0 calculated:  %15.0f (%.2f %%)\n", POVMSLongToCDouble(l), 100.0 * POVMSLongToCDouble(l) / (POVMSLongToCDouble(l) + POVMSLongToCDouble(l2)));
1567         tsb->printf("Radiosity Depth 0 reused:      %15.0f\n", POVMSLongToCDouble(l2));
1568         tsb->printf("Radiosity Depth 0 rays shot:   %15.0f\n", POVMSLongToCDouble(l3));
1569 
1570         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadFinalGatherCount, &l);
1571         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadFinalReuseCount, &l2);
1572         (void)POVMSUtil_GetLong(msg, kPOVAttrib_RadFinalRayCount, &l3);
1573         tsb->printf("----------------------------------------------------------------------------\n");
1574         tsb->printf("Radiosity (final) calculated:  %15.0f (%.2f %%)\n", POVMSLongToCDouble(l), 100.0 * POVMSLongToCDouble(l) / (POVMSLongToCDouble(l) + POVMSLongToCDouble(l2)));
1575         tsb->printf("Radiosity (final) reused:      %15.0f\n", POVMSLongToCDouble(l2));
1576         tsb->printf("Radiosity (final) rays shot:   %15.0f\n", POVMSLongToCDouble(l3));
1577 
1578         POVMSLong samples[5][5];
1579         POVMSLong sampleSumPerRecursion[5];
1580         POVMSLong sampleSumPerPass[5];
1581         POVMSLong samplesFinal[5];
1582         POVMSLong sampleSumFinal = 0;
1583         POVMSLong sampleSum = 0;
1584         POVMSFloat sampleWeight[5];
1585         for (int recursion = 0; recursion < 5; recursion ++)
1586             sampleSumPerRecursion[recursion] = 0;
1587         for(int pass = 1; pass <= 5; pass ++)
1588         {
1589             sampleSumPerPass[pass-1] = 0;
1590             for (int recursion = 0; recursion < 5; recursion ++)
1591             {
1592                 unsigned int id = kPOVAttrib_RadSamplesP1R0 + (pass-1)*256 + recursion;
1593                 (void)POVMSUtil_GetLong(msg, id, &l);
1594                 samples[pass-1][recursion] = l;
1595                 sampleSumPerPass[pass-1] += l;
1596                 sampleSumPerRecursion[recursion] += l;
1597                 sampleSum += l;
1598             }
1599         }
1600         for (int recursion = 0; recursion < 5; recursion ++)
1601         {
1602             unsigned int id = kPOVAttrib_RadSamplesFR0 + recursion;
1603             (void)POVMSUtil_GetLong(msg, id, &l);
1604             samplesFinal[recursion] = l;
1605             sampleSumFinal += l;
1606             sampleSumPerRecursion[recursion] += l;
1607             sampleSum += l;
1608             id = kPOVAttrib_RadWeightR0 + recursion;
1609             (void)POVMSUtil_GetFloat(msg, id, &(sampleWeight[recursion]));
1610         }
1611         tsb->printf("----------------------------------------------------------------------------\n");
1612         tsb->printf("  Pass ");
1613         for (int recursion = 0; recursion < 5; recursion ++)
1614             if (POVMSLongToCDouble(sampleSumPerRecursion[recursion]) > 0.5)
1615                 tsb->printf((recursion < 4? "    Depth %i" : "   Depth 4+") , recursion);
1616         tsb->printf("           Total\n");
1617         tsb->printf("----------------------------------------------------------------------------\n");
1618         for(int pass = 1; pass <= 5; pass ++)
1619         {
1620             if (sampleSumPerPass[pass-1] > 0)
1621             {
1622                 tsb->printf("  %i%c   ", pass, (pass < 5 ? ' ' : '+'));
1623                 for (int recursion = 0; recursion < 5; recursion ++)
1624                 {
1625                     if (POVMSLongToCDouble(samples[pass-1][recursion]) > 0.5)
1626                         tsb->printf(" %10.0f", POVMSLongToCDouble(samples[pass-1][recursion]));
1627                     else if (POVMSLongToCDouble(sampleSumPerRecursion[recursion]) > 0.5)
1628                         tsb->printf("          -");
1629                 }
1630                 tsb->printf(" %15.0f\n", POVMSLongToCDouble(sampleSumPerPass[pass-1]));
1631             }
1632         }
1633         if (sampleSumFinal > 0)
1634         {
1635             tsb->printf("  Final");
1636             for (int recursion = 0; recursion < 5; recursion ++)
1637             {
1638                 if (POVMSLongToCDouble(samplesFinal[recursion]) > 0.5)
1639                     tsb->printf(" %10.0f", POVMSLongToCDouble(samplesFinal[recursion]));
1640                 else if (POVMSLongToCDouble(sampleSumPerRecursion[recursion]) > 0.5)
1641                     tsb->printf("          -");
1642             }
1643             tsb->printf(" %15.0f\n", POVMSLongToCDouble(sampleSumFinal));
1644         }
1645         tsb->printf("----------------------------------------------------------------------------\n");
1646         tsb->printf("  Total");
1647         for (int recursion = 0; recursion < 5; recursion ++)
1648         {
1649             if (POVMSLongToCDouble(sampleSumPerRecursion[recursion]) > 0.5)
1650                 tsb->printf(" %10.0f", POVMSLongToCDouble(sampleSumPerRecursion[recursion]));
1651         }
1652         tsb->printf(" %15.0f\n", POVMSLongToCDouble(sampleSum));
1653         tsb->printf("  Weight");
1654         for (int recursion = 0; recursion < 5; recursion ++)
1655         {
1656             if (sampleWeight[recursion] > 1e-6)
1657                 tsb->printf("%10.3f ", sampleWeight[recursion]);
1658             else if (POVMSLongToCDouble(sampleSumPerRecursion[recursion]) > 0.5)
1659                 tsb->printf("         - ");
1660         }
1661         tsb->printf("\n");
1662     }
1663 
1664     (void)POVMSUtil_GetLong(msg, kPOVAttrib_PhotonsShot, &l);
1665     if(POVMSLongToCDouble(l) > 0.5)
1666     {
1667         tsb->printf("----------------------------------------------------------------------------\n");
1668         tsb->printf("Number of photons shot: %15.0f\n", POVMSLongToCDouble(l));
1669         (void)POVMSUtil_GetLong(msg, kPOVAttrib_PhotonsStored, &l);
1670         if(POVMSLongToCDouble(l) > 0.5)
1671             tsb->printf("Surface photons stored: %15.0f\n", POVMSLongToCDouble(l));
1672         (void)POVMSUtil_GetLong(msg, kPOVAttrib_MediaPhotonsStored, &l);
1673         if(POVMSLongToCDouble(l) > 0.5)
1674             tsb->printf("Media photons stored:   %15.0f\n", POVMSLongToCDouble(l));
1675         (void)POVMSUtil_GetLong(msg, kPOVAttrib_GlobalPhotonsStored, &l);
1676         if(POVMSLongToCDouble(l) > 0.5)
1677             tsb->printf("Global photons stored:  %15.0f\n", POVMSLongToCDouble(l));
1678         (void)POVMSUtil_GetLong(msg, kPOVAttrib_PhotonsPriQInsert, &l);
1679         if(POVMSLongToCDouble(l) > 0.5)
1680             tsb->printf("Priority queue insert:  %15.0f\n", POVMSLongToCDouble(l));
1681         (void)POVMSUtil_GetLong(msg, kPOVAttrib_PhotonsPriQRemove, &l);
1682         if(POVMSLongToCDouble(l) > 0.5)
1683             tsb->printf("Priority queue remove:  %15.0f\n", POVMSLongToCDouble(l));
1684         (void)POVMSUtil_GetLong(msg, kPOVAttrib_GatherPerformedCnt, &l);
1685         if(POVMSLongToCDouble(l) > 0.5)
1686             tsb->printf("Gather function called: %15.0f\n", POVMSLongToCDouble(l));
1687         (void)POVMSUtil_GetLong(msg, kPOVAttrib_GatherExpandedCnt, &l);
1688         if(POVMSLongToCDouble(l) > 0.5)
1689             tsb->printf("Gather radius expanded: %15.0f\n", POVMSLongToCDouble(l));
1690     }
1691 
1692     tsb->printf("----------------------------------------------------------------------------\n");
1693 
1694     (void)POVMSUtil_GetLong(msg, kPOVAttrib_MinAlloc, &l);
1695     if (l > 0) // don't count allocs of 0 anyhow
1696         tsb->printf("Smallest Alloc:     %15.0f bytes\n", POVMSLongToCDouble(l));
1697     (void)POVMSUtil_GetLong(msg, kPOVAttrib_MaxAlloc, &l);
1698     if (l > 0)
1699         tsb->printf("Largest  Alloc:     %15.0f bytes\n", POVMSLongToCDouble(l));
1700 
1701     l = 0;
1702     l2 = 0;
1703     (void)POVMSUtil_GetLong(msg, kPOVAttrib_CallsToAlloc, &l);
1704     (void)POVMSUtil_GetLong(msg, kPOVAttrib_CallsToFree, &l2);
1705     if(POVMSLongToCDouble(l) > 0.5)
1706         tsb->printf("Total Alloc calls:  %15.0f         Free calls:%15.0f\n", POVMSLongToCDouble(l), POVMSLongToCDouble(l2));
1707 
1708     l = 0;
1709     (void)POVMSUtil_GetLong(msg, kPOVAttrib_PeakMemoryUsage, &l);
1710     if(POVMSLongToCDouble(l) > 0.5)
1711         tsb->printf("Peak memory used:   %15.0f bytes\n", POVMSLongToCDouble(l));
1712 
1713     tsb->printf("----------------------------------------------------------------------------\n");
1714 
1715     POVMSObject_Delete(msg);
1716 }
1717 
Warning(POVMS_Object & cppmsg,TextStreamBuffer * tsb)1718 void Warning(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
1719 {
1720     POVMSObject msgobj(cppmsg());
1721     POVMSObjectPtr msg = &msgobj;
1722 
1723     FileMessage(tsb, WARNING_STREAM, msg);
1724 
1725     POVMSObject_Delete(msg);
1726 }
1727 
Error(POVMS_Object & cppmsg,TextStreamBuffer * tsb)1728 void Error(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
1729 {
1730     POVMSObject msgobj(cppmsg());
1731     POVMSObjectPtr msg = &msgobj;
1732 
1733     FileMessage(tsb, WARNING_STREAM, msg);
1734 
1735     POVMSObject_Delete(msg);
1736 }
1737 
FatalError(POVMS_Object & cppmsg,TextStreamBuffer * tsb)1738 void FatalError(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
1739 {
1740     POVMSObject msgobj(cppmsg());
1741     POVMSObjectPtr msg = &msgobj;
1742     int ret = kNoErr;
1743     int l = 0;
1744     int s = 0;
1745 
1746     if(ret == kNoErr)
1747         FileMessage(tsb, FATAL_STREAM, msg);
1748 
1749     if(ret != kNoErr)
1750         throw POV_EXCEPTION_CODE(ret);
1751 
1752     POVMSObject_Delete(msg);
1753 }
1754 
FileMessage(TextStreamBuffer * tsb,int stream,POVMSObjectPtr msg)1755 void FileMessage(TextStreamBuffer *tsb, int stream, POVMSObjectPtr msg)
1756 {
1757     const int Num_Echo_Lines = 5; // TODO FIXME
1758     const int output_string_buffer_size = 1024; // TODO FIXME
1759     char output_string_buffer[output_string_buffer_size]; // TODO FIXME
1760     UCS2 filename[2048];
1761 
1762     POVMSLong ll = 0;
1763     int ret = kNoErr;
1764     int l = sizeof(filename);
1765 
1766     if(POVMSUtil_GetUCS2String(msg, kPOVAttrib_FileName, filename, &l) == kNoErr)
1767     {
1768         // TODO FIXME: we ought to support UCS2 string output.
1769         POVMSUCS2String fn(filename);
1770         string asciiFN(UCS2toASCIIString(fn));
1771 
1772         if((POVMSUtil_GetLong(msg, kPOVAttrib_Line, &ll) == kNoErr) && ((stream == WARNING_STREAM) || (stream == FATAL_STREAM)))
1773         {
1774             if ((asciiFN.empty() == false) && (ll > 0))
1775                 tsb->printf("File: %s  Line: %ld\n", asciiFN.c_str(), ll);
1776         }
1777         if(((POVMSUtil_GetLong(msg, kPOVAttrib_FilePosition, &ll) == kNoErr) && (Num_Echo_Lines > 0)) && (stream == FATAL_STREAM))
1778         {
1779             tsb->printf("File Context (%d lines):\n", Num_Echo_Lines);
1780             tsb->printfile(asciiFN.c_str(), ll, -Num_Echo_Lines);
1781             tsb->printf("\n");
1782         }
1783     }
1784 
1785     l = output_string_buffer_size;
1786     output_string_buffer[0] = 0;
1787     ret = POVMSUtil_GetString(msg, kPOVAttrib_EnglishText, output_string_buffer, &l);
1788     if(ret == kNoErr)
1789         tsb->printf("%s\n", output_string_buffer);
1790 
1791     if(ret != kNoErr)
1792         throw POV_EXCEPTION_CODE(ret);
1793 }
1794 
GetOptionSwitchString(POVMSObjectPtr msg,POVMSType key,bool defaultstate)1795 const char *GetOptionSwitchString(POVMSObjectPtr msg, POVMSType key, bool defaultstate)
1796 {
1797     POVMSBool b = false;
1798 
1799     if(POVMSUtil_GetBool(msg, key, &b) != kNoErr)
1800         b = defaultstate;
1801 
1802     if(b == true)
1803         return ".On ";
1804 
1805     return ".Off";
1806 }
1807 
ParserTime(POVMS_Object & cppmsg,TextStreamBuffer * tsb)1808 void ParserTime(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
1809 {
1810     POV_LONG i = 0;
1811     int msec = 0;
1812     int sec = 0;
1813 
1814     tsb->printf("Parser Time\n");
1815 
1816     POVMS_Object parseTime;
1817     POVMS_Object boundingTime;
1818 
1819     if(cppmsg.Exist(kPOVAttrib_ParseTime))
1820     {
1821         cppmsg.Get(kPOVAttrib_ParseTime, parseTime);
1822         i = parseTime.TryGetLong(kPOVAttrib_RealTime, 0);
1823         sec = int(i / (POV_LONG)(1000));
1824         msec = int(i % (POV_LONG)(1000));
1825         tsb->printf("  Parse Time:     %3d hours %2d minutes %2d seconds (%d.%03d seconds)\n", int(sec / 3600), int((sec / 60) % 60), int(sec % 60), sec, msec);
1826         if(parseTime.Exist(kPOVAttrib_CPUTime) == true)
1827         {
1828             i = parseTime.TryGetLong(kPOVAttrib_CPUTime, 0);
1829             sec = int(i / (POV_LONG)(1000));
1830             msec = int(i % (POV_LONG)(1000));
1831             tsb->printf("              using %d thread(s) with %d.%03d CPU-seconds total\n", int(parseTime.TryGetInt(kPOVAttrib_TimeSamples, 1)), sec, msec);
1832         }
1833         else
1834             tsb->printf("              using %d thread(s)\n", int(parseTime.TryGetInt(kPOVAttrib_TimeSamples, 1)));
1835     }
1836     else
1837         tsb->printf("  Parse Time:       No parsing\n");
1838 
1839     if(cppmsg.Exist(kPOVAttrib_BoundingTime))
1840     {
1841         cppmsg.Get(kPOVAttrib_BoundingTime, boundingTime);
1842         i = boundingTime.TryGetLong(kPOVAttrib_RealTime, 0);
1843         sec = int(i / (POV_LONG)(1000));
1844         msec = int(i % (POV_LONG)(1000));
1845         tsb->printf("  Bounding Time:  %3d hours %2d minutes %2d seconds (%d.%03d seconds)\n", int(sec / 3600), int((sec / 60) % 60), int(sec % 60), sec, msec);
1846         if(boundingTime.Exist(kPOVAttrib_CPUTime) == true)
1847         {
1848             i = boundingTime.TryGetLong(kPOVAttrib_CPUTime, 0);
1849             sec = int(i / (POV_LONG)(1000));
1850             msec = int(i % (POV_LONG)(1000));
1851             tsb->printf("              using %d thread(s) with %d.%03d CPU-seconds total\n", int(boundingTime.TryGetInt(kPOVAttrib_TimeSamples, 1)), sec, msec);
1852         }
1853         else
1854             tsb->printf("              using %d thread(s)\n", int(boundingTime.TryGetInt(kPOVAttrib_TimeSamples, 1)));
1855     }
1856     else
1857         tsb->printf("  Bounding Time:    No bounding\n");
1858 }
1859 
RenderTime(POVMS_Object & cppmsg,TextStreamBuffer * tsb)1860 void RenderTime(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
1861 {
1862     POV_LONG i = 0;
1863     int msec = 0;
1864     int sec = 0;
1865 
1866     tsb->printf("Render Time:\n");
1867 
1868     POVMS_Object photonTime;
1869     POVMS_Object radiosityTime;
1870     POVMS_Object renderTime;
1871 
1872     if(cppmsg.Exist(kPOVAttrib_PhotonTime))
1873     {
1874         cppmsg.Get(kPOVAttrib_PhotonTime, photonTime);
1875         i = photonTime.TryGetLong(kPOVAttrib_RealTime, 0);
1876         sec = int(i / (POV_LONG)(1000));
1877         msec = int(i % (POV_LONG)(1000));
1878         tsb->printf("  Photon Time:    %3d hours %2d minutes %2d seconds (%d.%03d seconds)\n", int(sec / 3600), int((sec / 60) % 60), int(sec % 60), sec, msec);
1879         if(photonTime.Exist(kPOVAttrib_CPUTime) == true)
1880         {
1881             i = photonTime.TryGetLong(kPOVAttrib_CPUTime, 0);
1882             sec = int(i / (POV_LONG)(1000));
1883             msec = int(i % (POV_LONG)(1000));
1884             tsb->printf("              using %d thread(s) with %d.%03d CPU-seconds total\n", int(photonTime.TryGetInt(kPOVAttrib_TimeSamples, 1)), sec, msec);
1885         }
1886         else
1887             tsb->printf("              using %d thread(s)\n", int(photonTime.TryGetInt(kPOVAttrib_TimeSamples, 1)));
1888     }
1889     else
1890         tsb->printf("  Photon Time:      No photons\n");
1891 
1892     if(cppmsg.Exist(kPOVAttrib_RadiosityTime))
1893     {
1894         cppmsg.Get(kPOVAttrib_RadiosityTime, radiosityTime);
1895         i = radiosityTime.TryGetLong(kPOVAttrib_RealTime, 0);
1896         sec = int(i / (POV_LONG)(1000));
1897         msec = int(i % (POV_LONG)(1000));
1898         tsb->printf("  Radiosity Time: %3d hours %2d minutes %2d seconds (%d.%03d seconds)\n", int(sec / 3600), int((sec / 60) % 60), int(sec % 60), sec, msec);
1899         if(radiosityTime.Exist(kPOVAttrib_CPUTime) == true)
1900         {
1901             i = radiosityTime.TryGetLong(kPOVAttrib_CPUTime, 0);
1902             sec = int(i / (POV_LONG)(1000));
1903             msec = int(i % (POV_LONG)(1000));
1904             tsb->printf("              using %d thread(s) with %d.%03d CPU-seconds total\n", int(radiosityTime.TryGetInt(kPOVAttrib_TimeSamples, 1)), sec, msec);
1905         }
1906         else
1907             tsb->printf("              using %d thread(s)\n", int(radiosityTime.TryGetInt(kPOVAttrib_TimeSamples, 1)));
1908     }
1909     else
1910         tsb->printf("  Radiosity Time:   No radiosity\n");
1911 
1912     if(cppmsg.Exist(kPOVAttrib_TraceTime))
1913     {
1914         cppmsg.Get(kPOVAttrib_TraceTime, renderTime);
1915         i = renderTime.TryGetLong(kPOVAttrib_RealTime, 0);
1916         sec = int(i / (POV_LONG)(1000));
1917         msec = int(i % (POV_LONG)(1000));
1918         tsb->printf("  Trace Time:     %3d hours %2d minutes %2d seconds (%d.%03d seconds)\n", int(sec / 3600), int((sec / 60) % 60), int(sec % 60), sec, msec);
1919         if(renderTime.Exist(kPOVAttrib_CPUTime) == true)
1920         {
1921             i = renderTime.TryGetLong(kPOVAttrib_CPUTime, 0);
1922             sec = int(i / (POV_LONG)(1000));
1923             msec = int(i % (POV_LONG)(1000));
1924             tsb->printf("              using %d thread(s) with %d.%03d CPU-seconds total\n", int(renderTime.TryGetInt(kPOVAttrib_TimeSamples, 1)), sec, msec);
1925         }
1926         else
1927             tsb->printf("              using %d thread(s)\n", int(renderTime.TryGetInt(kPOVAttrib_TimeSamples, 1)));
1928     }
1929     else
1930         tsb->printf("  Trace Time:       No trace\n");
1931 }
1932 
DebugInfo(POVMS_Object & cppmsg,TextStreamBuffer * tsb)1933 void DebugInfo(POVMS_Object& cppmsg, TextStreamBuffer *tsb)
1934 {
1935     std::string str = cppmsg.TryGetString(kPOVAttrib_EnglishText, "<Error retrieving debug output>");
1936     tsb->printf("%s\n", str.c_str());
1937 }
1938 
GetProgressTime(POVMS_Object & obj,POVMSType key)1939 string GetProgressTime(POVMS_Object& obj, POVMSType key)
1940 {
1941     int sec = int(obj.TryGetLong(kPOVAttrib_RealTime, 0) / (POV_LONG)(1000));
1942     char buffer[32];
1943 
1944     sprintf(buffer, "%3d:%02d:%02d", int(sec / 3600), int((sec / 60) % 60), int(sec % 60));
1945 
1946     return string(buffer);
1947 }
1948 
RenderDone(TextStreamBuffer * tsb,POVMSObjectPtr msg)1949 void RenderDone(TextStreamBuffer *tsb, POVMSObjectPtr msg)
1950 {/*
1951     POVMSObject object;
1952     int ret = 0;
1953     int i = 0;
1954 
1955     ret = POVMSObject_Get(msg, &object, kPOVAttrib_AnimationTime);
1956     if(ret == kNoErr)
1957         tsb->printf("Total Scene Processing Times\n");
1958 
1959     if(ret == kNoErr)
1960         ret = POVMSUtil_GetInt(&object, kPOVAttrib_ParseTime, &i);
1961     if(ret == kNoErr)
1962         tsb->printf("  Parse Time:  %3d hours %2d minutes %2d seconds (%d seconds)\n", (int)(i / 3600), (int)((i / 60) % 60), (int)(i % 60), (int)i);
1963 
1964     if(ret == kNoErr)
1965         ret = POVMSUtil_GetInt(&object, kPOVAttrib_PhotonTime, &i);
1966     if(ret == kNoErr)
1967         tsb->printf("  Photon Time: %3d hours %2d minutes %2d seconds (%d seconds)\n", (int)(i / 3600), (int)((i / 60) % 60), (int)(i % 60), (int)i);
1968 
1969     if(ret == kNoErr)
1970         ret = POVMSUtil_GetInt(&object, kPOVAttrib_TraceTime, &i);
1971     if(ret == kNoErr)
1972         tsb->printf("  Render Time: %3d hours %2d minutes %2d seconds (%d seconds)\n", (int)(i / 3600), (int)((i / 60) % 60), (int)(i % 60), (int)i);
1973 
1974     if(ret == kNoErr)
1975         ret = POVMSUtil_GetInt(&object, kPOVAttrib_TotalTime, &i);
1976     if(ret == kNoErr)
1977         tsb->printf("  Total Time:  %3d hours %2d minutes %2d seconds (%d seconds)\n", (int)(i / 3600), (int)((i / 60) % 60), (int)(i % 60), (int)i);
1978 
1979     (void)POVMSObject_Delete(&object);
1980 
1981     if(ret != kNoErr)
1982         throw POV_EXCEPTION_CODE(ret);*/
1983 }
1984 
Progress(TextStreamBuffer * tsb,POVMSObjectPtr msg)1985 void Progress(TextStreamBuffer *tsb, POVMSObjectPtr msg)
1986 {/*
1987     POVMSLong ll = 0;
1988     POVMSBool b = false;
1989     int ret = kNoErr;
1990     int l = 0;
1991     int s = 0;
1992 
1993 //  Flush(DEBUG_STREAM);
1994 
1995     ret = POVMSUtil_GetBool(msg, kPOVAttrib_ProgressStatus, &b);
1996     if(ret == kNoErr)
1997         ret = POVMSUtil_GetInt(msg, kPOVAttrib_TotalTime, &s);
1998     if(ret == kNoErr)
1999     {
2000         l = 80;
2001 
2002         if(b == false)
2003         {
2004             ret = POVMSUtil_GetString(msg, kPOVAttrib_EnglishText, status_string_buffer, &l);
2005             if(ret == kNoErr)
2006                 tsb->printf("\n%3d:%02d:%02d %s", (int)(s / 3600), (int)((s / 60) % 60), (int)(s % 60), status_string_buffer);
2007         }
2008         else // if(opts.Options & VERBOSE) // Should this be part of verbose reporting only or not? I really don't know which way would be better... [trf]
2009         {
2010             (void)POVMSUtil_GetString(msg, kPOVAttrib_EnglishText, status_string_buffer, &l);
2011             tsb->printf("\r%3d:%02d:%02d %s", (int)(s / 3600), (int)((s / 60) % 60), (int)(s % 60), status_string_buffer);
2012         }
2013 
2014 // FIXME        if(opts.Options & VERBOSE)
2015         {
2016             // animation frame progress
2017             if(POVMSUtil_GetInt(msg, kPOVAttrib_FrameCount, &l) == kNoErr)
2018             {
2019                 if(POVMSUtil_GetInt(msg, kPOVAttrib_AbsoluteCurFrame, &s) == kNoErr)
2020                     tsb->printf(" %d of %d", s, l);
2021             }
2022             // parsing progress
2023             else if((POVMSUtil_GetLong(msg, kPOVAttrib_CurrentTokenCount, &ll) == kNoErr) && (ll > 0))
2024             {
2025                 tsb->printf(" %ldK tokens", long(((POV_LONG)(ll))/1000));
2026             }
2027             // rendering progress
2028             else if(POVMSUtil_GetInt(msg, kPOVAttrib_CurrentLine, &l) == kNoErr)
2029             {
2030                 if(POVMSUtil_GetInt(msg, kPOVAttrib_LineCount, &s) == kNoErr)
2031                     tsb->printf(" line %d of %d", l, s);
2032                 if(POVMSUtil_GetInt(msg, kPOVAttrib_MosaicPreviewSize, &l) == kNoErr)
2033                     tsb->printf(" at %dx%d", l, l);
2034                 if(POVMSUtil_GetInt(msg, kPOVAttrib_SuperSampleCount, &l) == kNoErr)
2035                     tsb->printf(", %d supersamples", l);
2036                 if(POVMSUtil_GetInt(msg, kPOVAttrib_RadGatherCount, &l) == kNoErr)
2037                     tsb->printf(", %d rad. samples", l);
2038             }
2039             // photon progress
2040             else if(POVMSUtil_GetInt(msg, kPOVAttrib_TotalPhotonCount, &l) == kNoErr)
2041             {
2042                 // sorting
2043                 if(POVMSUtil_GetInt(msg, kPOVAttrib_CurrentPhotonCount, &s) == kNoErr)
2044                     tsb->printf(" %d of %d", s, l);
2045                 // shooting
2046                 else
2047                 {
2048                     tsb->printf(" Photons %d", l);
2049                     l = 0;
2050                     (void)POVMSUtil_GetInt(msg, kPOVAttrib_PhotonXSamples, &l);
2051                     s = 0;
2052                     (void)POVMSUtil_GetInt(msg, kPOVAttrib_PhotonYSamples, &s);
2053                     tsb->printf(" (sampling %dx%d)", l, s);
2054                 }
2055             }
2056         }
2057     }
2058 
2059     if(ret != kNoErr)
2060         throw POV_EXCEPTION_CODE(ret);*/
2061 }
2062 
2063 }
2064 
2065 }
2066