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