vfe.cpp
1 /******************************************************************************* 2 * vfe.cpp 3 * 4 * This module contains the C++ implementation for the virtual frontend. 5 * 6 * Author: Christopher J. Cason 7 * 8 * --------------------------------------------------------------------------- 9 * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. 10 * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd. 11 * 12 * POV-Ray is free software: you can redistribute it and/or modify 13 * it under the terms of the GNU Affero General Public License as 14 * published by the Free Software Foundation, either version 3 of the 15 * License, or (at your option) any later version. 16 * 17 * POV-Ray is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU Affero General Public License for more details. 21 * 22 * You should have received a copy of the GNU Affero General Public License 23 * along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * --------------------------------------------------------------------------- 25 * POV-Ray is based on the popular DKB raytracer version 2.12. 26 * DKBTrace was originally written by David K. Buck. 27 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. 28 * --------------------------------------------------------------------------- 29 * $File: //depot/public/povray/3.x/vfe/vfe.cpp $ 30 * $Revision: #1 $ 31 * $Change: 6069 $ 32 * $DateTime: 2013/11/06 11:59:40 $ 33 * $Author: chrisc $ 34 *******************************************************************************/ 35 36 #ifdef _MSC_VER 37 #pragma warning(disable : 4244) 38 #pragma warning(disable : 4267) 39 #endif 40 41 #include "frame.h" 42 #include "povray.h" 43 #include "vfe.h" 44 45 // this must be the last file included 46 #include "base/povdebug.h" 47 48 namespace vfe 49 { 50 51 using namespace pov_base; 52 using boost::format; 53 54 //////////////////////////////////////////////////////////////////////////////////////// 55 // 56 // class POVMSMessageDetails 57 // 58 //////////////////////////////////////////////////////////////////////////////////////// 59 60 class POVMSMessageDetails 61 { 62 public: 63 POVMSMessageDetails (POVMS_Object &Obj); 64 virtual ~POVMSMessageDetails () {} ; 65 string GetContext (int NumLines) ; 66 67 protected: 68 string File ; 69 UCS2String UCS2File; 70 string URL ; 71 string Message ; 72 POVMSInt Line ; 73 POVMSInt Col ; 74 POVMSLong Offset ; 75 } ; 76 77 POVMSMessageDetails::POVMSMessageDetails (POVMS_Object& Obj) 78 { 79 char buffer [2048] = ""; 80 UCS2 ubuffer [2048]; 81 POVMSInt l = sizeof (ubuffer); 82 POVMSLong ll ; 83 POVMSObject msgobj (Obj()); 84 POVMSObjectPtr msg = &msgobj; 85 86 Line = Col = 0 ; 87 Offset = -1 ; 88 ubuffer[0] = 0 ; 89 90 if (POVMSUtil_GetUCS2String (msg, kPOVAttrib_FileName, ubuffer, &l) == kNoErr) 91 { 92 UCS2File = ubuffer ; 93 File = UCS2toASCIIString (UCS2File); 94 } 95 if (POVMSUtil_GetLong (msg, kPOVAttrib_Line, &ll) == kNoErr) 96 Line = POVMSInt(ll) ; 97 if (POVMSUtil_GetLong (msg, kPOVAttrib_Column, &ll) == kNoErr) 98 Col = POVMSInt(ll + 1) ; 99 if(POVMSUtil_GetLong(msg, kPOVAttrib_FilePosition, &ll) == kNoErr) 100 Offset = ll ; 101 l = sizeof (buffer) ; 102 if (POVMSUtil_GetString (msg, kPOVAttrib_EnglishText, buffer, &l) == kNoErr) 103 Message = buffer ; 104 105 POVMSObject_Delete(msg); 106 } 107 108 string POVMSMessageDetails::GetContext (int NumLines) 109 { 110 return ("") ; 111 } 112 113 //////////////////////////////////////////////////////////////////////////////////////// 114 // 115 // class ParseErrorDetails, ParseWarningDetails 116 // 117 //////////////////////////////////////////////////////////////////////////////////////// 118 119 class ParseWarningDetails : public POVMSMessageDetails 120 { 121 public: 122 ParseWarningDetails (POVMS_Object &Obj) : POVMSMessageDetails (Obj) {} ; 123 virtual ~ParseWarningDetails () {} ; 124 125 public: 126 using POVMSMessageDetails::File ; 127 using POVMSMessageDetails::UCS2File ; 128 using POVMSMessageDetails::Message ; 129 using POVMSMessageDetails::Line ; 130 using POVMSMessageDetails::Col ; 131 using POVMSMessageDetails::Offset ; 132 } ; 133 134 class ParseErrorDetails : public POVMSMessageDetails 135 { 136 public: 137 ParseErrorDetails (POVMS_Object &Obj) : POVMSMessageDetails (Obj) {} ; 138 virtual ~ParseErrorDetails () {} ; 139 140 public: 141 using POVMSMessageDetails::File ; 142 using POVMSMessageDetails::UCS2File ; 143 using POVMSMessageDetails::Message ; 144 using POVMSMessageDetails::Line ; 145 using POVMSMessageDetails::Col ; 146 using POVMSMessageDetails::Offset ; 147 } ; 148 149 //////////////////////////////////////////////////////////////////////////////////////// 150 // 151 // class vfeConsole 152 // 153 //////////////////////////////////////////////////////////////////////////////////////// 154 155 vfeConsole::vfeConsole(vfeSession *session, int width) : Console(width == -1 ? session->GetConsoleWidth() : width) 156 { 157 m_Session = session; 158 Initialise(); 159 } 160 161 vfeConsole::~vfeConsole() 162 { 163 } 164 165 void vfeConsole::Initialise() 166 { 167 rawBuffer [0] = '\0' ; 168 } 169 170 void vfeConsole::BufferOutput(const char *str, unsigned int chars, vfeSession::MessageType mType) 171 { 172 char *s ; 173 174 // HACK FIXME - this is to prevent duplicate messages 175 if (m_Session->HadErrorMessage() && strncmp (str, "Fatal error in parser: ", 23) == 0) 176 return ; 177 178 if (str [0] == '\n' && str [1] == '\0') 179 { 180 m_Session->AppendStreamMessage (mType, rawBuffer) ; 181 rawBuffer [0] = '\0' ; 182 return ; 183 } 184 185 size_t sLen = chars ; 186 if (sLen == 0) 187 sLen = strlen (str) ; 188 size_t bLen = strlen (rawBuffer) ; 189 if (sLen > sizeof (rawBuffer) - bLen - 1) 190 sLen = sizeof (rawBuffer) - bLen - 1 ; 191 strncat (rawBuffer, str, sLen) ; 192 if ((s = strrchr (rawBuffer, '\n')) != NULL) 193 { 194 *s++ = '\0' ; 195 m_Session->AppendStreamMessage (mType, rawBuffer) ; 196 strcpy (rawBuffer, s) ; 197 } 198 } 199 200 void vfeConsole::Output(const char *str, vfeSession::MessageType mType) 201 { 202 BufferOutput (str, (unsigned int) strlen (str), mType) ; 203 BufferOutput ("\n", 1, mType) ; 204 } 205 206 void vfeConsole::Output(const string& str, vfeSession::MessageType mType) 207 { 208 Output (str.c_str(), mType) ; 209 } 210 211 void vfeConsole::Output(const string& str) 212 { 213 Output (str.c_str()) ; 214 } 215 216 //////////////////////////////////////////////////////////////////////////////////////// 217 // 218 // class vfePlatformBase 219 // 220 //////////////////////////////////////////////////////////////////////////////////////// 221 222 vfePlatformBase::vfePlatformBase(vfeSession& session) : m_Session(&session), PlatformBase() 223 { 224 } 225 226 vfePlatformBase::~vfePlatformBase() 227 { 228 } 229 230 IStream *vfePlatformBase::CreateIStream(const unsigned int stype) 231 { 232 return (new IStream (stype)) ; 233 } 234 235 OStream *vfePlatformBase::CreateOStream(const unsigned int stype) 236 { 237 return (new OStream (stype)) ; 238 } 239 240 UCS2String vfePlatformBase::GetTemporaryPath(void) 241 { 242 return m_Session->GetTemporaryPath(); 243 } 244 245 UCS2String vfePlatformBase::CreateTemporaryFile(void) 246 { 247 return m_Session->CreateTemporaryFile(); 248 } 249 250 void vfePlatformBase::DeleteTemporaryFile(const UCS2String& filename) 251 { 252 m_Session->DeleteTemporaryFile(filename); 253 } 254 255 bool vfePlatformBase::ReadFileFromURL(OStream *file, const UCS2String& url, const UCS2String& referrer) 256 { 257 return false; 258 } 259 260 //////////////////////////////////////////////////////////////////////////////////////// 261 // 262 // class vfeParserMessageHandler 263 // 264 //////////////////////////////////////////////////////////////////////////////////////// 265 266 vfeParserMessageHandler::vfeParserMessageHandler() : ParserMessageHandler() 267 { 268 m_Session = vfeSession::GetSessionFromThreadID(); 269 } 270 271 vfeParserMessageHandler::~vfeParserMessageHandler() 272 { 273 } 274 275 void vfeParserMessageHandler::Options(Console *Con, POVMS_Object& Obj, bool conout) 276 { 277 if (Obj.TryGetBool (kPOVAttrib_OutputAlpha, false)) 278 m_Session->SetUsingAlpha(); 279 if (Obj.TryGetBool (kPOVAttrib_ClocklessAnimation, false)) 280 m_Session->SetClocklessAnimation(); 281 if (Obj.TryGetBool (kPOVAttrib_RealTimeRaytracing, false)) 282 m_Session->SetRealTimeRaytracing(); 283 ParserMessageHandler::Options (Con, Obj, conout) ; 284 } 285 286 void vfeParserMessageHandler::Statistics(Console *Con, POVMS_Object& Obj, bool conout) 287 { 288 ParserMessageHandler::Statistics (Con, Obj, conout) ; 289 } 290 291 void vfeParserMessageHandler::Progress(Console *Con, POVMS_Object& Obj, bool verbose) 292 { 293 switch(Obj.GetType(kPOVMSObjectClassID)) 294 { 295 case kPOVObjectClass_ParserProgress: 296 { 297 m_Session->AppendStatusMessage (format ("Parsing %uK tokens") % (Obj.GetLong (kPOVAttrib_CurrentTokenCount) / 1000)); 298 break; 299 } 300 case kPOVObjectClass_BoundingProgress: 301 { 302 m_Session->AppendStatusMessage (format ("Constructed %uK BSP nodes") % (Obj.GetLong (kPOVAttrib_CurrentNodeCount) / 1000)); 303 break; 304 } 305 } 306 } 307 308 void vfeParserMessageHandler::Warning(Console *Con, POVMS_Object& Obj, bool conout) 309 { 310 ParseWarningDetails d (Obj) ; 311 312 if (d.Message == "") 313 return ; 314 315 // as we provide special treatment for warning messages here if we're not 316 // optimized for console output, we don't duplicate them to the console 317 // regardless of whether or not conout is set. 318 if (m_Session->m_OptimizeForConsoleOutput == false) 319 m_Session->AppendWarningMessage (d.Message, d.UCS2File, d.Line, d.Col) ; 320 321 if (!d.File.empty() && (d.Line > 0)) 322 { 323 format f = format ("File '%s' line %d: %s") % d.File % d.Line % d.Message ; 324 if (m_Session->m_OptimizeForConsoleOutput == false) 325 m_Session->AppendStatusMessage (f) ; 326 else if (conout) 327 Con->puts (f.str().c_str()) ; 328 } 329 else 330 { 331 if (m_Session->m_OptimizeForConsoleOutput == false) 332 m_Session->AppendStatusMessage (d.Message) ; 333 else if (conout) 334 Con->puts (d.Message.c_str()) ; 335 } 336 } 337 338 void vfeParserMessageHandler::Error(Console *Con, POVMS_Object& Obj, bool conout) 339 { 340 ParseErrorDetails d (Obj) ; 341 342 if (d.Message == "" && (d.File == "" || d.Line <= 0)) 343 return ; 344 345 // as we provide special treatment for parser errors here if we're not 346 // optimized for console output, we don't duplicate them to the console 347 // regardless of whether or not conout is set. 348 if (m_Session->m_OptimizeForConsoleOutput == false) 349 m_Session->AppendErrorMessage (d.Message, d.UCS2File, d.Line, d.Col) ; 350 351 if (!d.Message.empty()) 352 { 353 if (!d.File.empty() && (d.Line > 0)) 354 { 355 format f = format ("File '%s' line %d: %s") % d.File % d.Line % d.Message ; 356 if (m_Session->m_OptimizeForConsoleOutput == false) 357 m_Session->AppendStatusMessage (f) ; 358 else if (conout) 359 Con->puts (f.str().c_str()) ; 360 } 361 else 362 { 363 if (m_Session->m_OptimizeForConsoleOutput == false) 364 m_Session->AppendStatusMessage (d.Message) ; 365 if (conout) 366 if (m_Session->m_OptimizeForConsoleOutput == true) 367 Con->puts (d.Message.c_str()) ; 368 } 369 } 370 else 371 { 372 format f = format ("Parse error in file '%s' at line %d") % d.File % d.Line ; 373 if (m_Session->m_OptimizeForConsoleOutput == false) 374 m_Session->AppendStatusMessage (f) ; 375 if (conout) 376 if (m_Session->m_OptimizeForConsoleOutput == true) 377 Con->puts (f.str().c_str()) ; 378 } 379 } 380 381 void vfeParserMessageHandler::FatalError(Console *Con, POVMS_Object& Obj, bool conout) 382 { 383 m_Session->SetFailed(); 384 Error (Con, Obj, conout) ; 385 } 386 387 void vfeParserMessageHandler::DebugInfo(Console *Con, POVMS_Object& Obj, bool conout) 388 { 389 string str(Obj.GetString(kPOVAttrib_EnglishText)); 390 if (m_Session->m_OptimizeForConsoleOutput == true) 391 { 392 if (conout) 393 Con->puts (str.c_str()) ; 394 } 395 else 396 m_Session->AppendStreamMessage (vfeSession::mDebug, str.c_str()) ; 397 } 398 399 //////////////////////////////////////////////////////////////////////////////////////// 400 // 401 // class vfeRenderMessageHandler 402 // 403 //////////////////////////////////////////////////////////////////////////////////////// 404 405 vfeRenderMessageHandler::vfeRenderMessageHandler() : RenderMessageHandler() 406 { 407 m_Session = vfeSession::GetSessionFromThreadID(); 408 } 409 410 vfeRenderMessageHandler::~vfeRenderMessageHandler() 411 { 412 } 413 414 void vfeRenderMessageHandler::Options(Console *Con, POVMS_Object& Obj, bool conout) 415 { 416 RenderMessageHandler::Options (Con, Obj, conout) ; 417 } 418 419 void vfeRenderMessageHandler::Statistics(Console *Con, POVMS_Object& Obj, bool conout) 420 { 421 RenderMessageHandler::Statistics (Con, Obj, conout) ; 422 } 423 424 void vfeRenderMessageHandler::Progress(Console *Con, POVMS_Object& Obj, bool verbose) 425 { 426 switch (Obj.GetType(kPOVMSObjectClassID)) 427 { 428 case kPOVObjectClass_PhotonProgress: 429 { 430 int cpc (Obj.GetInt (kPOVAttrib_CurrentPhotonCount)) ; 431 m_Session->AppendStatusMessage (format ("Photon count %u") % cpc, 250) ; 432 break; 433 } 434 case kPOVObjectClass_RadiosityProgress: 435 { 436 int pc (Obj.GetInt (kPOVAttrib_Pixels)) ; 437 int cc (Obj.GetInt (kPOVAttrib_PixelsCompleted)) ; 438 m_Session->SetPixelsRendered(cc, pc); 439 int percent = pc > 0 ? int ((cc * 100.0) / pc) : 0 ; 440 m_Session->SetPercentComplete (percent); 441 m_Session->AppendStatusMessage (format ("Performing radiosity pretrace: %d of %d pixels (%d%%)") % cc % pc % percent, 250) ; 442 break; 443 } 444 case kPOVObjectClass_RenderProgress: 445 { 446 int pc (Obj.GetInt (kPOVAttrib_Pixels)) ; 447 int cc (Obj.GetInt (kPOVAttrib_PixelsCompleted)) ; 448 449 if (m_Session->GetRealTimeRaytracing() == false) 450 { 451 m_Session->SetPixelsRendered(cc, pc); 452 int percent = pc > 0 ? (int) ((cc * 100.0) / pc) : 0 ; 453 m_Session->SetPercentComplete (percent); 454 if (verbose == true || m_Session->m_OptimizeForConsoleOutput == false) 455 m_Session->AppendStatusMessage (format ("Rendered %u of %u pixels (%d%%)") % cc % pc % percent, 250) ; 456 } 457 else 458 { 459 m_Session->SetPixelsRendered(cc % pc, pc); 460 float elapsed = m_Session->GetElapsedTime() / 1000.0f; 461 float frames = (float) cc / pc; 462 float fps = frames / elapsed; 463 if (verbose == true || m_Session->m_OptimizeForConsoleOutput == false) 464 m_Session->AppendStatusMessage (format ("Rendered %g frames over %g seconds (%g FPS)") % frames % elapsed % fps, 250) ; 465 } 466 break; 467 } 468 } 469 } 470 471 void vfeRenderMessageHandler::Warning(Console *Con, POVMS_Object& Obj, bool conout) 472 { 473 RenderMessageHandler::Warning (Con, Obj, conout) ; 474 } 475 476 void vfeRenderMessageHandler::Error(Console *Con, POVMS_Object& Obj, bool conout) 477 { 478 m_Session->SetFailed(); 479 RenderMessageHandler::Error (Con, Obj, conout) ; 480 } 481 482 void vfeRenderMessageHandler::FatalError(Console *Con, POVMS_Object& Obj, bool conout) 483 { 484 m_Session->SetFailed(); 485 RenderMessageHandler::FatalError (Con, Obj, conout) ; 486 } 487 488 //////////////////////////////////////////////////////////////////////////////////////// 489 // 490 // class vfeProcessRenderOptions 491 // 492 //////////////////////////////////////////////////////////////////////////////////////// 493 494 vfeProcessRenderOptions::vfeProcessRenderOptions(vfeSession *Session) : ProcessRenderOptions(), m_Session(Session) 495 { 496 } 497 498 vfeProcessRenderOptions::~vfeProcessRenderOptions() 499 { 500 } 501 502 int vfeProcessRenderOptions::ReadSpecialOptionHandler(INI_Parser_Table *Table, char *Param, POVMSObjectPtr Obj) 503 { 504 return ProcessRenderOptions::ReadSpecialOptionHandler (Table, Param, Obj); 505 } 506 507 int vfeProcessRenderOptions::ReadSpecialSwitchHandler(Cmd_Parser_Table *Table, char *Param, POVMSObjectPtr Obj, bool On) 508 { 509 return ProcessRenderOptions::ReadSpecialSwitchHandler (Table, Param, Obj, On); 510 } 511 512 int vfeProcessRenderOptions::WriteSpecialOptionHandler(INI_Parser_Table *Table, POVMSObjectPtr Obj, OTextStream *S) 513 { 514 return ProcessRenderOptions::WriteSpecialOptionHandler (Table, Obj, S); 515 } 516 517 bool vfeProcessRenderOptions::WriteOptionFilter(INI_Parser_Table *Table) 518 { 519 return ProcessRenderOptions::WriteOptionFilter (Table); 520 } 521 522 int vfeProcessRenderOptions::ProcessUnknownString(char *String, POVMSObjectPtr Obj) 523 { 524 return ProcessRenderOptions::ProcessUnknownString (String, Obj); 525 } 526 527 ITextStream *vfeProcessRenderOptions::OpenFileForRead(const char *Name, POVMSObjectPtr Obj) 528 { 529 return (ProcessRenderOptions::OpenFileForRead (Name, Obj)) ; 530 } 531 532 OTextStream *vfeProcessRenderOptions::OpenFileForWrite(const char *Name, POVMSObjectPtr Obj) 533 { 534 return (ProcessRenderOptions::OpenFileForWrite (Name, Obj)) ; 535 } 536 537 void vfeProcessRenderOptions::ParseError(const char *format, ...) 538 { 539 char str[1024]; 540 va_list marker; 541 542 va_start(marker, format); 543 vsnprintf(str, sizeof(str)-2, format, marker); 544 va_end(marker); 545 546 m_Session->AppendStatusMessage (str); 547 m_Session->AppendErrorMessage (str) ; 548 m_Session->SetFailed(); 549 } 550 551 void vfeProcessRenderOptions::ParseErrorAt(ITextStream *file, const char *format, ...) 552 { 553 char str[1024]; 554 va_list marker; 555 556 va_start(marker, format); 557 vsnprintf(str, sizeof(str)-2, format, marker); 558 va_end(marker); 559 560 m_Session->AppendStatusMessage (str); 561 m_Session->AppendErrorMessage (str, file->name(), file->line(), 0) ; 562 m_Session->SetFailed(); 563 } 564 565 void vfeProcessRenderOptions::WriteError(const char *format, ...) 566 { 567 char str[1024]; 568 va_list marker; 569 570 va_start(marker, format); 571 vsnprintf(str, sizeof(str)-2, format, marker); 572 va_end(marker); 573 574 m_Session->AppendStatusMessage (str); 575 m_Session->AppendErrorMessage (str) ; 576 m_Session->SetFailed(); 577 } 578 579 //////////////////////////////////////////////////////////////////////////////////////// 580 // 581 // class VirtualFrontEnd 582 // 583 //////////////////////////////////////////////////////////////////////////////////////// 584 585 VirtualFrontEnd::VirtualFrontEnd(vfeSession& session, POVMSContext ctx, POVMSAddress addr, POVMS_Object& msg, POVMS_Object *result, shared_ptr<Console>& console) : 586 m_Session(&session), m_PlatformBase(session), renderFrontend (ctx) 587 { 588 backendAddress = addr ; 589 state = kReady ; 590 m_PostPauseState = kReady; 591 consoleResult = NULL ; 592 displayResult = NULL ; 593 m_PauseRequested = m_PausedAfterFrame = false; 594 renderFrontend.ConnectToBackend(backendAddress, msg, result, console); 595 } 596 597 VirtualFrontEnd::~VirtualFrontEnd() 598 { 599 // file-backed images may require a reference to PlatformBase to delete temporary files 600 // we need to explicitly delete it here since otherwise PlatformBase will have been destroyed 601 // before the shared_ptr does its cleanup 602 imageProcessing.reset(); 603 if (backendAddress != POVMSInvalidAddress) 604 renderFrontend.DisconnectFromBackend(backendAddress); 605 state = kUnknown; 606 } 607 608 bool VirtualFrontEnd::Start(POVMS_Object& opts) 609 { 610 if (state != kReady) 611 return false; 612 613 m_Session->Clear(); 614 animationProcessing.reset() ; 615 m_PauseRequested = m_PausedAfterFrame = false; 616 m_PostPauseState = kReady; 617 618 Path ip (m_Session->GetInputFilename()); 619 shelloutProcessing.reset(m_Session->CreateShelloutProcessing(opts, UCS2toASCIIString(ip.GetFile()), m_Session->GetRenderWidth(), m_Session->GetRenderHeight())) ; 620 shelloutProcessing->SetCancelMessage("Render halted because the %1% shell-out ('%6%') requested POV-Ray to %5%."); 621 shelloutProcessing->SetSkipMessage("The %1% shell-out ('%3%') requested POV-Ray to %2%."); 622 623 POVMS_List declares; 624 if(opts.Exist(kPOVAttrib_Declare) == true) 625 opts.Get(kPOVAttrib_Declare, declares); 626 627 POVMS_Object image_width(kPOVMSType_WildCard); 628 image_width.SetString(kPOVAttrib_Identifier, "image_width"); 629 image_width.SetFloat(kPOVAttrib_Value, opts.TryGetInt(kPOVAttrib_Width, 160)); 630 declares.Append(image_width); 631 632 POVMS_Object image_height(kPOVMSType_WildCard); 633 image_height.SetString(kPOVAttrib_Identifier, "image_height"); 634 image_height.SetFloat(kPOVAttrib_Value, opts.TryGetInt(kPOVAttrib_Height, 120)); 635 declares.Append(image_height); 636 637 POVMS_Object input_file_name(kPOVMSType_WildCard); 638 input_file_name.SetString(kPOVAttrib_Identifier, "input_file_name"); 639 input_file_name.SetString(kPOVAttrib_Value, UCS2toASCIIString(ip.GetFile()).c_str()); 640 declares.Append(input_file_name); 641 642 int initialFrame = opts.TryGetInt (kPOVAttrib_InitialFrame, 0) ; 643 int finalFrame = opts.TryGetInt (kPOVAttrib_FinalFrame, 0) ; 644 if ((initialFrame == 0 && finalFrame == 0) || (initialFrame == 1 && finalFrame == 1)) 645 { 646 POVMS_Object clock_delta(kPOVMSType_WildCard); 647 clock_delta.SetString(kPOVAttrib_Identifier, "clock_delta"); 648 clock_delta.SetFloat(kPOVAttrib_Value, 0.0f); 649 declares.Append(clock_delta); 650 651 POVMS_Object final_clock(kPOVMSType_WildCard); 652 final_clock.SetString(kPOVAttrib_Identifier, "final_clock"); 653 final_clock.SetFloat(kPOVAttrib_Value, 0.0f); 654 declares.Append(final_clock); 655 656 POVMS_Object final_frame(kPOVMSType_WildCard); 657 final_frame.SetString(kPOVAttrib_Identifier, "final_frame"); 658 final_frame.SetFloat(kPOVAttrib_Value, 0.0f); 659 declares.Append(final_frame); 660 661 POVMS_Object frame_number(kPOVMSType_WildCard); 662 frame_number.SetString(kPOVAttrib_Identifier, "frame_number"); 663 frame_number.SetFloat(kPOVAttrib_Value, 0.0f); 664 declares.Append(frame_number); 665 666 POVMS_Object initial_clock(kPOVMSType_WildCard); 667 initial_clock.SetString(kPOVAttrib_Identifier, "initial_clock"); 668 initial_clock.SetFloat(kPOVAttrib_Value, 0.0f); 669 declares.Append(initial_clock); 670 671 POVMS_Object initial_frame(kPOVMSType_WildCard); 672 initial_frame.SetString(kPOVAttrib_Identifier, "initial_frame"); 673 initial_frame.SetFloat(kPOVAttrib_Value, 0.0f); 674 declares.Append(initial_frame); 675 676 opts.Set(kPOVAttrib_Declare, declares); 677 // optimization: reset imageProcessing now even though the following assign 678 // will free the old pointer (if it exists). this can potentially free a 679 // significant amount of memory and may in some circumstances prevent the 680 // image allocation from failing. TODO: it may be useful to check whether 681 // we can re-use an old imageProcessing instance (e.g. if image options are 682 // the same). 683 imageProcessing.reset(); 684 685 // TODO: update ImageProcessing with the means of accepting and caching 686 // blocks of pixels as opposed to individual ones, with a back-end that 687 // can serialize completed rows to the final image output file. 688 options = opts; 689 690 if (m_Session->OutputToFileSet()) 691 { 692 imageProcessing = shared_ptr<ImageProcessing> (new ImageProcessing (opts)); 693 UCS2String filename = imageProcessing->GetOutputFilename (opts, 0, 0); 694 options.SetUCS2String (kPOVAttrib_OutputFile, filename.c_str()); 695 696 if ((imageProcessing->OutputIsStdout() || imageProcessing->OutputIsStderr()) && m_Session->ImageOutputToStdoutSupported() == false) 697 throw POV_EXCEPTION(kCannotOpenFileErr, "Image output to STDOUT/STDERR not supported on this platform"); 698 699 // test access permission now to avoid surprise later after waiting for 700 // the render to complete. 701 if (imageProcessing->OutputIsStdout() == false && imageProcessing->OutputIsStderr() == false && m_Session->TestAccessAllowed(filename, true) == false) 702 { 703 string str ("IO Restrictions prohibit write access to '") ; 704 str += UCS2toASCIIString(filename); 705 str += "'"; 706 throw POV_EXCEPTION(kCannotOpenFileErr, str); 707 } 708 shelloutProcessing->SetOutputFile(UCS2toASCIIString(filename)); 709 m_Session->AdviseOutputFilename (filename); 710 } 711 } 712 else 713 { 714 // the output filename is set in Process() 715 m_Session->SetRenderingAnimation(); 716 opts.Set(kPOVAttrib_Declare, declares); 717 imageProcessing.reset(); 718 if (m_Session->OutputToFileSet()) 719 imageProcessing = shared_ptr<ImageProcessing> (new ImageProcessing (opts)) ; 720 animationProcessing = shared_ptr<AnimationProcessing> (new AnimationProcessing (opts)) ; 721 options = animationProcessing->GetFrameRenderOptions () ; 722 } 723 724 state = kStarting; 725 726 return true; 727 } 728 729 bool VirtualFrontEnd::Stop() 730 { 731 bool result = false; 732 733 try 734 { 735 switch(state) 736 { 737 case kStarting: 738 state = kStopped; 739 m_Session->SetFailed(); 740 result = true; 741 break; 742 743 case kPreSceneShellout: 744 case kPreFrameShellout: 745 case kPostFrameShellout: 746 case kPostSceneShellout: 747 if (shelloutProcessing->ShelloutRunning()) 748 if (!shelloutProcessing->KillShellouts(2, false) && !shelloutProcessing->KillShellouts(1, true)) 749 m_Session->AppendErrorAndStatusMessage("Failed to terminate currently-running shellout process") ; 750 if (state == kPostSceneShellout) 751 { 752 state = kDone; 753 return true; 754 } 755 m_Session->SetFailed(); 756 state = kStopped; 757 result = true; 758 break; 759 760 case kPostShelloutPause: 761 m_Session->SetFailed(); 762 state = kStopping; 763 result = true; 764 break; 765 766 case kParsing: 767 case kPausedParsing: 768 // the parser could be already in a finished state, even if it accepted a pause earlier 769 try { renderFrontend.StopParser(sceneId); } catch (pov_base::Exception&) { } 770 m_Session->SetFailed(); 771 state = kStopping; 772 result = true; 773 break; 774 775 case kRendering: 776 case kPausedRendering: 777 m_Session->SetFailed(); 778 if (m_PausedAfterFrame == true) 779 { 780 m_PausedAfterFrame = false; 781 state = kStopped; 782 } 783 else 784 { 785 // the renderer could be already in a finished state, even if it accepted a pause earlier 786 try { renderFrontend.StopRender(viewId); } catch (pov_base::Exception&) { } 787 state = kStopping; 788 } 789 result = true; 790 break; 791 } 792 } 793 catch (pov_base::Exception& e) 794 { 795 m_Session->SetFailed(); 796 m_Session->AppendErrorAndStatusMessage (e.what()) ; 797 } 798 try 799 { 800 shelloutProcessing->ProcessEvent(ShelloutProcessing::userAbort); 801 } 802 catch (pov_base::Exception& e) 803 { 804 // if it's a kCannotOpenFileErr, it means permission to run the process was denied 805 // we don't set failed in that case as we allow shelloutprocessing to handle it 806 if (!e.codevalid() || (e.code() != kCannotOpenFileErr)) 807 m_Session->SetFailed(); 808 m_Session->AppendErrorAndStatusMessage (e.what()) ; 809 } 810 811 return result; 812 } 813 814 bool VirtualFrontEnd::Pause() 815 { 816 try 817 { 818 switch(state) 819 { 820 case kParsing: 821 renderFrontend.PauseParser(sceneId); 822 state = kPausedParsing; 823 return true; 824 825 case kPreSceneShellout: 826 case kPreFrameShellout: 827 case kPostFrameShellout: 828 m_PauseRequested = true; 829 return true; 830 831 case kRendering: 832 renderFrontend.PauseRender(viewId); 833 state = kPausedRendering; 834 return true; 835 836 default: 837 break; 838 } 839 } 840 catch (pov_base::Exception&) 841 { 842 return false; 843 } 844 return false; 845 } 846 847 bool VirtualFrontEnd::Resume() 848 { 849 try 850 { 851 switch(state) 852 { 853 case kPostShelloutPause: 854 state = m_PostPauseState; 855 return true; 856 857 case kPausedParsing: 858 if (renderFrontend.GetSceneState(sceneId) == SceneData::Scene_Paused) 859 renderFrontend.ResumeParser(sceneId); 860 state = kParsing; 861 return true; 862 863 case kPausedRendering: 864 if (m_PausedAfterFrame) 865 { 866 state = kStarting; 867 m_PausedAfterFrame = false; 868 return true; 869 } 870 if (renderFrontend.GetViewState(viewId) == ViewData::View_Paused) 871 renderFrontend.ResumeRender(viewId); 872 state = kRendering; 873 return true; 874 875 default: 876 break; 877 } 878 } 879 catch (pov_base::Exception&) 880 { 881 return (false) ; 882 } 883 return false; 884 } 885 886 bool VirtualFrontEnd::HandleShelloutCancel() 887 { 888 if (!shelloutProcessing->RenderCancelled()) 889 return false; 890 891 int code(shelloutProcessing->ExitCode()); 892 string str(shelloutProcessing->GetCancelMessage()); 893 if (code) 894 { 895 state = kFailed; 896 m_Session->SetFailed(); 897 } 898 else 899 { 900 state = kStopped; 901 m_Session->SetSucceeded(true); 902 } 903 m_Session->AppendErrorMessage(str) ; 904 m_Session->AppendStatusMessage(str) ; 905 return true; 906 } 907 908 State VirtualFrontEnd::Process() 909 { 910 if (state == kReady) 911 return kReady; 912 913 switch(state) 914 { 915 case kStarting: 916 try 917 { 918 m_Session->SetSucceeded (false); 919 if (animationProcessing != NULL) 920 { 921 shelloutProcessing->SetFrameClock(animationProcessing->GetFrameNumber(), animationProcessing->GetClockValue()); 922 if (shelloutProcessing->SkipNextFrame() == false) 923 { 924 UCS2String filename; 925 int frame = animationProcessing->GetFrameNumber() - animationProcessing->GetStartFrame() ; 926 options = animationProcessing->GetFrameRenderOptions (); 927 if (m_Session->OutputToFileSet()) 928 { 929 filename = imageProcessing->GetOutputFilename (options, animationProcessing->GetFrameNumber(), animationProcessing->GetFrameNumberDigits()); 930 options.SetUCS2String (kPOVAttrib_OutputFile, filename.c_str()); 931 932 // test access permission now to avoid surprise later after waiting for 933 // the render to complete. 934 if (m_Session->TestAccessAllowed(filename, true) == false) 935 { 936 string str ("IO Restrictions prohibit write access to '") ; 937 str += UCS2toASCIIString(filename); 938 str += "'"; 939 throw POV_EXCEPTION(kCannotOpenFileErr, str); 940 } 941 shelloutProcessing->SetOutputFile(UCS2toASCIIString(filename)); 942 m_Session->AdviseOutputFilename (filename); 943 } 944 m_Session->AppendAnimationStatus (frame + 1, animationProcessing->GetTotalFrames(), filename) ; 945 } 946 } 947 948 bool hadPreScene = shelloutProcessing->HadPreScene(); 949 950 // will do pre-scene instead if it hasn't yet been done 951 try 952 { 953 shelloutProcessing->ProcessEvent(ShelloutProcessing::preFrame); 954 } 955 catch (pov_base::Exception& e) 956 { 957 // if it's a kCannotOpenFileErr, it means permission to run the process was denied 958 // we don't set failed in that case as we allow shelloutprocessing to handle it 959 m_Session->AppendErrorAndStatusMessage (e.what()) ; 960 if (!e.codevalid() || (e.code() != kCannotOpenFileErr)) 961 { 962 m_Session->SetFailed(); 963 return state = kFailed; 964 } 965 } 966 967 // returns true if cancel has been requested 968 if (HandleShelloutCancel()) 969 return state; 970 971 state = hadPreScene ? kPreFrameShellout : kPreSceneShellout; 972 return state; 973 } 974 catch(pov_base::Exception& e) 975 { 976 m_Session->SetFailed(); 977 m_Session->AppendErrorAndStatusMessage (e.what()) ; 978 return state = kFailed; 979 } 980 981 case kPreSceneShellout: 982 if (shelloutProcessing->ShelloutRunning() || HandleShelloutCancel()) 983 return state; 984 985 // if a pause was requested by the user whilst the shellout was still running, do it now 986 if (m_PauseRequested) 987 { 988 m_PostPauseState = kStarting; 989 m_PauseRequested = false; 990 return state = kPostShelloutPause; 991 } 992 993 // go back to kStarting; it won't run pre-scene again 994 return state = kStarting; 995 996 case kPreFrameShellout: 997 if (shelloutProcessing->ShelloutRunning() || HandleShelloutCancel()) 998 return state; 999 1000 if (shelloutProcessing->SkipNextFrame()) 1001 { 1002 string str(shelloutProcessing->GetSkipMessage()); 1003 m_Session->AppendStatusMessage (str) ; 1004 m_Session->AppendStreamMessage (vfeSession::mInformation, str.c_str()) ; 1005 if ((animationProcessing != NULL) && (animationProcessing->MoreFrames() == true)) 1006 { 1007 animationProcessing->ComputeNextFrame(); 1008 m_Session->SetPixelsRendered(0, m_Session->GetTotalPixels()); 1009 m_Session->SetPercentComplete(0); 1010 if (m_PauseRequested) 1011 { 1012 m_PostPauseState = kStarting; 1013 m_PauseRequested = false; 1014 return state = kPostShelloutPause; 1015 } 1016 return state = kStarting; 1017 } 1018 else 1019 { 1020 m_Session->SetSucceeded (true); 1021 if (m_PauseRequested) 1022 { 1023 m_PostPauseState = kStopped; 1024 m_PauseRequested = false; 1025 return state = kPostShelloutPause; 1026 } 1027 return state = kStopped; 1028 } 1029 } 1030 1031 // now set up the scene in preparation for parsing, then start the parser 1032 try { sceneId = renderFrontend.CreateScene(backendAddress, options, boost::bind(&vfe::VirtualFrontEnd::CreateConsole, this)); } 1033 catch(pov_base::Exception& e) 1034 { 1035 m_Session->SetFailed(); 1036 m_Session->AppendErrorMessage (e.what()) ; 1037 m_Session->AppendStatusMessage (e.what()) ; 1038 return state = kFailed; 1039 } 1040 try { renderFrontend.StartParser(sceneId, options); } 1041 catch(pov_base::Exception& e) 1042 { 1043 m_Session->SetFailed(); 1044 m_Session->AppendErrorMessage (e.what()) ; 1045 m_Session->AppendStatusMessage (e.what()) ; 1046 return state = kFailed; 1047 } 1048 if (m_PauseRequested) 1049 { 1050 m_PostPauseState = kParsing; 1051 m_PauseRequested = false; 1052 return state = kPostShelloutPause; 1053 } 1054 return state = kParsing; 1055 1056 case kParsing: 1057 case kPausedParsing: 1058 switch(renderFrontend.GetSceneState(sceneId)) 1059 { 1060 case SceneData::Scene_Paused: 1061 return state = kPausedParsing; 1062 1063 case SceneData::Scene_Failed: 1064 m_Session->SetFailed(); 1065 return state = kStopped; 1066 1067 case SceneData::Scene_Stopping: 1068 return state = kStopping; 1069 1070 case SceneData::Scene_Ready: 1071 if (state == kPausedParsing) 1072 { 1073 // it's possible for the parser to transition to Scene_Ready after a successful pause request. 1074 // this typically happens if the request comes in very close to the end of a parse, since the 1075 // task thread only checks the pause state intermittently. we don't start the renderer in this 1076 // case. 1077 return state; 1078 } 1079 try { viewId = renderFrontend.CreateView(sceneId, options, imageProcessing, boost::bind(&vfe::VirtualFrontEnd::CreateDisplay, this, _1, _2, _3)); } 1080 catch(pov_base::Exception& e) 1081 { 1082 m_Session->SetFailed(); 1083 m_Session->AppendErrorMessage (e.what()) ; 1084 m_Session->AppendStatusMessage (e.what()) ; 1085 return state = kFailed; 1086 } 1087 try { renderFrontend.StartRender(viewId, options); } 1088 catch(pov_base::Exception& e) 1089 { 1090 m_Session->ClearStatusMessages(); 1091 if (e.codevalid() && e.code() == kImageAlreadyRenderedErr) 1092 { 1093 // this is not a failure; continue has been requested and 1094 // the file has already been rendered, so we skip it. 1095 m_Session->AppendStatusMessage ("File already rendered and continue requested; skipping.") ; 1096 m_Session->AppendStreamMessage (vfeSession::mInformation, "File already rendered and continue requested; skipping.") ; 1097 1098 /* [JG] the block here is a duplicate of actions done after 1099 * the post frame shellout (that won't be reached because 1100 * the image was already there). 1101 */ 1102 try { renderFrontend.CloseView(viewId); } 1103 catch (pov_base::Exception&) { /* Ignore any error here! */ } 1104 try { renderFrontend.CloseScene(sceneId); } 1105 catch (pov_base::Exception&) { /* Ignore any error here! */ } 1106 1107 if ((animationProcessing != NULL) && (animationProcessing->MoreFrames() == true)) 1108 { 1109 animationProcessing->ComputeNextFrame(); 1110 m_Session->SetPixelsRendered(0, m_Session->GetTotalPixels()); 1111 m_Session->SetPercentComplete(0); 1112 return state = kStarting; 1113 } 1114 else 1115 { 1116 m_Session->SetSucceeded (true); 1117 return state = kStopped; 1118 } 1119 } 1120 1121 m_Session->SetFailed(); 1122 m_Session->AppendErrorMessage (e.what()) ; 1123 m_Session->AppendStatusMessage (e.what()) ; 1124 return state = kFailed; 1125 } 1126 1127 // now we display the render window, if enabled 1128 shared_ptr<Display> display(GetDisplay()); 1129 if (display != NULL) 1130 { 1131 vfeDisplay *disp = dynamic_cast<vfeDisplay *>(display.get()); 1132 if (disp != NULL) 1133 disp->Show () ; 1134 } 1135 return state = kRendering; 1136 } 1137 return kParsing; 1138 1139 case kRendering: 1140 case kPausedRendering: 1141 switch(renderFrontend.GetViewState(viewId)) 1142 { 1143 case ViewData::View_Paused: 1144 return state = kPausedRendering; 1145 1146 case ViewData::View_Failed: 1147 m_Session->SetFailed(); 1148 return state = kStopped; 1149 1150 case ViewData::View_Stopping: 1151 return state = kStopping; 1152 1153 case ViewData::View_Rendered: 1154 if (state == kPausedRendering) 1155 { 1156 // it's possible for the renderer to transition to View_Rendered after a successful pause request. 1157 return kPausedRendering; 1158 } 1159 try 1160 { 1161 if (animationProcessing != NULL) 1162 { 1163 if (m_Session->OutputToFileSet()) 1164 m_Session->AdviseOutputFilename (imageProcessing->WriteImage(options, animationProcessing->GetFrameNumber(), animationProcessing->GetFrameNumberDigits())); 1165 m_Session->AdviseFrameCompleted(); 1166 } 1167 else 1168 if (m_Session->OutputToFileSet()) 1169 m_Session->AdviseOutputFilename (imageProcessing->WriteImage(options)); 1170 } 1171 catch (pov_base::Exception& e) 1172 { 1173 m_Session->SetFailed(); 1174 m_Session->AppendErrorMessage (e.what()) ; 1175 m_Session->AppendStatusMessage (e.what()) ; 1176 // TODO: perhaps we should allow them to pause the queue/insert render 1177 // here if need be. 1178 return state = kFailed; 1179 } 1180 try 1181 { 1182 shelloutProcessing->ProcessEvent(ShelloutProcessing::postFrame); 1183 } 1184 catch (pov_base::Exception& e) 1185 { 1186 // if it's a kCannotOpenFileErr, it means permission to run the process was denied 1187 // we don't set failed in that case as we allow shelloutprocessing to handle it 1188 m_Session->AppendErrorAndStatusMessage (e.what()); 1189 if (!e.codevalid() || (e.code() != kCannotOpenFileErr)) 1190 { 1191 m_Session->SetFailed(); 1192 return state = kFailed; 1193 } 1194 } 1195 1196 // check for cancel here: if the return value is true, state has already been changed 1197 if (HandleShelloutCancel()) 1198 return state; 1199 1200 return state = kPostFrameShellout; 1201 1202 default: 1203 break; 1204 } 1205 return kRendering; 1206 1207 case kPostFrameShellout: 1208 if (shelloutProcessing->ShelloutRunning() || HandleShelloutCancel()) 1209 return state; 1210 if ((animationProcessing == NULL) || animationProcessing->MoreFrames() == false) 1211 { 1212 m_Session->SetSucceeded (true); 1213 if (m_PauseRequested) 1214 { 1215 m_PostPauseState = kStopped; 1216 m_PauseRequested = false; 1217 return state = kPostShelloutPause; 1218 } 1219 return state = kStopped; 1220 } 1221 if (shelloutProcessing->SkipAllFrames()) 1222 { 1223 string str(shelloutProcessing->GetSkipMessage()); 1224 m_Session->SetSucceeded (true); 1225 m_Session->AppendStatusMessage (str) ; 1226 m_Session->AppendStreamMessage (vfeSession::mInformation, str.c_str()) ; 1227 if (m_PauseRequested) 1228 { 1229 m_PostPauseState = kStopped; 1230 m_PauseRequested = false; 1231 return state = kPostShelloutPause; 1232 } 1233 return state = kStopped; 1234 } 1235 /* [JG] the actions hereafter should be also done 1236 * when the image already existed: tidy up the data before next frame or stop 1237 */ 1238 try { renderFrontend.CloseView(viewId); } 1239 catch (pov_base::Exception&) { /* Ignore any error here! */ } 1240 try { renderFrontend.CloseScene(sceneId); } 1241 catch (pov_base::Exception&) { /* Ignore any error here! */ } 1242 animationProcessing->ComputeNextFrame(); 1243 if (m_Session->GetPauseWhenDone()) 1244 { 1245 // wait for a manual continue 1246 m_PausedAfterFrame = true; 1247 m_PauseRequested = false; 1248 return state = kPausedRendering; 1249 } 1250 if (m_PauseRequested) 1251 { 1252 m_PostPauseState = kStarting; 1253 m_PauseRequested = false; 1254 return state = kPostShelloutPause; 1255 } 1256 return state = kStarting; 1257 1258 case kPostSceneShellout: 1259 if (shelloutProcessing->ShelloutRunning()) 1260 return state; 1261 return state = kDone; 1262 1263 case kPostShelloutPause: 1264 break; 1265 1266 case kStopping: 1267 if (renderFrontend.GetSceneState(sceneId) == SceneData::Scene_Ready || renderFrontend.GetSceneState(sceneId) == SceneData::Scene_Failed) 1268 return state = kStopped; 1269 if (renderFrontend.GetViewState(viewId) == ViewData::View_Rendered || renderFrontend.GetViewState(viewId) == ViewData::View_Failed) 1270 return state = kStopped; 1271 return kStopping; 1272 1273 case kFailed: 1274 m_Session->SetFailed(); 1275 // ShelloutProcessing ignores the fatal error event if it requested a cancel 1276 try { shelloutProcessing->ProcessEvent(ShelloutProcessing::fatalError); } 1277 catch (pov_base::Exception&) { /* Ignore any error here */ } 1278 return state = kStopped; 1279 1280 case kStopped: 1281 try { renderFrontend.CloseView(viewId); } 1282 catch (pov_base::Exception&) { /* Ignore any error here! */ } 1283 try { renderFrontend.CloseScene(sceneId); } 1284 catch (pov_base::Exception&) { /* Ignore any error here! */ } 1285 animationProcessing.reset(); 1286 imageProcessing.reset(); 1287 1288 // we only run the post-scene or failed action if we have passed the pre-scene point 1289 // i.e. if we stop before pre-scene, we don't run post-scene 1290 if (shelloutProcessing->HadPreScene()) 1291 { 1292 if (m_Session->Failed()) 1293 { 1294 // it is possible for us to get to kStopped without going through kFailed 1295 // so we call the failed shellout event here just in case: ShelloutProcessing 1296 // can handle being called twice for the same event. 1297 try { shelloutProcessing->ProcessEvent(ShelloutProcessing::fatalError); } 1298 catch (pov_base::Exception&) { /* Ignore any error here */ } 1299 } 1300 1301 if (!shelloutProcessing->HadPostScene()) 1302 { 1303 try { shelloutProcessing->ProcessEvent(ShelloutProcessing::postScene); } 1304 catch (pov_base::Exception&) { /* Ignore any error here! */ } 1305 return state = kPostSceneShellout; 1306 } 1307 } 1308 1309 return state = kDone; 1310 1311 case kDone: 1312 return state = kReady; 1313 } 1314 1315 return state; 1316 } 1317 1318 void VirtualFrontEnd::SetResultPointers(Console **cr, Image **ir, Display **dr) 1319 { 1320 consoleResult = cr; 1321 displayResult = dr; 1322 } 1323 1324 bool VirtualFrontEnd::IsPausable (void) 1325 { 1326 switch (GetState ()) 1327 { 1328 case kParsing : 1329 case kPausedParsing : 1330 case kRendering : 1331 case kPausedRendering : 1332 case kPreSceneShellout: 1333 case kPreFrameShellout: 1334 case kPostFrameShellout: 1335 case kPostShelloutPause: 1336 return (true) ; 1337 1338 default : 1339 return (false) ; 1340 } 1341 } 1342 1343 bool VirtualFrontEnd::Paused (void) 1344 { 1345 switch (GetState ()) 1346 { 1347 case kPausedParsing : 1348 case kPausedRendering : 1349 case kPostShelloutPause: 1350 return (true) ; 1351 1352 case kPreSceneShellout: 1353 case kPreFrameShellout: 1354 case kPostFrameShellout: 1355 return m_PauseRequested; 1356 1357 default : 1358 return (false) ; 1359 } 1360 } 1361 1362 //////////////////////////////////////////////////////////////////////////////////////// 1363 // 1364 // helper funtions 1365 // 1366 //////////////////////////////////////////////////////////////////////////////////////// 1367 1368 int Allow_File_Write (const char *Filename, const unsigned int FileType) 1369 { 1370 if (strcmp(Filename, "stdout") == 0 || strcmp(Filename, "stderr") == 0) 1371 return true; 1372 return (vfeSession::GetSessionFromThreadID()->TestAccessAllowed(Filename, true)); 1373 } 1374 1375 int Allow_File_Write (const unsigned short *Filename, const unsigned int FileType) 1376 { 1377 if (strcmp(UCS2toASCIIString(Filename).c_str(), "stdout") == 0 || strcmp(UCS2toASCIIString(Filename).c_str(), "stderr") == 0) 1378 return true; 1379 return (vfeSession::GetSessionFromThreadID()->TestAccessAllowed(Filename, true)); 1380 } 1381 1382 int Allow_File_Read (const char *Filename, const unsigned int FileType) 1383 { 1384 return (vfeSession::GetSessionFromThreadID()->TestAccessAllowed(Filename, false)); 1385 } 1386 1387 int Allow_File_Read (const unsigned short *Filename, const unsigned int FileType) 1388 { 1389 return (vfeSession::GetSessionFromThreadID()->TestAccessAllowed(Filename, false)); 1390 } 1391 1392 FILE *vfeFOpen (const std::basic_string<unsigned short>& name, const char *mode) 1393 { 1394 return (fopen (UCS2toASCIIString (name).c_str(), mode)) ; 1395 } 1396 1397 bool vfeRemove(const UCS2String& Filename) 1398 { 1399 return (DELETE_FILE (UCS2toASCIIString (Filename).c_str()) == 0); 1400 } 1401 1402 } 1403