/******************************************************************************* * pvfrontend.cpp * * This module contains the default C++ interface for render frontend. * * Author: Christopher J. Cason and Thorsten Froelich. * * --------------------------------------------------------------------------- * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd. * * POV-Ray is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * POV-Ray is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * --------------------------------------------------------------------------- * POV-Ray is based on the popular DKB raytracer version 2.12. * DKBTrace was originally written by David K. Buck. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. * --------------------------------------------------------------------------- * $File: //depot/public/povray/3.x/windows/pvfrontend.cpp $ * $Revision: #1 $ * $Change: 6069 $ * $DateTime: 2013/11/06 11:59:40 $ * $Author: chrisc $ *******************************************************************************/ #define POVWIN_FILE #define _WIN32_IE COMMONCTRL_VERSION #include #include "pvfrontend.h" #include "pvengine.h" #include "resource.h" #include "pvdisplay.h" // this must be the last file included #include "syspovdebug.h" namespace povwin { bool ListenMode ; extern int io_restrictions ; extern char *WriteDirSpecs [] ; extern char *ReadDirSpecs [] ; extern bool first_frame ; extern bool rendering_animation ; extern bool preserve_bitmap ; extern bool ErrorOccurred; extern bool ErrorNotified; extern bool no_shell_outs; extern bool system_noactive; extern string ErrorMessage ; extern string ErrorFilename ; extern unsigned ErrorLine ; extern unsigned ErrorCol ; } namespace pov_frontend { using namespace povwin; using namespace vfe; using namespace vfePlatform; static vfeWinSession *gSession; ////////////////////////////////////////////////////////////////////////////// // WinDisplayCreator // // This function is set as the session DisplayCreator by CreateFrontend below. // Whenever the core POV code wants to create an output window, the below code // will therefore be executed. ////////////////////////////////////////////////////////////////////////////// vfeDisplay *WinDisplayCreator (unsigned int width, unsigned int height, GammaCurvePtr gamma, vfeSession *session, bool visible) { // we attempt to minimize 'flashing' of the window (destroy followed by a re-create) // by checking to see if the previous window (if any) had the same dimensions. if it // did then we effectively re-use it by taking over its resources. the actual instance // is however automatically destroyed once the global display shared pointer is reset. WinDisplay *display = GetRenderWindow () ; if (display != NULL && display->GetWidth() == width && display->GetHeight() == height) { WinDisplay *p ; p = new WinLegacyDisplay (width, height, gamma, session, false) ; if (p->TakeOver (display)) { bool anim = gSession->RenderingAnimation(); // if we're not running an animation, or if we are and it's the first // frame, OR the user doesn't want frame preservation, clear the window. if (!anim || !preserve_bitmap || first_frame) p->Clear () ; return p ; } delete p; } return new WinLegacyDisplay (width, height, gamma, session, visible) ; } ////////////////////////////////////////////////////////////////////////////// // CreateFrontend // // Calling the below function is one of the very first things that the main // PVENGINE code does once it starts up. Since the legacy POVWIN code only // supports one rendering session at once, we store the session pointer in // a global variable (gSession). The session itself is an instance of the // vfeWinSession class declared in the windows platform-specific portion of // VFE, and is a descendant of vfeSession. Note that gSession is static and // not directly available outside this file; however a reference to the // current session may be obtained by the POVWIN code via GetSession() below. ////////////////////////////////////////////////////////////////////////////// void CreateFrontend (void) { if (gSession != NULL) throw POV_EXCEPTION_STRING ("Session already open"); try { gSession = new vfeWinSession(); } catch(vfeException& e) { throw POV_EXCEPTION_STRING (e.what()); } if (gSession == NULL) throw POV_EXCEPTION_STRING ("Failed to create session"); gSession->OptimizeForConsoleOutput(false); if (gSession->Initialize(NULL, NULL) != vfeNoError) { gSession->Shutdown(); string str = gSession->GetErrorString(); delete gSession; gSession = NULL; throw POV_EXCEPTION_STRING (str.c_str()); } gSession->SetDisplayCreator(WinDisplayCreator); } ////////////////////////////////////////////////////////////////////////////// // SetupFrontend // // This function loads the IO restriction paths into the session. It is called // initially upon startup by the main POVWIN code, and subsequently any time // the user changes the IO restriction settings via the menu options. ////////////////////////////////////////////////////////////////////////////// void SetupFrontend (void) { // 0: no restrictions // 1: restrict write // 2: restrict read/write gSession->ClearPaths(); if (io_restrictions != 0) { for (char **dirspec = WriteDirSpecs ; *dirspec != NULL ; dirspec++) gSession->AddWritePath (string (*dirspec), true); if (io_restrictions > 1) { gSession->AddReadPath(string(DocumentsPath), true); gSession->AddReadPath(string(FontPath) + "\\", false); for (char **dirspec = ReadDirSpecs ; *dirspec != NULL ; dirspec++) gSession->AddReadPath (string (*dirspec), true); } // allow write to the insert menu directory string str(DocumentsPath); str += "Insert Menu\\"; gSession->AddWritePath (str, true); // now add excluded write paths (e.g. the path containing the restrictions INI file) str = DocumentsPath; str += "ini\\"; gSession->AddExcludedPath(str, true); } } ////////////////////////////////////////////////////////////////////////////// // DeleteFrontend // // Destroys the global session after calling its Shutdown method. // This is more or less the last thing done by PVENGINE before exiting. ////////////////////////////////////////////////////////////////////////////// void DeleteFrontend (void) { if (gSession != NULL) { gSession->Shutdown() ; delete gSession; gSession = NULL; } } ////////////////////////////////////////////////////////////////////////////// // GetSession // // Returns a reference to the current vfeWinSession instance. Throws an // exception if one does not exist. (Since sessions in the current POVWIN // code last until exit, it is safe to return a reference). ////////////////////////////////////////////////////////////////////////////// vfeWinSession &GetSession (void) { if (gSession == NULL) throw POV_EXCEPTION_STRING ("No session open"); return *gSession; } ////////////////////////////////////////////////////////////////////////////// // HaveSession // // Used by the POVWIN code to check that a session exists. ////////////////////////////////////////////////////////////////////////////// bool HaveSession (void) { return gSession != NULL; } #if 0 void DrawFrame() { if (gDrawNow) { if (gDisplay) { WinLegacyDisplay *p = dynamic_cast(gDisplay.get()); p->DrawPixelBlock(0, 0, gDisplay->GetWidth() - 1, gDisplay->GetHeight() - 1, (pov_frontend::Display::RGBA8 *) gFrontBufferPtr); RECT rect; GetClientRect (p->GetHandle(), &rect); HDC dc=GetDC(p->GetHandle()); BITMAPINFO bmi={p->GetBMIH()}; StretchDIBits(dc,0,0,rect.right,rect.bottom,0,0,p->GetWidth(),p->GetHeight(),p->GetBitmapSurface(),&bmi,DIB_RGB_COLORS,SRCCOPY); ReleaseDC(p->GetHandle(), dc); } gDrawNow = false; } } #endif ////////////////////////////////////////////////////////////////////////////// // ProcessSession // // This function is called regularly by the main POVWIN code, primarily from // its message loop, but also in one or two other places where it might have // to wait a while before returning to loop processing. The optional delay // parameter (defaults to 0 if not specified) is as described for the // vfeSession::GetStatus() method. // // The purpose of ProcessSession is to query vfe for any outstanding events // (it does this by checking the status flags), and if any are available, // processing them. Typically this involves picking up messages and routing // them to the message output window or status bar, but it also handles change // of state (e.g. rendering to not rendering, and so forth, in which case it // will call back to the main POVWIN code to advise it of such). ////////////////////////////////////////////////////////////////////////////// bool ProcessSession (int delay) { if (gSession == NULL) throw POV_EXCEPTION_STRING ("No session open"); if (gSession->BackendFailed()) return (false); vfeStatusFlags flags = gSession->GetStatus (true, delay); if (flags == 0) return (false) ; if ((flags & stFailed) != 0) ErrorOccurred = true; if ((flags & stRenderingAnimation) != 0) rendering_animation = true; if ((flags & stAnimationFrameCompleted) != 0) first_frame = false; if ((flags & (stStatusMessage | stAnimationStatus)) != 0) { vfeSession::StatusMessage msg(*gSession) ; while (gSession->GetNextStatusMessage (msg)) { if (msg.m_Type == vfeSession::mGenericStatus) { strncpy (status_buffer, msg.m_Message.c_str(), sizeof (status_buffer) - 1); if (delay_next_status == 0) delay_next_status = msg.m_Delay; } else if (msg.m_Type == vfeSession::mAnimationStatus) { buffer_stream_message (mDivider, "-"); SetStatusPanelItemText (IDC_STATUS_DATA_FRAME, "%d/%d", msg.m_Frame, msg.m_TotalFrames); sprintf (status_buffer, "Rendering frame %d of %d", msg.m_Frame, msg.m_TotalFrames); } else { // huh? assert (false); } } } if ((flags & (stStreamMessage | stErrorMessage | stWarningMessage)) != 0) { int line; int col; char str[32]; string errormsg; string message; string filename; vfeSession::MessageType type; while (gSession->GetNextNonStatusMessage (type, message, filename, line, col)) { switch (type) { case vfeSession::mDebug: buffer_stream_message (mDebug, message.c_str()); break; case vfeSession::mInformation: buffer_stream_message (mAll, message.c_str()); break; case vfeSession::mWarning: case vfeSession::mPossibleError: buffer_stream_message (mWarning, message.c_str()); break; case vfeSession::mError: buffer_stream_message (mDivider, "-"); if (ErrorMessage.empty()) { ErrorMessage = message; ErrorLine = line; ErrorCol = col; ErrorFilename = filename; } if (filename.empty() == false) { errormsg = "\""; errormsg += filename + "\""; if (line > 0) { sprintf(str, "%u", line); errormsg += " line "; errormsg += str; } errormsg += ": " + message; buffer_stream_message (mFatal, errormsg.c_str()); } else buffer_stream_message (mFatal, message.c_str()); break; case vfeSession::mDivider: buffer_stream_message (mDivider, "-"); break; default: buffer_stream_message (mUnknown, message.c_str()); break; } } } if ((flags & stBackendStateChanged) != 0) { State state = gSession->GetBackendState(); SetCaption (NULL) ; SetStatusPanelItemText (IDC_STATUS_DATA_STATE, gSession->GetBackendStateName ()) ; if (state == kReady) update_menu_for_render (false) ; else if (state == kStopping) PVEnableMenuItem (CM_STOPRENDER, MF_GRAYED) ; else if (state == kPausedRendering || state == kPausedParsing) // TODO: handle pause request when shellout is active ShowIsPaused(); PVEnableMenuItem (CM_RENDERSLEEP, gSession->IsPausable () ? MF_ENABLED : MF_GRAYED) ; } if ((flags & stRenderShutdown) != 0) render_stopped () ; if ((flags & stShutdown) != 0) return (true); return (false); } //////////////////////////////// // Called from the shellout code //////////////////////////////// bool MinimizeShellouts(void) { return system_noactive; } bool ShelloutsPermitted(void) { return !no_shell_outs; } }