/******************************************************************************* * pvengine.cpp * * This file implements Windows specific routines, WinMain, and message loops. * * Primary author: Christopher J. Cason. * * --------------------------------------------------------------------------- * 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/pvengine.cpp $ * $Revision: #1 $ * $Change: 6069 $ * $DateTime: 2013/11/06 11:59:40 $ * $Author: chrisc $ *******************************************************************************/ /*****************************************************************************/ /* NOTICE */ /* */ /* Much of this source code (all of pvengine.exe) should be considered on */ /* its last legs. The base code was originally written back in early 1995 */ /* (with some of the code even predating that), and targeted at Win32s under */ /* Windows 3.1. An additional constraint was a desire for the code to be */ /* able to be compiled on a DEC Alpha under NT for the Alpha using only a */ /* 'C' compiler, and for it to be able to run with or without the editor. */ /* */ /* With the introduction of VFE in version 3.7, creating a new UI for POVWIN */ /* should be a lot less painful as almost all of the bindings with the core */ /* POV-Ray renderer have been abstracted into the above class library. */ /* */ /*****************************************************************************/ #define POVWIN_FILE #define _WIN32_IE COMMONCTRL_VERSION #if !defined( __BORLANDC__ ) && !defined( __DMC__ ) && !defined( __MINGW32__ ) #pragma comment(lib, "htmlhelp") #pragma comment(lib, "winmm") #endif #define _CRT_RAND_S #define PSAPI_VERSION 1 #pragma comment(lib, "psapi") #include #include #include #include #include #include #include #include #include #include #include // #define DEVELOPMENT #include #include #include #include "pvengine.h" #include "resource.h" #include "pvdialog.h" #include "pvguiext.h" #include "pvedit.h" #include "backend/control/benchmark.h" #include "pvdisplay.h" #include "syspovprotofrontend.h" #include "povray.h" #ifdef RTR_SUPPORT #include "rtrsupport.h" #endif #if defined(USE_AVX_FMA4_FOR_NOISE) #include "backend/texture/avxfma4check.h" #endif // this must be the last file included #include "syspovdebug.h" typedef HRESULT (CALLBACK* DLLGETVERSIONPROC) (DLLVERSIONINFO *); typedef DWORD __stdcall shCopyType (HKEY, LPCTSTR, HKEY, DWORD) ; #ifndef SM_CMONITORS #define SM_XVIRTUALSCREEN 76 #define SM_YVIRTUALSCREEN 77 #define SM_CXVIRTUALSCREEN 78 #define SM_CYVIRTUALSCREEN 79 #define SM_CMONITORS 80 #endif #ifndef PROCESS_MODE_BACKGROUND_BEGIN #define PROCESS_MODE_BACKGROUND_BEGIN 0x00100000 #define PROCESS_MODE_BACKGROUND_END 0x00200000 #endif #define CONFIRM_STOP_THRESHOLD 900 typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam ); char *WriteDump(struct _EXCEPTION_POINTERS *pExceptionInfo, bool full, long timestamp); namespace pov_frontend { extern shared_ptr gDisplay; } namespace vfePlatform { extern bool GetCPUCount(unsigned int *TotAvailLogical, unsigned int *TotAvailCore, unsigned int *PhysicalNum); } using namespace pov; using namespace pov_frontend; void GenerateDumpMeta(bool brief); namespace povwin { typedef struct { int id ; HWND hwnd ; SIZE size ; } StatusPanelItem ; bool rendering ; bool stop_rendering ; bool rendersleep ; bool render_cooperate = false ; bool InFrontend = false ; bool ErrorNotified ; bool ErrorOccurred ; bool HideRenderWithMain ; bool UseAlpha; bool IsExpired; bool BackendFailedFlag = false; bool PreventSleep = true; char DumpMeta[65536]; string ErrorMessage ; string ErrorFilename ; unsigned ErrorLine ; unsigned ErrorCol ; unsigned render_priority = CM_RENDERPRIORITY_NORMAL ; unsigned Duty_Cycle = 9 ; unsigned renderwin_8bits ; extern int renderwin_xoffset ; extern int renderwin_yoffset ; extern int renderwin_left ; extern int renderwin_top ; extern char PovLegacyRenderWinClass [] ; extern unsigned renderwin_max_width ; extern unsigned renderwin_max_height ; extern unsigned renderwin_flags ; extern bool MakeRenderwinActive ; int render_bitmap_depth ; unsigned render_width ; unsigned render_height ; int alert_sound ; int run_count ; int render_anim_count ; int argc ; int io_restrictions ; int tb_combo_sel ; int povray_return_code ; int PerformanceScale = 1 ; int seconds_for_last_line = -1 ; int delay_next_status ; int screen_origin_x ; int screen_origin_y ; int virtual_screen_width ; int virtual_screen_height ; int LastRenderPercentage ; int renderwin_transparency ; int cb_expect_selchange ; char command_line [_MAX_PATH * 3] ; char old_command_line [_MAX_PATH * 3] ; char *argv [MAX_ARGV] ; char source_file_name [_MAX_PATH] ; char modulePath [_MAX_PATH] ; char engineHelpPath [_MAX_PATH] ; char lastRenderName [_MAX_PATH] ; char lastBitmapName [_MAX_PATH] ; char lastRenderPath [_MAX_PATH] ; char lastBitmapPath [_MAX_PATH] ; char lastQueuePath [_MAX_PATH] ; char lastSecondaryIniFilePath [_MAX_PATH] ; char DefaultRenderIniFileName [_MAX_PATH] ; char SecondaryRenderIniFileName [_MAX_PATH] ; char SecondaryRenderIniFileSection [64] ; char background_file [_MAX_PATH] ; char EngineIniFileName[_MAX_PATH] ; char BinariesPath [_MAX_PATH] ; char DocumentsPath [_MAX_PATH] ; char LastInferredHome [_MAX_PATH] ; char ToolIniFileName [_MAX_PATH] ; char tool_commands [MAX_TOOLCMD] [MAX_TOOLCMDTEXT] ; char tool_help [MAX_TOOLCMD] [MAX_TOOLHELPTEXT] ; char requested_render_file [_MAX_PATH] ; char RegionStr [128] ; char TempRegionStr [128] ; char demo_file_name [_MAX_PATH] ; char demo_ini_name [_MAX_PATH] ; char status_buffer [1024] ; char render_complete_sound [_MAX_PATH] ; char parse_error_sound [_MAX_PATH] ; char render_error_sound [_MAX_PATH] ; char FontPath [_MAX_PATH] ; char *EditDLLPath ; bool render_complete_sound_enabled ; bool parse_error_sound_enabled ; bool render_error_sound_enabled ; bool alert_on_completion ; bool save_settings ; bool IsW95UserInterface = true; bool IsW98 ; bool IsWNT ; bool IsW2k ; bool IsWXP ; bool IsVista ; bool running_demo ; bool running_benchmark ; bool benchmark_multithread ; bool fast_scroll ; bool no_shellout_wait ; bool tile_background = false ; bool debugging ; bool no_palette_warn ; bool render_lock_up ; bool RenderwinIsChild = true ; bool demo_mode ; bool benchmark_mode; bool ignore_auto_ini ; bool newVersion ; bool exit_after_render ; bool system_noactive ; bool one_instance = true ; bool run_renderer ; bool use_toolbar = true ; bool use_tooltips = true ; bool use_editors = true ; bool editors_enabled = true; bool resizing ; bool drop_to_editor ; bool restore_command_line ; bool render_requested ; bool render_auto_close ; bool noexec ; bool ExtensionsEnabled = true ; bool use_taskbar = true ; bool main_window_hidden ; bool about_showing ; bool NoRestore ; bool IsComCtl5 = false ; bool IsComCtl6 = false ; bool allow_rw_source ; bool no_shell_outs = true ; bool hide_newuser_help ; bool info_render_complete = false ; bool no_status_output = false ; bool temp_render_region = false ; bool rendering_insert_menu = false ; bool was_insert_render = false ; bool rendering_animation = false ; bool preserve_bitmap = false ; bool first_frame = false ; bool check_new_version ; bool check_news ; bool send_system_info ; bool homeInferred = false ; bool editSettingsCopied = false ; bool FreshInstall = false; bool output_to_file ; bool UpdateCheckDone = false ; bool AutoAppendPaths ; HWND toolbar_window ; HWND aux_toolbar_window ; HWND window_list [MAX_WINDOWS] ; HWND toolbar_combobox ; HWND rebar_window ; HWND StatusWindow ; HWND StatusTooltip ; HWND toolbar_cmdline ; HWND tab_window ; HICON ourIcon ; HICON renderIcon ; HFONT about_font ; HANDLE hMainThread ; string InputFileName ; time_t SecondCountStart ; time_t quit ; HBITMAP hBmpBackground ; HBITMAP hBmpRendering ; HBITMAP hBmpIcon ; HBITMAP hBmpAbout ; __int64 PerformanceFrequency ; __int64 PerformanceCounter1 ; __int64 PerformanceCounter2 ; __int64 KernelTimeStart ; __int64 KernelTimeEnd ; __int64 UserTimeStart ; __int64 UserTimeEnd ; __int64 KernelTimeTotal ; __int64 UserTimeTotal ; __int64 CPUTimeTotal ; clock_t ClockTimeStart ; clock_t ClockTimeEnd ; clock_t ClockTimeTotal ; clock_t SleepTimeStart ; clock_t SleepTimeEnd ; clock_t SleepTimeTotal ; unsigned class_registered = 0 ; unsigned currentX = 0 ; unsigned currentY = 0 ; unsigned screen_width ; unsigned screen_height ; unsigned screen_depth ; unsigned background_width ; unsigned background_height ; unsigned seconds = 0 ; unsigned toolheight = 0 ; unsigned statusheight = 0 ; unsigned on_completion = CM_COMPLETION_NOTHING ; unsigned window_count = 0 ; unsigned ThreadCount = 2 ; unsigned NumberOfCPUs ; unsigned NumLogicalCPUs ; unsigned NumCPUCores ; unsigned NumPhysicalCPUs ; HPALETTE hPalApp ; HPALETTE hPalBitmap ; COLORREF background_colour ; COLORREF text_colours [3] ; COLORREF custom_colours [16] ; COLORREF background_shade = RGB (1, 1, 1) ; HINSTANCE hInstance ; HH_AKLINK hh_aklink ; OSVERSIONINFO version_info ; StatusPanelItem StatusPanelItems [IDC_STATUS_ID_LAST + 1] ; CRITICAL_SECTION critical_section ; // key is the name of an included file (all lower case). // content is the name of the most recent rendered file that caused it to be included. map IncludeToSourceMap; map IncludeAlternateDecisionMap; char queued_files [MAX_QUEUE] [_MAX_PATH] ; char dir [_MAX_PATH] ; unsigned queued_file_count = 0 ; unsigned auto_render = true ; unsigned timer_id ; unsigned about_timer_id ; unsigned timer_ticks; unsigned panel_size ; char PovMainWinClass [] = CLASSNAMEPREFIX "MainWinClass" ; unsigned mainwin_xpos ; unsigned mainwin_ypos ; HWND main_window ; HWND message_window ; WINDOWPLACEMENT mainwin_placement ; char PovAboutWinClass [] = CLASSNAMEPREFIX "AboutWinClass" ; HWND about_window ; HWND about_buttons [3] ; WNDPROC about_button_wndproc ; unsigned about_width ; unsigned about_height ; HPALETTE about_palette ; HWND statuspanel ; char PovMessageWinClass [] = CLASSNAMEPREFIX "MessageWinClass" ; #define NUM_ABOUT_LINKS 7 RECT AboutLinks[NUM_ABOUT_LINKS] = { { 23, 14, 188, 87 }, { 104, 397, 184, 409 }, { 185, 397, 262, 409 }, { 263, 397, 370, 409 }, { 371, 397, 480, 409 }, { 481, 397, 560, 409 }, { 32, 411, 154, 423 } }; char *AboutURLs[NUM_ABOUT_LINKS] = { "http://www.povray.org/", "http://www.digicert.com/", "http://ntplx.net/", "http://opensourcelaw.biz/", "http://www.perforce.com/", "http://softwarefreedom.org/", "http://softwarefreedom.org/" }; bool handle_main_command (WPARAM wParam, LPARAM lParam) ; void SetStatusPanelItemText (int id, LPCSTR format, ...) ; void ShowAboutBox (void); extern int message_xchar ; extern int message_ychar ; extern int message_scroll_pos_x ; extern int message_scroll_pos_y ; extern int top_message_row ; extern int message_count ; extern int message_cols ; extern int message_rows ; extern int listbox_xchar ; extern int listbox_ychar ; extern int EditFileCount ; extern int message_output_x ; extern char message_font_name [256] ; extern char *EditFiles [] ; extern bool ListenMode ; extern bool keep_messages ; extern bool MenuBarDraw ; extern bool TrackMem; extern __int64 PeakMem; extern unsigned message_font_size ; extern unsigned message_font_weight ; extern HFONT message_font ; extern HFONT tab_font ; extern HMENU hMenuBar ; extern HMENU hMainMenu ; extern HMENU hPopupMenus ; extern HMENU hVidcapMenu ; extern HACCEL hAccelerators ; extern HINSTANCE hLibPovEdit ; #define MAX_INSERT_MENU_SECTIONS 8192 typedef std::vector InsMenuSecList; int InsertMenuSection; bool StartInsertRender; InsMenuSecList InsertMenuSections; typedef struct { WORD wVirtkey ; int iMessage ; WORD wRequest ; } SCROLLKEYS ; SCROLLKEYS key2scroll [] = { { VK_END, WM_VSCROLL, SB_BOTTOM }, { VK_PRIOR, WM_VSCROLL, SB_PAGEUP }, { VK_NEXT, WM_VSCROLL, SB_PAGEDOWN }, { VK_UP, WM_VSCROLL, SB_LINEUP }, { VK_DOWN, WM_VSCROLL, SB_LINEDOWN }, { VK_LEFT, WM_HSCROLL, SB_PAGEUP }, { VK_RIGHT, WM_HSCROLL, SB_PAGEDOWN }, { -1, -1, -1 } } ; string StripFilePath (const string& str) { string::size_type pos = str.find_last_of ("\\/") ; if (pos == string::npos) return (str) ; return string (str, pos + 1) ; } bool StripPathComponent (char *path, int number) { if (number > 1) if (!StripPathComponent (path, number - 1)) return (false) ; char *s = path + strlen (path) - 1 ; if (isPathSeparator(*s)) *s-- = '\0' ; while (s > path && !isPathSeparator(*s)) s-- ; *s = '\0' ; return (path [0] != '\0') ; } void debug_output (const char *format, ...) { char str [2048] ; va_list arg_ptr ; FILE *f ; if (format == NULL) { _unlink ("c:\\temp\\povdebug.txt") ; return ; } va_start (arg_ptr, format) ; vsprintf (str, format, arg_ptr) ; va_end (arg_ptr) ; OutputDebugString (str) ; if ((f = fopen ("c:\\temp\\povdebug.txt", "a+t")) != NULL) { fprintf (f, sizeof(time_t) == 4 ? "%u: %s" : "%I64u: %s", time (NULL), str) ; fclose (f) ; } } // this function is declared in syspovconfig.h ... use pov::WIN32_DEBUG_OUTPUT() from // anywhere in the POV-Ray source, core or otherwise void WIN32_DEBUG_OUTPUT (const char *format,...) { char str [2048] ; va_list arg_ptr ; sprintf (str, "%5d ", GetCurrentThreadId()); va_start (arg_ptr, format) ; vsprintf (str + 6, format, arg_ptr) ; va_end (arg_ptr) ; OutputDebugString (str) ; } // this function is declared in syspovconfig.h ... use pov::WIN32_DEBUG_FILE_OUTPUT() from // anywhere in the POV-Ray source, core or otherwise. it's also thread-safe. void WIN32_DEBUG_FILE_OUTPUT (const char *format,...) { va_list arg_ptr ; static FILE *f ; static boost::mutex mtx; if (format == NULL) { if (f != NULL) { fclose (f) ; f = NULL ; } return ; } if (f == NULL) { f = fopen ("c:\\temp\\povdebug.txt", "at") ; if (f == NULL) return ; } boost::mutex::scoped_lock l(mtx); fprintf (f, "%u [%d]: ", GetTickCount (), GetCurrentThreadId ()) ; va_start (arg_ptr, format) ; vfprintf (f, format, arg_ptr) ; va_end (arg_ptr) ; fflush (f); } void SetCaption (LPCSTR str) { char buffer [1024] ; static char lastStr [1024] ; vfeSession& Session (GetSession()); if (str != NULL) strcpy (lastStr, str) ; else str = lastStr ; if (Session.BackendFailed()) { SetWindowText (main_window, "Backend Failed") ; return; } #ifndef DEVELOPMENT if (Session.GetBackendState() == kRendering && InputFileName.size () > 0) { string filename = StripFilePath (InputFileName) ; if (strstr (str, filename.c_str ()) != NULL) { // if the filename is in the caption already, we're probably rendering // the current editor file (exception: if a file with the same name but // a different path is being viewed). sprintf (buffer, "%s [%s %d%%]", str, Session.GetBackendStateName(), Session.GetPercentComplete()) ; } else { // the render file name is not in the caption: in that case we are // probably viewing another file or the message window. sprintf (buffer, "%s [Rendering %s: %d%%]", str, filename.c_str (), Session.GetPercentComplete()) ; } } else sprintf (buffer, "%s [%s]", str, Session.GetBackendStateName ()) ; SetWindowText (main_window, buffer) ; #else if (Session.GetBackendState() == kRendering && InputFileName.size () > 0) { string filename = StripFilePath (InputFileName) ; if (strstr (str, filename.c_str ()) != NULL) { // if the filename is in the caption already, we're probably rendering // the current editor file (exception: if a file with the same name but // a different path is being viewed). sprintf (buffer, CAPTIONPREFIX " %s [%s %d%%]", str, Session.GetBackendStateName(), Session.GetPercentComplete()) ; } else { // the render file name is not in the caption: in that case we are // probably viewing another file or the message window. sprintf (buffer, CAPTIONPREFIX " %s [Rendering %s:%d%%]", str, filename.c_str (), Session.GetPercentComplete()) ; } } else sprintf (buffer, CAPTIONPREFIX " %s [%s]", str, Session.GetBackendStateName()) ; SetWindowText (main_window, buffer) ; #endif } // returned value is in microseconds __int64 GetCPUTime (bool Kernel = true, bool User = true) { __int64 kt ; __int64 ut ; __int64 total = 0 ; FILETIME ct ; FILETIME et ; if (IsWNT) { if (!GetProcessTimes (GetCurrentProcess (), &ct, &et, (FILETIME *) &kt, (FILETIME *) &ut)) { assert (false) ; return (0) ; } if (Kernel) total += kt ; if (User) total += ut ; return (total / 10) ; } else { // have to simulate the results for now // TODO: handle pause time ut = clock () ; if (User) total += ut * 1000 ; return (total) ; } } char *PPS_String (unsigned pixels, unsigned renderseconds) { static char str [128] ; if (rendersleep) return ("PAUSED") ; if (renderseconds == 0) return ("??? PPS") ; if (pixels / renderseconds < 5) { if (pixels * 60 / renderseconds < 5) sprintf (str, "%u PPH", pixels * 3600 / renderseconds) ; else sprintf (str, "%u PPM", pixels * 60 / renderseconds) ; } else sprintf (str, "%u PPS", pixels / renderseconds) ; return (str) ; } void PrintRenderTimes (int Finished, int NormalCompletion) { int PixelsRendered = GetSession().GetPixelsRendered(); unsigned STT = SleepTimeTotal ; if (rendersleep) { SleepTimeEnd = clock () ; if (Finished) { SleepTimeTotal += SleepTimeEnd - SleepTimeStart ; STT = SleepTimeTotal ; rendersleep = false ; } else STT += SleepTimeEnd - SleepTimeStart ; } KernelTimeEnd = GetCPUTime (true, false) ; UserTimeEnd = GetCPUTime (false, true) ; KernelTimeTotal = KernelTimeEnd - KernelTimeStart ; UserTimeTotal = UserTimeEnd - UserTimeStart ; CPUTimeTotal = UserTimeTotal + KernelTimeTotal ; ClockTimeEnd = clock () ; ClockTimeTotal = ClockTimeEnd - ClockTimeStart - STT ; if (ClockTimeTotal >= CLOCKS_PER_SEC) status_printf (StatusPPS, PPS_String (PixelsRendered, ClockTimeTotal / CLOCKS_PER_SEC)) ; say_status_message (StatusRendertime, get_elapsed_time (ClockTimeTotal / CLOCKS_PER_SEC)) ; if (IsWNT != 0 && Finished != 0) { message_printf ("CPU time used: kernel %.02f seconds, user %.02f seconds, total %.02f seconds.\n", KernelTimeTotal / 1000000.0, UserTimeTotal / 1000000.0, CPUTimeTotal / 1000000.0) ; message_printf ("Elapsed time %.02f seconds", (double) ClockTimeTotal / CLOCKS_PER_SEC) ; if (NumberOfCPUs > 1 && ThreadCount > 1) { POV_ULONG cputotal = CPUTimeTotal * CLOCKS_PER_SEC / 1000000 ; if (cputotal > ClockTimeTotal * 10 / 9) message_printf (", CPU vs elapsed time ratio %.02f", (double) cputotal / ClockTimeTotal) ; } message_printf (".\n") ; if (PixelsRendered > 0 && CPUTimeTotal > 0 && NormalCompletion) { message_printf ("Render averaged %.02f PPS (%.02f PPS CPU time) over %u pixels.\n", (double) PixelsRendered * CLOCKS_PER_SEC / ClockTimeTotal, (double) PixelsRendered * 1000000 / CPUTimeTotal, PixelsRendered) ; message_printf ("----------------------------------------------------------------------------\n") ; #ifndef _DEBUG char str [2048] ; if (running_benchmark) { char *s = str; s += sprintf(str, "CPU time used: kernel %.02f seconds, user %.02f seconds, total %.02f seconds.\n", KernelTimeTotal / 1000000.0, UserTimeTotal / 1000000.0, CPUTimeTotal / 1000000.0) ; s += sprintf(s, "Elapsed time %.02f seconds", (double) ClockTimeTotal / CLOCKS_PER_SEC) ; if (NumberOfCPUs > 1 && ThreadCount > 1) { POV_ULONG cputotal = CPUTimeTotal * CLOCKS_PER_SEC / 1000000 ; if (cputotal > ClockTimeTotal * 10 / 9) s += sprintf(s, ", CPU vs elapsed time ratio %.02f", (double) cputotal / ClockTimeTotal) ; } s += sprintf(s, ".\n") ; s += sprintf (s, "Render averaged %.02f PPS (%.02f PPS CPU time) over %u pixels using %u thread(s).\n", (double) PixelsRendered * CLOCKS_PER_SEC / ClockTimeTotal, (double) PixelsRendered * 1000000 / CPUTimeTotal, PixelsRendered, ThreadCount) ; copy_text_to_clipboard(str); if (benchmark_mode) { // special case: we are running the benchmark because of a command-line request. char fn[_MAX_PATH]; char ts[256]; time_t t = time(NULL); strftime(ts, sizeof(ts), "%Y%m%d.%H%M%S", gmtime(&t)); sprintf(fn, "%sbenchmark-%s.txt", DocumentsPath, ts); FILE *f = fopen(fn, "wt"); if (f != NULL) { int n = Get_Benchmark_Version(); fprintf(f, "%s", str); strftime(str, sizeof(str), "%#c", gmtime(&t)); fprintf(f, "\nRender of benchmark version %x.%02x completed at %s UTC.\n", n / 256, n % 256, str); fprintf(f, "----------------------------------------------------------------------------\n"); GenerateDumpMeta(true); fwrite(DumpMeta, strlen(DumpMeta), 1, f); fprintf(f, "povversion=%s\n", POV_RAY_VERSION) ; fprintf(f, "compilerversion=%s\n", COMPILER_VER) ; fprintf(f, "platformversion=%s\n", PVENGINE_VER) ; fclose(f); } } else { strcat(str, "\nThese results have been placed in the clipboard.\n"); MessageBox (main_window, str, "Benchmark Complete.", MB_OK) ; } } #endif } else message_printf ("----------------------------------------------------------------------------\n") ; } } bool OkToStopRendering (void) { if (GetSession().BackendFailed()) return (true); if (time (NULL) - SecondCountStart < CONFIRM_STOP_THRESHOLD) return (true) ; if (GetSession().GetRealTimeRaytracing() == true) return (true); if (MessageBox (main_window, "You've been running this render for quite a while - really cancel ?", "Stop rendering ?", MB_ICONQUESTION | MB_YESNO) == IDYES) return (true) ; return (false) ; } void menuhelp (UINT idCommand) { switch (idCommand) { case CM_FILEMENUHELP : hh_aklink.pszKeywords = "File Menu" ; break ; case CM_EDITMENUHELP : hh_aklink.pszKeywords = "Edit Menu" ; break ; case CM_SEARCHMENUHELP : hh_aklink.pszKeywords = "Search Menu" ; break ; case CM_TEXTMENUHELP : hh_aklink.pszKeywords = "Text Menu" ; break ; case CM_EDITORMENUHELP : hh_aklink.pszKeywords = "Editor Menu" ; break ; case CM_RENDERMENUHELP : hh_aklink.pszKeywords = "Render Menu" ; break ; case CM_OPTIONSMENUHELP : hh_aklink.pszKeywords = "Options Menu" ; break ; case CM_TOOLSMENUHELP : hh_aklink.pszKeywords = "Tools Menu" ; break ; case CM_WINDOWMENUHELP : hh_aklink.pszKeywords = "Window Menu" ; break ; case CM_RENDERWINMENUHELP : hh_aklink.pszKeywords = "Render Window Menu" ; break ; case CM_MESSAGEWINMENUHELP : hh_aklink.pszKeywords = "Message Window Menu" ; break ; default : hh_aklink.pszKeywords = NULL ; break ; } if (hh_aklink.pszKeywords != NULL) HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ; } // example taken from MSDN documentation DWORD GetDllVersion (LPCTSTR lpszDllName) { HINSTANCE hinstDll; DWORD dwVersion = 0; hinstDll = LoadLibrary(lpszDllName) ; if (hinstDll) { DLLGETVERSIONPROC pDllGetVersion; pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress (hinstDll, "DllGetVersion"); if (pDllGetVersion) { DLLVERSIONINFO dvi; HRESULT hr; ZeroMemory(&dvi, sizeof (dvi)); dvi.cbSize = sizeof (dvi); hr = (*pDllGetVersion) (&dvi); if (SUCCEEDED (hr)) dwVersion = MAKELONG (dvi.dwMajorVersion, dvi.dwMinorVersion); } FreeLibrary (hinstDll); } return dwVersion; } void getvars (ExternalVarStruct *v) { strcpy (v->command_line, command_line) ; strcpy (v->source_file_name, source_file_name) ; strcpy (v->lastRenderName, lastRenderName) ; strcpy (v->lastRenderPath, lastRenderPath) ; strcpy (v->lastQueuePath, lastQueuePath) ; strcpy (v->lastSecondaryIniFilePath, lastSecondaryIniFilePath) ; strcpy (v->DefaultRenderIniFileName, DefaultRenderIniFileName) ; strcpy (v->SecondaryRenderIniFileName, SecondaryRenderIniFileName) ; strcpy (v->SecondaryRenderIniFileSection, SecondaryRenderIniFileSection) ; strcpy (v->ourPath, modulePath) ; strcpy (v->engineHelpPath, engineHelpPath) ; strcpy (v->rendererHelpPath, "") ; strcpy (v->BinariesPath, BinariesPath) ; strcpy (v->EngineIniFileName, EngineIniFileName) ; strcpy (v->ToolIniFileName, ToolIniFileName) ; memcpy (v->queued_files, queued_files, sizeof (v->queued_files)) ; v->loadRerun = false ; v->continueRerun = false ; v->povray_return_code = povray_return_code ; v->rendering = rendering ; v->IsWin32 = true ; v->IsW95UserInterface = IsW95UserInterface ; v->running_demo = running_demo ; v->debugging = debugging ; v->isMaxiMinimized = false ; v->newVersion = newVersion ; v->use_threads = true ; v->use_toolbar = use_toolbar ; v->use_tooltips = use_tooltips ; v->use_editors = use_editors ; v->drop_to_editor = drop_to_editor ; v->rendersleep = rendersleep ; v->ExtensionsEnabled = ExtensionsEnabled ; v->queued_file_count = queued_file_count > OLD_MAX_QUEUE ? OLD_MAX_QUEUE : queued_file_count ; v->auto_render = auto_render ; } void setvars (ExternalVarStruct *v) { strncpy (command_line, v->command_line, sizeof (command_line) - 1) ; SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ; strncpy (source_file_name, v->source_file_name, sizeof (source_file_name) - 1) ; strncpy (lastRenderName, v->lastRenderName, sizeof (lastRenderName) - 1) ; strncpy (lastRenderPath, v->lastRenderPath, sizeof (lastRenderPath) - 1) ; strncpy (lastQueuePath, v->lastQueuePath, sizeof (lastQueuePath) - 1) ; strncpy (lastSecondaryIniFilePath, v->lastSecondaryIniFilePath, sizeof (lastSecondaryIniFilePath) - 1) ; strncpy (DefaultRenderIniFileName, v->DefaultRenderIniFileName, sizeof (DefaultRenderIniFileName) - 1) ; strncpy (SecondaryRenderIniFileName, v->SecondaryRenderIniFileName, sizeof (SecondaryRenderIniFileName) - 1) ; strncpy (SecondaryRenderIniFileSection, v->SecondaryRenderIniFileSection, sizeof (SecondaryRenderIniFileSection) - 1) ; } bool HaveWin95OrLater (void) { return (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) ; } bool HaveWin98OrLater (void) { if (version_info.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) return (false) ; if (version_info.dwMajorVersion < 4) return (false) ; if (version_info.dwMajorVersion > 4) return (true) ; return (version_info.dwMinorVersion > 0) ; } bool HaveNT4OrLater (void) { return (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion >= 4) ; } bool HaveWin2kOrLater (void) { return (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion >= 5) ; } bool HaveWinXPOrLater (void) { if (version_info.dwPlatformId != VER_PLATFORM_WIN32_NT || version_info.dwMajorVersion < 5) return (false) ; return (version_info.dwMajorVersion > 5 || (version_info.dwMajorVersion == 5 && version_info.dwMinorVersion > 0)) ; } bool HaveVistaOrLater (void) { return version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion > 5; } void set_render_priority (unsigned priority) { switch (priority) { case CM_RENDERPRIORITY_BACKGROUND : SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN) ; break ; case CM_RENDERPRIORITY_LOW : if (IsVista) SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END); SetPriorityClass (GetCurrentProcess(), IDLE_PRIORITY_CLASS) ; break ; case CM_RENDERPRIORITY_NORMAL : if (IsVista) SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END); SetPriorityClass (GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS) ; break ; case CM_RENDERPRIORITY_HIGH : if (IsVista) SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END); SetPriorityClass (GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS) ; break ; } } // we can't allow LoadBitmap to load our background bitmaps 'cause if we're running // a 256-colour mode, it will map the incoming resource to 16 colours ... // LoadImage () doesn't exist under Win32s, either. sigh. HBITMAP NonBogusLoadBitmap (HINSTANCE hInst, LPSTR lpszBitmap) { void *p ; HRSRC hres ; HGLOBAL hg ; HBITMAP hBitmap ; if ((hres = FindResource (hInst, lpszBitmap, RT_BITMAP)) == NULL) return (NULL) ; if ((hg = LoadResource (hInst, hres)) == NULL) return (NULL) ; if ((p = LockResource (hg)) == NULL) { FreeResource (hg) ; return (NULL) ; } hBitmap = lpDIBToBitmap (p, hPalApp) ; FreeResource (hg) ; return (hBitmap) ; } HBITMAP NonBogusLoadBitmapAndPalette (HINSTANCE hInst, LPSTR lpszBitmap) { void *p ; HRSRC hres ; HGLOBAL hg ; HBITMAP hBitmap ; if ((hres = FindResource (hInst, lpszBitmap, RT_BITMAP)) == NULL) return (NULL) ; if ((hg = LoadResource (hInst, hres)) == NULL) return (NULL) ; if ((p = LockResource (hg)) == NULL) { FreeResource (hg) ; return (NULL) ; } hBitmap = lpDIBToBitmapAndPalette (p) ; FreeResource (hg) ; return (hBitmap) ; } // finds fist separator character in a path char *findFirstPathSeparator (char *s) { size_t pos = strcspn(s, "\\/"); return pos >= strlen(s) ? NULL : s + pos; } // finds last separator character in a path char *findLastPathSeparator (char *s) { char *s1 = strrchr (s, '\\'); char *s2 = strrchr (s1 ? s1 : s, '/'); return s2 ? s2 : s1; } // append separator character to a path, if not present already // does not append to empty strings. // does append to solitary drive letters; this isn't quite legit but as we don't // support the use of drive references without a path (i.e. references that rely // on the uniquely-DOS/Windows concept of a CWD for *each* mounted device), it // doesn't really matter. void appendPathSeparator (char *str) { if (str[0] != '\0') // only append to non-empty strings if (!hasTrailingPathSeparator(str)) strcat(str, "\\"); } // tests if path has trailing separator character // does not return true if path is a solitary drive letter (e.g. "C:"). // the same consideration applies regarding relative drive references as // mentioned in appendPathSeparator. bool hasTrailingPathSeparator (const char *str) { return isPathSeparator(str[strlen (str) - 1]); } // strips trailing separator character from path // will strip a trailing separator right after drive letter (e.g. "C:\"). // calling functions must be careful not to let this trip them up if they // are passed any user-specified input. void trimTrailingPathSeparator (char *str) { char *s = str + strlen (str) - 1 ; if (isPathSeparator(*s)) *s = '\0' ; } // strips leading and trailing double-quotes from a string. // does not check that both are present, just removes them // if they are there. returns new start of string. char *trimDoubleQuotes (char *str) { if (str[0] == '"') str++; char *s = str + strlen (str) - 1 ; if (*s == '"') *s = '\0' ; return str; } // strips trailing separator character from path void validatePath (char *s) { if (s [1] == ':' && strlen (s) < 4) return ; // make sure we don't trim a trailing separator right after a drive letter (e.g. "C:\") trimTrailingPathSeparator (s); } int joinPath (char *out, const char *path, const char *name) { strcpy (out, path) ; appendPathSeparator (out); strcat (out, name) ; return ((int) strlen (out)) ; } bool reg_printf (bool useHKCU, char *keyName, char *valName, char *format, ...) { char str [2048] ; HKEY hKey ; va_list arg_ptr ; if (strlen (format) > sizeof (str) - 256) return (false) ; if (RegCreateKeyEx (useHKCU ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) { va_start (arg_ptr, format) ; vsprintf (str, format, arg_ptr) ; va_end (arg_ptr) ; RegSetValueEx (hKey, valName, 0, REG_SZ, (BYTE *) str, (int) strlen (str) + 1) ; RegCloseKey (hKey) ; return (true) ; } return (false) ; } // conditional version of reg_printf bool cond_reg_printf (char *keyName, char *valName, char *format, ...) { char str [2048] ; DWORD len = sizeof (str) ; HKEY hKey ; va_list arg_ptr ; if (strlen (format) > sizeof (str) - 256) return (false) ; if (RegOpenKeyEx (HKEY_CURRENT_USER, keyName, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { if (RegQueryValueEx (hKey, valName, 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS) { RegCloseKey (hKey) ; // it already exists - if it doesn't have zero length we don't update it if (str [0]) return (true) ; } else RegCloseKey (hKey) ; } if (RegCreateKeyEx (HKEY_CURRENT_USER, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) { va_start (arg_ptr, format) ; vsprintf (str, format, arg_ptr) ; va_end (arg_ptr) ; RegSetValueEx (hKey, valName, 0, REG_SZ, (BYTE *) str, (int) strlen (str) + 1) ; RegCloseKey (hKey) ; return (true) ; } return (false) ; } static bool reg_dword (char *keyName, char *valName, DWORD value) { HKEY hKey ; if (RegCreateKeyEx (HKEY_CURRENT_USER, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) { RegSetValueEx (hKey, valName, 0, REG_DWORD, (BYTE *) &value, 4) ; RegCloseKey (hKey) ; return (true) ; } return (false) ; } char *GetInstallTime (void) { HKEY key ; DWORD len ; static char str [64] ; len = sizeof (str) ; if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY, 0, KEY_READ, &key) == ERROR_SUCCESS) { if (RegQueryValueEx (key, INSTALLTIMEKEY, 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS) { RegCloseKey (key) ; return (str) ; } RegCloseKey (key) ; } return (NULL) ; } bool checkRegKey (void) { char str [_MAX_PATH] ; HKEY key ; DWORD val; DWORD len = sizeof (str) ; FILETIME file_time ; SYSTEMTIME system_time ; if (GetInstallTime () == NULL) { GetSystemTime (&system_time) ; if (SystemTimeToFileTime (&system_time, &file_time)) reg_printf (true, "Software\\" REGKEY, INSTALLTIMEKEY, "%I64u", ((__int64) file_time.dwHighDateTime << 32) | file_time.dwLowDateTime) ; } if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS) { if (RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) str, &len) != 0) str[0] = '\0'; if (str [0] == '\0') { RegCloseKey (key) ; return (false) ; } len = sizeof(val); if (RegQueryValueEx (key, "FreshInstall", 0, NULL, (BYTE *) &val, &len) == 0) { FreshInstall = val != 0; RegCloseKey (key) ; if (FreshInstall && RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ | KEY_SET_VALUE, &key) == ERROR_SUCCESS) { RegDeleteValue(key, "FreshInstall"); RegCloseKey (key) ; } } else RegCloseKey (key) ; } else return (false) ; if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\CurrentVersion\\Windows", 0, KEY_READ | KEY_WRITE, &key) == ERROR_SUCCESS) { len = sizeof (str) ; if (RegQueryValueEx (key, VERSIONVAL, 0, NULL, (BYTE *) str, &len) != 0 || strcmp (str, POV_RAY_VERSION) != 0) RegSetValueEx (key, VERSIONVAL, 0, REG_SZ, (BYTE *) POV_RAY_VERSION, (int) strlen (POV_RAY_VERSION) + 1) ; RegCloseKey (key) ; } return true; } bool getHome (void) { HKEY key ; DWORD len ; if (debugging) debug_output ("querying registry\n") ; DocumentsPath [0] = BinariesPath [0] = '\0' ; if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS) { len = sizeof (LastInferredHome) ; RegQueryValueEx (key, "LastInferredHome", 0, NULL, (BYTE *) LastInferredHome, &len) ; len = sizeof (BinariesPath) ; RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) BinariesPath, &len) ; if (debugging && BinariesPath[0] != '\0') debug_output("Win32 getHome() succeeded (HKCU::Home), BinariesPath is '%s'\n", BinariesPath) ; len = sizeof (DocumentsPath) ; RegQueryValueEx (key, "DocPath", 0, NULL, (BYTE *) DocumentsPath, &len) ; if (debugging && DocumentsPath[0] != '\0') debug_output("Win32 getHome() succeeded (HKCU::DocPath), DocumentsPath is '%s'\n", DocumentsPath) ; RegCloseKey (key) ; return (BinariesPath[0] != '\0') ; } if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS) { len = sizeof (BinariesPath) ; RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) BinariesPath, &len) ; RegCloseKey (key) ; if (debugging && BinariesPath[0] != '\0') debug_output("Win32 getHome() succeeded (HKLM::Home), BinariesPath is '%s'\n", BinariesPath) ; return (BinariesPath[0] != '\0') ; } return (false) ; } bool inferHome (void) { char exePath [_MAX_PATH] ; char *s ; if (GetModuleFileName (NULL, exePath, _MAX_PATH) == 0) return (false) ; // find path component if ((s = findLastPathSeparator (exePath)) == NULL) return (false) ; *s = '\0' ; // now step up one directory if ((s = findLastPathSeparator (exePath)) == NULL) return (false) ; *++s = '\0' ; // now look for some standard directories strcpy (s, "help") ; if (!dirExists (exePath)) { strcpy (s, "sounds") ; if (!dirExists (exePath)) { strcpy (s, "tiles") ; if (!dirExists (exePath)) return (false) ; } } *s = '\0' ; strcpy (BinariesPath, exePath) ; homeInferred = true ; return (true) ; } string get36Home(void) { char str[_MAX_PATH]; HKEY key ; DWORD len = sizeof(str); if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\" REGKEY "\\v3.6\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS) { if (RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) str, &len) == 0) { RegCloseKey (key) ; appendPathSeparator(str); return string(str); } RegCloseKey (key) ; } if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\v3.6\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS) { if (RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) str, &len) == 0) { RegCloseKey (key) ; appendPathSeparator(str); return string(str); } RegCloseKey (key) ; } return string(); } bool copy36EditSettings(void) { HKEY hKeySrc ; HKEY hKeyDst ; DWORD result ; HINSTANCE hLib ; shCopyType *shCopyKey ; if ((hLib = LoadLibrary ("shlwapi.dll")) == NULL) return (false) ; shCopyKey = (shCopyType *) GetProcAddress (hLib, "SHCopyKeyA") ; if (shCopyKey == NULL) { FreeLibrary (hLib) ; return (false) ; } if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\v3.6", 0, KEY_READ, &hKeySrc) != ERROR_SUCCESS) { FreeLibrary (hLib) ; return (false) ; } if (RegCreateKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit", 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyDst, NULL) != ERROR_SUCCESS) { RegCloseKey (hKeySrc) ; FreeLibrary (hLib) ; return (false) ; } result = shCopyKey (hKeySrc, "POV-Edit", hKeyDst, NULL) ; RegCloseKey (hKeySrc) ; RegCloseKey (hKeyDst) ; FreeLibrary (hLib) ; return (result == ERROR_SUCCESS) ; } bool checkEditKey36 (void) { HKEY key ; if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\v3.6\\POV-Edit", 0, KEY_READ, &key) == ERROR_SUCCESS) { RegCloseKey (key) ; return (true) ; } return (false) ; } bool checkEditKey37 (void) { HKEY key ; if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit", 0, KEY_READ, &key) == ERROR_SUCCESS) { RegCloseKey (key) ; return (true) ; } return (false) ; } // called if either our registry entries don't seem to be set up, or if they do exist and // the FreshInstall option is set in the registry. bool CloneOptions (void) { if (debugging) debug_output("attempting to create registry entries\n") ; // don't do this if we're being called as a result of the FreshInstall registry setting if (!FreshInstall) { if (!reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "Home", "%s", BinariesPath)) return (false) ; if (!homeInferred) reg_printf (true, "Software\\" REGKEY "\\CurrentVersion\\Windows", "Home", "%s", BinariesPath) ; } reg_printf (true, "Software\\" REGKEY "\\CurrentVersion\\Windows", VERSIONVAL, "%s", POV_RAY_VERSION) ; cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open", "Open0", "%sChanges.txt,1,1,0,0,8,2", DocumentsPath) ; cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent0", "%sChanges.txt,1,1,0,0,8,2", DocumentsPath) ; cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open", "Open1", "%sRevision.txt,1,1,0,0,8,2", DocumentsPath) ; cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent1", "%sRevision.txt,1,1,0,0,8,2", DocumentsPath) ; cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open", "Open2", "%sscenes\\advanced\\biscuit.pov,1,1,0,6,8,2", DocumentsPath) ; cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent2", "%sscenes\\advanced\\biscuit.pov,1,1,0,6,8,2", DocumentsPath) ; cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open", "Open3", "%sscenes\\advanced\\woodbox.pov,1,1,0,6,8,2", DocumentsPath) ; cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent3", "%sscenes\\advanced\\woodbox.pov,1,1,0,6,8,2", DocumentsPath) ; return (true) ; } int parse_commandline (char *s) { char *prevWord = NULL ; char inQuote = '\0' ; static char str [_MAX_PATH * 3] ; static char filename [_MAX_PATH] ; argc = 0 ; GetModuleFileName (hInstance, filename, sizeof (filename) - 1) ; argv [argc++] = filename ; s = strncpy (str, s, sizeof (str) - 1) ; while (*s) { switch (*s) { case '"' : case '\'' : if (inQuote) { if (*s == inQuote) inQuote = 0 ; } else { inQuote = *s ; if (prevWord == NULL) prevWord = s ; } break ; case ' ' : case '\t' : if (!inQuote) { if (prevWord != NULL) { *s = '\0' ; argv [argc++] = prevWord ; prevWord = NULL ; } } break ; default : if (prevWord == NULL) prevWord = s ; break ; } if (argc >= MAX_ARGV - 1) break ; s++ ; } if (prevWord != NULL && argc < MAX_ARGV - 1) argv [argc++] = prevWord ; argv [argc] = NULL ; return (argc) ; } int InstallSettings (char *binpath, char *docpath, bool quiet) { char base [_MAX_PATH] ; char str [_MAX_PATH] ; char *s ; // we attempt to infer the install dir if it's not supplied if (binpath == NULL) { if (_getcwd (base, sizeof (base) - 1) == NULL) { if (!quiet) MessageBox (NULL, "Could not get current directory - cannot infer home path. Please supply it on the command-line", "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ; return 5 ; } if (strlen (base) < 3 || (strlen (base) == 3 && base [1] == ':' && isPathSeparator(base [2]))) { if (!quiet) { sprintf (str, "Current dir '%s' is root - cannot infer home path. Please supply it on the command-line.", base) ; MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ; } return 10 ; } // the strlen test covers the case where base is "\\" (i.e. a network path) or a bare drive (e.g. "c:"). if (!StripPathComponent (base, 1) || strlen(base) < 3) { if (!quiet) MessageBox (NULL, "Cannot infer home path. Please supply it on the command-line.", "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ; return 15 ; } } else { strcpy (str, binpath) ; s = trimDoubleQuotes(str); validatePath (s) ; if (GetFullPathName (s, sizeof (base), base, NULL) == 0) { sprintf (str, "GetFullPathName() for '%s' failed [0x%08x]", s, GetLastError ()) ; MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ; } } if (!dirExists (base)) { if (!quiet) { sprintf (str, "Could not stat directory '%s'", base) ; MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ; } return 20 ; } if (docpath != NULL) { if (!dirExists(docpath)) { // if the path doesn't exist and quiet is selected, we continue, assuming that // by the time povray is ready to be used, it will either exist or be able to be // created. note that we do auto-create the path if possible (i.e. the parent // directory exists and is writable by the user who launches POV-Ray). if (!quiet) if (MessageBox (NULL, "Could not verify supplied user files path: use it anyway?\n(Selecting NO will exit.)", "POV-Ray for Windows - running INSTALL option", MB_YESNO | MB_ICONEXCLAMATION) == IDNO) return 30; } reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "DocPath", "%s\\", docpath); } if (!reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "Home", "%s\\", base)) { if (!quiet) MessageBox (NULL, "Failed to write to HKCU in registry", "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ; return 35 ; } // it's ok for this to fail as they may not have administrative rights reg_printf (false, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "Home", "%s\\", base) ; if (!quiet) { sprintf (str, "[Home path is %s]\n\nSuccess!", base) ; MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONINFORMATION) ; } return (0) ; } char *GetExceptionDescription (DWORD code) { switch (code) { case EXCEPTION_ACCESS_VIOLATION : return ("a memory access violation") ; case EXCEPTION_DATATYPE_MISALIGNMENT : return ("a datatype misalignment") ; case EXCEPTION_FLT_DENORMAL_OPERAND : return ("a denormal floating point operand") ; case EXCEPTION_FLT_DIVIDE_BY_ZERO : return ("a floating point divide by zero") ; case EXCEPTION_FLT_INEXACT_RESULT : return ("an inexact floating-point result") ; case EXCEPTION_FLT_INVALID_OPERATION : return ("an invalid floating-point operation") ; case EXCEPTION_FLT_OVERFLOW : return ("a floating-point overflow") ; case EXCEPTION_FLT_STACK_CHECK : return ("a floating-point stack over/underflow") ; case EXCEPTION_FLT_UNDERFLOW : return ("a floating-point underflow") ; case EXCEPTION_INT_DIVIDE_BY_ZERO : return ("an integer divide by zero") ; case EXCEPTION_INT_OVERFLOW : return ("an integer overflow") ; case EXCEPTION_PRIV_INSTRUCTION : return ("the execution of a privileged instruction") ; case EXCEPTION_IN_PAGE_ERROR : return ("a page error") ; case EXCEPTION_ILLEGAL_INSTRUCTION : return ("the execution of an illegal instruction") ; case EXCEPTION_NONCONTINUABLE_EXCEPTION : return ("a continuation after a noncontinuable exception") ; case EXCEPTION_STACK_OVERFLOW : return ("a stack overflow") ; case EXCEPTION_INVALID_DISPOSITION : return ("an invalid disposition") ; case EXCEPTION_GUARD_PAGE : return ("a guard page exception") ; case EXCEPTION_INVALID_HANDLE : return ("an invalid handle exception") ; default : return NULL ; } } #if POV_RAY_IS_OFFICIAL == 1 // this pulls in the code for update checks and crash dump submission. // it is only used in official releases made by the POV-Ray developers, // so the source is not included in the public distribution. #include "official.h" #else LONG WINAPI ExceptionHandler(struct _EXCEPTION_POINTERS* ExceptionInfo) { char *s; long timestamp = _time32(NULL); PCONTEXT c ; static char str[2048] ; static boost::mutex mtx; boost::mutex::scoped_lock l(mtx); c = ExceptionInfo->ContextRecord ; const char *desc = GetExceptionDescription(ExceptionInfo->ExceptionRecord->ExceptionCode); if (desc == NULL) desc = "an" ; sprintf (str, "Unfortunately, it appears that %s at address 0x%p has caused this unofficial POV-Ray build to crash. " "This dialog will allow you to choose whether or not a dump file (useful for diagnostics) is written.\n\n" "NOTE: If you were running a render, you should be able to recover the part that had already been generated. " "See the 'Continue' (+c) option in the documentation for more information about this.\n\n" "Would you like to write a dump file?", desc, #ifdef _WIN64 c->Rip); #else c->Eip); #endif DWORD result = MessageBox (NULL, str, "POV-Ray for Windows", MB_ICONSTOP | MB_TOPMOST | MB_TASKMODAL | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND) ; if (result == IDYES) { // write a full dump first, then a minidump. it's no big deal if the full dump write fails. WriteDump(ExceptionInfo, true, timestamp); if ((s = WriteDump(ExceptionInfo, false, timestamp)) != NULL) { MessageBox (main_window, "The dump was successfully saved.", "POV-Ray for Windows", MB_OK) ; sprintf(str, "/select,%s", s); ShellExecute (NULL, NULL, "explorer.exe", str, NULL, SW_SHOWNORMAL) ; ExitProcess (1) ; } } else MessageBox (main_window, "POV-Ray will now exit.", "POV-Ray for Windows", MB_OK) ; ExitProcess (1) ; return (EXCEPTION_CONTINUE_SEARCH) ; // make compiler happy } #endif // POV_RAY_IS_OFFICIAL int execute_tool (char *s) { int error ; STARTUPINFO startupInfo ; PROCESS_INFORMATION procInfo ; if (strlen (s) == 0) { PovMessageBox ("No command to run!", "Tool Error") ; return (0) ; } if (*s == '$') { switch (toupper (s[1])) { case 'S' : s += 2 ; while (*s == ' ') s++ ; if (strlen (s) == 0) { PovMessageBox ("No file to open!", "Tool Error") ; return (0) ; } if ((error = PtrToInt (ShellExecute (main_window, "open", s, NULL, NULL, SW_SHOWNORMAL))) <= 32) PovMessageBox ("ShellExecute failed", "Tool Error") ; return (error) ; case 'E' : s += 2 ; while (*s == ' ') s++ ; if (strlen (s) == 0) { PovMessageBox ("No file to open!", "Tool Error") ; return (0) ; } return EditOpenFile(s) ? 0 : 1; } } startupInfo.cb = sizeof (STARTUPINFO) ; startupInfo.lpReserved = 0 ; startupInfo.lpDesktop = NULL ; startupInfo.lpTitle = NULL ; startupInfo.dwX = 0 ; startupInfo.dwY = 0 ; startupInfo.dwXSize = 0 ; startupInfo.dwYSize = 0 ; startupInfo.dwXCountChars = 0 ; startupInfo.dwYCountChars = 0 ; startupInfo.dwFillAttribute = 0 ; startupInfo.dwFlags = STARTF_USESHOWWINDOW ; startupInfo.wShowWindow = SW_SHOW ; startupInfo.cbReserved2 = 0 ; startupInfo.lpReserved2 = 0 ; if (CreateProcess (NULL, s, NULL, NULL, false, 0, NULL, NULL, &startupInfo, &procInfo) == false) { error = GetLastError () ; PovMessageBox ("Could not run program", "Tool Error") ; return (error) ; } // clean up CloseHandle (procInfo.hProcess) ; CloseHandle (procInfo.hThread) ; return (0) ; } void RenderInsertMenu (void) { int val ; char str [_MAX_PATH] ; char *s1 ; char *s2 ; FILE *f ; stop_rendering = false ; sprintf (str, "%sInsert Menu\\Images.ini", DocumentsPath) ; if ((f = fopen (str, "rt")) == NULL) { MessageBox (main_window, "Cannot open 'Images.ini' in Insert Menu directory", "Insert Menu Images", MB_OK | MB_ICONEXCLAMATION) ; return ; } InsertMenuSection = 0 ; InsertMenuSections.clear(); while (fgets (str, sizeof (str), f) != NULL) { s1 = clean (str) ; if (*s1 == '[') { if ((s2 = strchr (s1, ']')) != NULL) { *s2 = '\0' ; val = atoi (++s1) ; if (val == 0) continue ; InsertMenuSections.push_back(val); if (InsertMenuSections.size() == MAX_INSERT_MENU_SECTIONS) break ; } } } fclose (f) ; if (InsertMenuSections.empty()) { MessageBox (main_window, "No insert menu sections found in 'Images.ini'", "Insert Menu Images", MB_OK | MB_ICONSTOP) ; return ; } sprintf (str, "There are %u insert menu images to render. Press OK to start rendering these now.\n\n" "Once the render has started you can press the 'Stop Rendering' button to cancel the render job.", (unsigned int) InsertMenuSections.size()) ; if (MessageBox (main_window, str, "Insert Menu Images", MB_OKCANCEL | MB_ICONINFORMATION) == IDCANCEL) return ; PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ; update_menu_for_render (true) ; rendering_insert_menu = was_insert_render = no_status_output = true ; EditShowMessages (true) ; CalculateClientWindows (true) ; ShowWindow (message_window, SW_SHOW) ; sprintf (str, "%sInsert Menu", DocumentsPath) ; SetCurrentDirectory (str) ; StartInsertRender = true ; } int GetUCS2String(POVMSObjectPtr object, POVMSType key, char *result, int *maxlen) { UCS2 *str = new UCS2 [*maxlen] ; int err = POVMSUtil_GetUCS2String (object, key, str, maxlen) ; if (err == kNoErr) { string abc = UCS2toASCIIString (str) ; strcpy (result, abc.c_str ()) ; } delete str ; return err ; } void ShowIsPaused(void) { if (GetSession().BackendFailed() == false && rendersleep == false) { SleepTimeStart = clock () ; status_printf (StatusPPS, PPS_String (GetSession().GetPixelsRendered(), ClockTimeTotal / CLOCKS_PER_SEC)) ; say_status_message (StatusPPS, "PAUSED") ; rendersleep = true ; SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, MAKELONG (1, 0)) ; } } char *getCommandLine (void) { HKEY key ; static char str [2048] ; DWORD len = sizeof (str) ; str [0] = '\0' ; if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS) { RegQueryValueEx (key, "Command Line", 0, NULL, (BYTE *) str, &len) ; RegCloseKey (key) ; } return (str) ; } void setRunOnce (void) { #ifndef NOSETRUNONCE char str [_MAX_PATH] ; HKEY key ; DWORD result ; if (RegCreateKeyEx (HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, &result) == ERROR_SUCCESS) { GetModuleFileName (hInstance, str, sizeof (str)) ; RegSetValueEx (key, "POV-Ray for Windows", 0, REG_SZ, (BYTE *) str, (int) strlen (str) + 1) ; RegCloseKey (key) ; } #endif } void display_cleanup (bool unconditional) { if (unconditional) { gDisplay.reset(); return; } Display *d = gDisplay.get(); if (d == NULL) return; WinDisplay *wd = dynamic_cast(d); if (wd == NULL) return; if (wd->GetWidth() != render_width || wd->GetHeight() != render_height) { gDisplay.reset(); return; } wd->Clear(); } void cancel_render (void) { stop_rendering = true ; if (GetSession().BackendFailed()) { render_stopped() ; return; } if (GetSession().CancelRender() == vfeNotRunning) { // we possibly have an anamolous situation MessageBox (NULL, "Warning: had to force state to stopped", "Cancel Render", MB_OK | MB_ICONEXCLAMATION) ; render_stopped() ; } } // TODO: we have a problem here - if the parse completes very quickly, it's // possible for the VFE code to process the change to rendering mode before // we exit start_rendering() [note that the VFE worker thread runs at a higher // priority than the main UI thread]. as a result, on occasion, the VFE code // will call the display's Show() method at the same time as we are executing // display_cleanup(). display_cleanup() can cause the value of the pointer in // gDisplay to change, and potentially destroy the old one ... bool start_rendering (bool ignore_source_file) { int threadCount = ThreadCount ; char str [sizeof (command_line)] ; char path [_MAX_PATH] ; char file [_MAX_PATH] ; vfeSession& Session (GetSession()); if (Session.BackendFailed()) { MessageBox (main_window, "The render backend has shut down due to an error: please re-start POV-Ray", "Error", MB_OK | MB_ICONSTOP) ; return false; } Session.Clear(); Session.ClearOptions(); if (!keep_messages) clear_messages(false); if (running_benchmark) threadCount = benchmark_mode || benchmark_multithread ? ThreadCount : 1 ; ErrorOccurred = ErrorNotified = false ; ErrorMessage.clear() ; ErrorFilename.clear() ; status_buffer [0] = '\0' ; povray_return_code = 0 ; rendersleep = false ; SleepTimeTotal = 0 ; render_anim_count = 0 ; rendering_animation = false ; stop_rendering = false ; was_insert_render = false ; first_frame = true ; render_width = render_height = 0 ; KernelTimeStart = GetCPUTime (true, false) ; UserTimeStart = GetCPUTime (false, true) ; CPUTimeTotal = KernelTimeTotal = UserTimeTotal = 0 ; ClockTimeStart = clock () ; SecondCountStart = time (NULL) ; SleepTimeTotal = ClockTimeTotal = 0 ; status_printf (StatusPPS, "") ; say_status_message (StatusRendertime, "") ; output_to_file = false ; InputFileName.clear(); LastRenderPercentage = 0; SendMessage (StatusPanelItems [IDC_STATUS_PROGRESS].hwnd, PBM_SETPOS, 0, 0) ; say_status_message (StatusMessage, "") ; PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ; update_menu_for_render (true) ; SendMessage (toolbar_combobox, CB_GETLBTEXT, SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0), (LPARAM) SecondaryRenderIniFileSection) ; if (!StartInsertRender) { if (!temp_render_region) if (RegionStr [0] != '\0' && strstr (command_line, RegionStr + 1) == NULL) RegionStr [0] = '\0' ; } if (save_settings) { if (restore_command_line) { strcpy (str, command_line) ; strcpy (command_line, old_command_line) ; } write_INI_settings (true) ; if (restore_command_line) strcpy (command_line, str) ; EditSaveState () ; } try { // set up render options vfeRenderOptions opts ; opts.SetThreadCount (threadCount); opts.AddINI (DefaultRenderIniFileName) ; if (AutoAppendPaths || homeInferred) { sprintf (str, "%sinclude", DocumentsPath) ; opts.AddLibraryPath (str); opts.AddLibraryPath (FontPath); } if (!StartInsertRender) { if (running_demo == 0) { if (SecondaryRenderIniFileName [0] != '\0') { if (!hasTrailingPathSeparator(SecondaryRenderIniFileName)) { splitpath (SecondaryRenderIniFileName, NULL, str) ; if (str [0] != '\0') { if (SecondaryRenderIniFileSection [0] == '\0') wrapped_printf ("Preset INI file is '%s'.", SecondaryRenderIniFileName) ; else wrapped_printf ("Preset INI file is '%s', section is '%s'.", SecondaryRenderIniFileName, SecondaryRenderIniFileSection) ; sprintf (str, "%s%s", SecondaryRenderIniFileName, SecondaryRenderIniFileSection) ; opts.AddINI (str); } } } if (!ignore_source_file && strlen (source_file_name) != 0) { wrapped_printf ("Preset source file is '%s'.", source_file_name) ; splitpath (source_file_name, dir, NULL) ; SetCurrentDirectory (dir) ; sprintf (str, "%s\\povray.ini", dir) ; if (fileExists (str)) { wrapped_printf ("File '%s' exists - merging it.", str) ; opts.AddINI (str); } switch (get_file_type (source_file_name)) { case filePOV : case fileINC : opts.SetSourceFile (source_file_name); break ; case fileINI : opts.AddINI (source_file_name); break ; default : message_printf ("POV-Ray for Windows doesn't recognize this file type ; assuming POV source.\n") ; opts.SetSourceFile (source_file_name); break ; } } } if (running_benchmark) { opts.AddINI (demo_ini_name) ; opts.SetSourceFile (demo_file_name) ; if (strlen (demo_file_name) != 0) { splitpath (demo_file_name, dir, NULL) ; SetCurrentDirectory (dir) ; } } else { if (RegionStr [0] != 0) { if (strstr (command_line, RegionStr) == NULL && strstr (command_line, RegionStr + 1) == NULL) { if (!running_demo) message_printf ("Selected render region is '%s'.\n", RegionStr + 1) ; opts.AddCommand (RegionStr); } } if (strlen (command_line)) { if (!running_demo) wrapped_printf ("Rendering using command line '%s'.", command_line) ; opts.AddCommand (command_line); } } } else { // we are rendering the insert menu if (InsertMenuSection >= InsertMenuSections.size()) throw POV_EXCEPTION_STRING("Insert menu render error - we should be stopped already!"); int section = InsertMenuSections [InsertMenuSection] ; sprintf (str, "Images.ini[%d]", section) ; opts.AddINI (str); } int result = Session.SetOptions (opts) ; if (result == vfeNoInputFile) throw POV_EXCEPTION_STRING("No source file specified, either directly or via an INI file."); else if (result != vfeNoError) throw POV_EXCEPTION_STRING (Session.GetErrorString()); // TODO FIXME - magic values if (opts.GetOptions().TryGetInt(kPOVAttrib_RenderBlockSize, 32) < 4) throw POV_EXCEPTION (kParseErr, "Minimum permitted render block size is 4 (+BS4 or Render_Block_Size=4)") ; InputFileName = UCS2toASCIIString (Session.GetInputFilename()); output_to_file = opts.GetOptions().TryGetBool(kPOVAttrib_OutputToFile, true) ; render_width = Session.GetRenderWidth(); render_height = Session.GetRenderHeight(); PutHKCU("LastRender", "SceneFile", "") ; PutHKCU("LastRender", "OutputFile", "") ; PutHKCU("LastRender", "IniOutputFile", "") ; PutHKCU("LastRender", "IniOutputFile", "") ; UseAlpha = Session.GetBoolOption("Output_Alpha", false); if (Session.GetBoolOption("Display", true) == false) display_cleanup(true); if (StartInsertRender) status_printf (StatusMessage, "Rendering Insert Menu entry %d of %d", InsertMenuSection + 1, (unsigned int) InsertMenuSections.size()) ; else status_printf (StatusMessage, "Parsing %s", InputFileName.c_str()) ; if (!running_demo && !demo_mode && !benchmark_mode) { GetCurrentDirectory (sizeof (dir), dir) ; PutHKCU("LastRender", "CurrentDirectory", dir) ; splitpath ((char *) InputFileName.c_str (), path, file) ; PutHKCU("LastRender", "SourceFile", get_full_name (file)) ; splitfn (str, NULL, file, NULL) ; PutHKCU("LastRender", "SceneFile", file) ; } result = Session.StartRender(); if (result < 0) throw POV_EXCEPTION_CODE (result); else if (result > 0) throw POV_EXCEPTION_STRING (Session.GetErrorString()); } catch (std::exception& e) { int errorCode = 0 ; if (dynamic_cast (&e) != NULL) { errorCode = dynamic_cast (&e)->code() ; povray_return_code = errorCode ; } if (povray_return_code == 0) povray_return_code = -1 ; ErrorOccurred = true ; PVEnableMenuItem (CM_RENDERSHOW, MF_ENABLED) ; update_menu_for_render (false) ; if (restore_command_line) { strcpy (command_line, old_command_line) ; SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (UINT_PTR) command_line) ; restore_command_line = false ; } // make sure any outstanding messages are processed ProcessSession(); EditShowMessages (true) ; if (ErrorNotified == false) { sprintf (str, "Failed to start render: %s", e.what()) ; say_status_message (StatusMessage, str) ; message_printf ("%s\n", str) ; } if (errorCode != kCannotOpenFileErr && errorCode != kParseErr && errorCode != kOutOfMemoryErr) { sprintf (str, "Failed to set render options (%s).\nSee message pane for more details.", e.what()) ; MessageBox (main_window, str, "Error", MB_OK | MB_ICONSTOP) ; } if (ErrorFilename.empty() == false) EditShowParseError (ErrorFilename.c_str(), ErrorMessage.c_str(), ErrorLine, ErrorCol) ; if (parse_error_sound_enabled) { PlaySound (parse_error_sound, NULL, SND_NOWAIT | SND_ASYNC | SND_NODEFAULT) ; if (!running_demo && !demo_mode && !benchmark_mode) FeatureNotify ("ParserErrorSound", "POV-Ray - Parse Error Sound", "You can change the sound played upon parse errors " "from the Render Menu.\n\n" "Click Help for more information.", "sounds", false) ; } buffer_message (mDivider, "\n") ; EditShowMessages (true) ; return (false) ; } if (!StartInsertRender) { if (MenuBarDraw) { DrawMenuBar (main_window) ; MenuBarDraw = false ; } bool show = EditShowMessages (true) ; CalculateClientWindows (true) ; if (show) ShowWindow (message_window, SW_SHOW) ; PutHKCU ("Info", "Rendering", 1) ; display_cleanup (false) ; } currentX = seconds_for_last_line = -1 ; message_printf ("Rendering with %d thread%s.\n", threadCount, threadCount > 1 ? "s" : "") ; if (GetRenderWindow()) GetRenderWindow()->SetRenderState (true); ExternalEvent (EventStartRendering, 0) ; set_render_priority (render_priority) ; // FIXME - ought to wait for the render to start here rendering = true ; // StartProfile () ; return (true) ; } void render_stopped (void) { char *s ; char str [4096] ; vfeWinSession& Session (GetSession()); run_renderer = false ; rendering = false ; status_buffer[0] = '\0' ; delay_next_status = 0 ; SetStatusPanelItemText (IDC_STATUS_DATA_FRAME, "N/A") ; SendMessage (StatusPanelItems [IDC_STATUS_PROGRESS].hwnd, PBM_SETPOS, 0, 0) ; bool success = Session.Succeeded(); if (message_output_x > 0) buffer_message (mIDE, "\n") ; s = EditGetFilename(true) ; if (s != NULL && *s != '\0') { sprintf (str, "POV-Ray - %s", s) ; SetCaption (str) ; } else SetCaption ("POV-Ray for Windows") ; if ((!success || ErrorOccurred) && povray_return_code == 0) povray_return_code = -1 ; PrintRenderTimes (true, !ErrorOccurred && !stop_rendering) ; ExternalEvent (EventStopRendering, povray_return_code) ; // EndProfile () ; if (restore_command_line && !rendering_insert_menu) { strcpy (command_line, old_command_line) ; SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ; restore_command_line = false ; } if (rendering_insert_menu) { if (InsertMenuSection < InsertMenuSections.size() - 1 && !(stop_rendering || quit)) { wrapped_printf ("Completed rendering Insert Menu section %d. result = %d", InsertMenuSections [InsertMenuSection++], povray_return_code) ; StartInsertRender = true ; return ; } StartInsertRender = rendering_insert_menu = no_status_output = false ; was_insert_render = true ; } else if (running_benchmark || running_demo) { if (running_benchmark == false) { strcpy (command_line, old_command_line) ; restore_command_line = false ; } _unlink (demo_file_name) ; _unlink (demo_ini_name) ; running_benchmark = running_demo = false ; if (benchmark_mode) // only applies to benchmarks started from the command-line PostQuitMessage (0) ; if (demo_mode) { PovMessageBox ("Demonstration completed. POV-Ray will now exit.", "Finished test run") ; PostQuitMessage (0) ; } } PutHKCU("Info", "Rendering", 0U) ; set_render_priority (CM_RENDERPRIORITY_NORMAL) ; if (quit != 0 || exit_after_render) { DestroyWindow (main_window) ; return ; } WinDisplay *rw = GetRenderWindow(); if (rw != NULL) { rw->SetCaption ("POV-Ray Render Window"); rw->SetRenderState (false); if (render_auto_close) rw->Hide(); } if (main_window_hidden) TaskBarModifyIcon (main_window, 0, "POV-Ray (Restore: DblClk ; Menu: Mouse2)") ; InvalidateRect (statuspanel, NULL, false) ; if (success == true && ErrorOccurred == false) { if (render_complete_sound_enabled) { PlaySound (render_complete_sound, NULL, SND_ASYNC | SND_NODEFAULT) ; if (!running_demo && !demo_mode && !benchmark_mode) FeatureNotify ("RenderCompleteSound", "POV-Ray - Render Complete Sound", "You can change the sound played upon completion of rendering " "from the Render Menu.\n\nIt is also possible to tell POV-Ray " "for Windows to do other things when a render stops (such as " "display a message or exit.)", "sounds", false) ; } say_status_message (StatusMessage, "") ; EditShowMessages (false) ; CalculateClientWindows (false) ; switch (on_completion) { case CM_COMPLETION_EXIT : DestroyWindow (main_window) ; break ; case CM_COMPLETION_MESSAGE : PovMessageBox ("Render completed", "Message from POV-Ray for Windows") ; break ; } if (!running_demo && !demo_mode && !benchmark_mode && !rendering_insert_menu && !running_benchmark && !was_insert_render) { string ofn = UCS2toASCIIString (Session.GetOutputFilename()); if (output_to_file && ofn.size () != 0) { sprintf (str, "Output -> '%s'", ofn.c_str ()) ; say_status_message (StatusMessage, str) ; //buffer_stream_message (mIDE, str) ; sprintf (str, "Your output file has been written to the following location:\n\n" " %s\n\n" "Press F1 to learn more about how to control where files are written.", ofn.c_str ()) ; FeatureNotify ("OutputFileLocation", "POV-Ray - Output File Notification", str, "Output_File_Name", false) ; PutHKCU("LastRender", "OutputFile", ofn.c_str ()) ; } else { if (!running_benchmark) { FeatureNotify ("OutputFileOff", "POV-Ray - No Output File", "A render has completed but file output was turned off. No file " "was written.\n\nPress F1 for help on output file control.", "Output_To_File", false) ; } } } } else { if (ErrorNotified == false && ErrorMessage.empty() == false) say_status_message (StatusMessage, ErrorMessage.c_str()) ; else if (stop_rendering) say_status_message (StatusMessage, "Render cancelled by user") ; else say_status_message (StatusMessage, "Render failed") ; if (ErrorFilename.empty() == false) EditShowParseError (ErrorFilename.c_str(), ErrorMessage.c_str(), ErrorLine, ErrorCol) ; if (stop_rendering) { if (render_error_sound_enabled) { PlaySound (render_error_sound, NULL, SND_ASYNC | SND_NODEFAULT) ; if (!running_demo && !demo_mode && !benchmark_mode) FeatureNotify ("RenderErrorSound", "POV-Ray - Render Stopped Sound", "You can change the sound played upon render errors/cancellation " "from the Render Menu.", "sounds", false) ; } } else { if (parse_error_sound_enabled) { PlaySound (parse_error_sound, NULL, SND_NOWAIT | SND_ASYNC | SND_NODEFAULT) ; if (!running_demo && !demo_mode && !benchmark_mode) FeatureNotify ("ParserErrorSound", "POV-Ray - Parse Error Sound", "You can change the sound played upon parse errors " "from the Render Menu.\n\n" "Click Help for more information.", "sounds", false) ; } } } // update the mapping of included files to source files const set& rf = Session.GetReadFiles(); for (set::const_iterator it = rf.begin(); it != rf.end(); it++) { if (_stricmp(it->c_str(), InputFileName.c_str()) == 0) continue; if (is_non_primary_file(it->c_str())) { FileType ft = get_file_type(it->c_str()); if (ft < fileFirstImageType || ft > fileLastImageType) { pair::iterator, bool> result = IncludeToSourceMap.insert(pair (*it, InputFileName)); if (result.second == false) result.first->second = InputFileName; } } } } UINT WINAPI ofn_hook_fn (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG : SetupExplorerDialog (hwnd) ; break ; } return (false) ; } void init_ofn (OPENFILENAME *ofn, HWND hWnd, char *title, char *name, int maxlen, char *lastPath, char *defaultExt) { ofn->lStructSize = sizeof (OPENFILENAME) ; ofn->hwndOwner = hWnd ; ofn->hInstance = hInstance ; ofn->lpstrCustomFilter = NULL ; ofn->nMaxCustFilter = 0 ; ofn->nFilterIndex = 1 ; ofn->lpstrTitle = title ; ofn->lpstrFile = name ; ofn->nMaxFile = maxlen ; ofn->lpstrFileTitle = NULL ; ofn->nMaxFileTitle = 0 ; ofn->lpstrInitialDir = lastPath ; ofn->Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR ; if (IsW95UserInterface) ofn->Flags |= OFN_EXPLORER ; ofn->nFileOffset = 0 ; ofn->nFileExtension = 0 ; ofn->lpstrDefExt = defaultExt ; ofn->lCustData = 0L ; ofn->lpfnHook = NULL ; ofn->lpTemplateName = NULL ; } char *file_open (HWND hWnd) { int result ; OPENFILENAME ofnTemp ; static char name [_MAX_PATH] ; strcpy (name, lastRenderName) ; validatePath (lastRenderPath) ; init_ofn (&ofnTemp, hWnd, "Render File", name, sizeof (name), lastRenderPath, "pov") ; ofnTemp.lpstrFilter = "POV source and INI (*.pov;*.ini)\0*.pov;*.ini\0POV files (*.pov)\0*.pov\0INI files (*.ini)\0*.ini\0Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0" ; if ((result = GetOpenFileName (&ofnTemp)) != 0) { strcpy (lastRenderPath, name) ; // this removes the name AND the trailing '\' [which is what we want] lastRenderPath [ofnTemp.nFileOffset - 1] = '\0' ; validatePath (lastRenderPath) ; strcpy (lastRenderName, name + ofnTemp.nFileOffset) ; } return (result ? name : NULL) ; } char *get_background_file (HWND hWnd) { int result ; OPENFILENAME ofnTemp ; static char name [_MAX_PATH] ; strcpy (name, lastBitmapName) ; validatePath (lastBitmapPath) ; init_ofn (&ofnTemp, hWnd, "Tile Bitmap File", name, sizeof (name), lastBitmapPath, "bmp") ; ofnTemp.lpstrFilter = "BMP files (*.bmp)\0*.bmp\0" ; if ((result = GetOpenFileName (&ofnTemp)) != 0) { strcpy (lastBitmapPath, name) ; lastBitmapPath [ofnTemp.nFileOffset - 1] = '\0' ; strcpy (lastBitmapName, name + ofnTemp.nFileOffset) ; } return (result ? name : NULL) ; } void get_font (void) { HDC hdc ; HFONT hfont ; HFONT hfontOld ; LOGFONT lf ; CHOOSEFONT cf ; TEXTMETRIC tm ; hdc = GetDC (message_window) ; memset(&cf, 0, sizeof (CHOOSEFONT)) ; cf.lStructSize = sizeof (CHOOSEFONT) ; cf.hwndOwner = main_window ; cf.lpLogFont = &lf ; cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT ; cf.nFontType = SCREEN_FONTTYPE ; get_logfont (hdc, &lf) ; if (ChooseFont (&cf)) { if ((hfont = CreateFontIndirect (&lf)) == NULL) { PovMessageBox ("Failed to create message font", "Cannot change to selected font") ; ReleaseDC (message_window, hdc) ; return ; } hfontOld = (HFONT)SelectObject (hdc, hfont) ; GetTextMetrics (hdc, &tm) ; message_xchar = tm.tmAveCharWidth ; message_ychar = tm.tmHeight + tm.tmExternalLeading ; SelectObject (hdc, hfontOld) ; DeleteObject (message_font) ; message_font = hfont ; PovInvalidateRect (message_window, NULL, true) ; message_font_size = -MulDiv (lf.lfHeight, 72, GetDeviceCaps (hdc, LOGPIXELSY)) ; message_font_weight = lf.lfWeight ; strncpy (message_font_name, lf.lfFaceName, sizeof (message_font_name) - 1) ; } ReleaseDC (message_window, hdc) ; } void DragFunction (HDROP handle) { int cFiles ; int i ; char szFile [_MAX_PATH] ; HDIB hDIB ; bool calc = 0 ; BITMAP bm ; cFiles = DragQueryFile (handle, -1, NULL, 0) ; if (rendering) message_printf ("\n") ; for (i = 0 ; i < cFiles ; i++) { DragQueryFile (handle, i, szFile, sizeof (szFile)) ; switch (get_file_type (szFile)) { case filePOV : case fileINI : case fileINC : if (!use_editors || !drop_to_editor) break ; if ((EditGetFlags () & EDIT_CAN_OPEN) == 0) { say_status_message (StatusMessage, "Cannot open dropped file - max editor count reached") ; message_printf ("Cannot open dropped file - max editor count reached\n") ; } else EditOpenFile (szFile) ; continue ; case fileBMP : if (screen_depth < 8) { PovMessageBox ("Tiled bitmaps not supported in this color depth", "File ignored") ; continue ; } if ((hDIB = LoadDIB (szFile)) != NULL) { strcpy (background_file, szFile) ; DeleteObject (hBmpBackground) ; hBmpBackground = DIBToBitmap (hDIB, hPalApp) ; DeleteObject (hDIB) ; GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ; background_width = bm.bmWidth ; background_height = bm.bmHeight ; tile_background = true ; PovInvalidateRect (message_window, NULL, true) ; } else PovMessageBox ("Failed to load bitmap file", "Error") ; continue ; default : if (!ExternalDragFunction (szFile, dfRealDrop)) { if (!use_editors || !drop_to_editor) { say_status_message (StatusMessage, "Dropped file ignored (must be .POV, .INC, or .INI if destination is renderer)") ; wrapped_printf ("Dropped file '%s' ignored (must be .POV, .INC, or .INI if destination is renderer).", szFile) ; } else { if ((EditGetFlags () & EDIT_CAN_OPEN) == 0) { say_status_message (StatusMessage, "Cannot open dropped file - max editor count reached") ; message_printf ("Cannot open dropped file - max editor count reached\n") ; } else EditOpenFile (szFile) ; } } continue ; } if (queued_file_count < MAX_QUEUE) { strcpy (queued_files [queued_file_count++], szFile) ; wrapped_printf ("File '%s' dropped as queue entry %d.", szFile, queued_file_count) ; } else wrapped_printf ("render queue full ; file '%s' ignored.", szFile) ; } if (rendering) message_printf ("\n") ; DragFinish (handle) ; update_queue_status (true) ; if (calc) CalculateClientWindows (true) ; FeatureNotify ("DropFiles", "POV-Ray - Drag and Drop", "POV-Ray can do one of several things when you drop files onto it, " "depending on the state of the 'Drop to Editor' option and the type " "of file dropped. For example if the file is a .POV or .INI you can " "chose whether POV-Ray opens it or renders it.\n\nPress F1 for more " "information.", "drag and drop", true) ; } void WIN_Debug_Log (unsigned int from, const char *msg) { if (debugging) OutputDebugString (msg) ; } #if POV_RAY_IS_OFFICIAL != 1 void WIN_PrintOtherCredits (void) { char *s = DISTRIBUTION_MESSAGE_2 ; while (*s == ' ' || *s == '\t') s++ ; message_printf ("This is an UNSUPPORTED UNOFFICIAL COMPILE by %s.\n", s) ; } #endif void PovMessageBox (const char *message, char *title) { MessageBox (main_window, message, title, MB_ICONEXCLAMATION) ; } void detect_graphics_config (void) { HDC hdc ; hdc = GetDC (NULL) ; screen_depth = GetDeviceCaps (hdc, BITSPIXEL) ; render_bitmap_depth = (GetDeviceCaps (hdc, BITSPIXEL) > 8 && renderwin_8bits == 0) ? 24 : 8 ; screen_width = GetDeviceCaps (hdc, HORZRES) ; screen_height = GetDeviceCaps (hdc, VERTRES) ; if (GetSystemMetrics (SM_CMONITORS) > 1) { screen_origin_x = GetSystemMetrics (SM_XVIRTUALSCREEN) ; screen_origin_y = GetSystemMetrics (SM_YVIRTUALSCREEN) ; virtual_screen_width = GetSystemMetrics (SM_CXVIRTUALSCREEN) ; virtual_screen_height = GetSystemMetrics (SM_CYVIRTUALSCREEN) ; } else { screen_origin_x = screen_origin_y = 0 ; virtual_screen_width = screen_width ; virtual_screen_height = screen_height ; } ReleaseDC (NULL, hdc) ; } // Clear the system palette when we start to ensure an identity palette mapping void clear_system_palette (void) { int Counter ; HDC ScreenDC ; LogPal Palette = { 0x300, 256 } ; HPALETTE ScreenPalette ; // Reset everything in the system palette to black for (Counter = 0 ; Counter < 256 ; Counter++) { Palette.pe [Counter].peRed = 0 ; Palette.pe [Counter].peGreen = 0 ; Palette.pe [Counter].peBlue = 0 ; Palette.pe [Counter].peFlags = PC_NOCOLLAPSE ; } // Create, select, realize, deselect, and delete the palette ScreenDC = GetDC (NULL) ; ScreenPalette = CreatePalette ((LOGPALETTE *) &Palette) ; if (ScreenPalette) { ScreenPalette = SelectPalette (ScreenDC, ScreenPalette, false) ; RealizePalette (ScreenDC) ; ScreenPalette = SelectPalette (ScreenDC, ScreenPalette, false) ; DeleteObject (ScreenPalette) ; } ReleaseDC (NULL, ScreenDC) ; } void create_about_font (void) { LOGFONT lf ; HDC hdc = GetDC (NULL) ; memset (&lf, 0, sizeof (LOGFONT)) ; lf.lfHeight = -12 ; lf.lfWeight = FW_REGULAR ; lf.lfPitchAndFamily = VARIABLE_PITCH ; lf.lfCharSet = DEFAULT_CHARSET ; lf.lfQuality = PROOF_QUALITY ; strcpy (lf.lfFaceName, "Trebuchet MS") ; if ((about_font = CreateFontIndirect (&lf)) == NULL) { strcpy (lf.lfFaceName, "Arial") ; about_font = CreateFontIndirect (&lf) ; } ReleaseDC (NULL, hdc) ; } void CalculateClientWindows (bool redraw) { RECT rect ; GetClientRect (main_window, &rect) ; rect.bottom -= toolheight + statusheight ; if (!use_editors) MoveWindow (message_window, 0, toolheight, rect.right, rect.bottom, redraw) ; else SetEditorPosition (0, toolheight, rect.right, rect.bottom) ; } // handle a WM_CHAR message destined for the toolbar commandline edit control. // return true if the message is to be discarded. bool handle_toolbar_cmdline (UINT wParam, UINT lParam) { if (wParam == VK_RETURN) { SendMessage (main_window, WM_COMMAND, CM_FILERENDER, 0) ; return (true) ; } if (wParam == VK_ESCAPE) { EditSetFocus () ; return (true) ; } if (wParam == 0x01) // ctrl-a { SendMessage(toolbar_cmdline, EM_SETSEL, 0, -1); return (true) ; } return (false) ; } void SetupStatusPanel (HWND hDlg) { int max = 0 ; int ypos = 0; char str [256] ; RECT rect ; StatusPanelItem item ; GetWindowRect (hDlg, &rect) ; int x = rect.left ; int y = rect.top ; int width = rect.right - rect.left + 1 ; int height = rect.bottom - rect.top + 1 ; for (int id = IDC_STATUS_LABEL_FIRST ; id <= IDC_STATUS_ID_LAST ; id++) { item.id = id ; item.hwnd = GetDlgItem (hDlg, id) ; if (item.hwnd == NULL) continue ; if (id <= IDC_STATUS_DATA_LAST) { GetWindowText (item.hwnd, str, sizeof (str)) ; HDC hdc = GetDC (item.hwnd) ; HFONT hFont = (HFONT) SendMessage (item.hwnd, WM_GETFONT, 0, 0) ; HFONT oldFont = (HFONT) SelectObject (hdc, hFont) ; GetTextExtentPoint32 (hdc, str, (int) strlen (str), &item.size) ; SelectObject (hdc, oldFont) ; ReleaseDC (GetDlgItem (hDlg, id), hdc) ; if (id <= IDC_STATUS_LABEL_LAST) if (item.size.cx > max) max = item.size.cx ; } else { GetClientRect (item.hwnd, &rect) ; item.size.cx = rect.right ; item.size.cy = rect.bottom ; } StatusPanelItems [id] = item ; } for (int id = IDC_STATUS_LABEL_FIRST; id <= IDC_STATUS_LABEL_LAST ; id++) { item = StatusPanelItems [id] ; if (item.hwnd == NULL) continue ; MoveWindow (item.hwnd, 2, ypos, max + 2, item.size.cy, false) ; item = StatusPanelItems [id + IDC_STATUS_DATA_FIRST] ; MoveWindow (item.hwnd, max + 7, ypos, width - max - 8, item.size.cy, false) ; if (id >= IDC_STATUS_DATA_FIRST) SetWindowText (item.hwnd, "") ; ypos += item.size.cy ; } item = StatusPanelItems [IDC_STATUS_PROGRESS] ; if (height - ypos > 6) { // there's at least six rows available, so we show the progress bar item.size.cy = height - ypos - 1; MoveWindow (item.hwnd, 2, ypos + 1, width - 2, item.size.cy, false) ; } else { // not enough room for progress bar: hide it ShowWindow(item.hwnd, SW_HIDE); } } void SetStatusPanelItemText (int id, LPCSTR format, ...) { char str [2048] ; va_list arg_ptr ; va_start (arg_ptr, format) ; vsprintf (str, format, arg_ptr) ; va_end (arg_ptr) ; SetWindowText (StatusPanelItems [id].hwnd, str) ; } /**************************************************************************************/ /* WINDOW PROCEDURES */ /**************************************************************************************/ /* * Return true if we are to return 0 to Windows, false if we are to continue. */ bool handle_main_command (WPARAM wParam, LPARAM lParam) { int n ; char *s ; char filename [_MAX_PATH] ; HDIB hDIB ; RECT rect ; BITMAP bm ; HBITMAP hBMP ; CHOOSECOLOR cc ; struct stat st ; static char str [8192] ; vfeWinSession& Session(GetSession()); if (process_toggles (wParam)) return (true) ; if (LOWORD (wParam) >= CM_FIRSTTOOL && LOWORD (wParam) <= CM_LASTTOOL) { s = parse_tool_command (tool_commands [LOWORD (wParam) - CM_FIRSTTOOL]) ; if (GetHKCU("General", "Debug", 0)) message_printf ("Tool request - in '%s', out '%s'\n", tool_commands [LOWORD (wParam) - CM_FIRSTTOOL], s) ; else execute_tool (s) ; return (true) ; } if (LOWORD (wParam) >= CM_FIRSTMENUHELP && LOWORD (wParam) <= CM_LASTMENUHELP) { menuhelp (LOWORD (wParam)) ; return (true) ; } if (LOWORD (wParam) >= CM_DUTYCYCLE_10 && LOWORD (wParam) <= CM_DUTYCYCLE_100) { PVCheckMenuRadioItem (CM_DUTYCYCLE_10, CM_DUTYCYCLE_100, LOWORD (wParam)) ; Duty_Cycle = LOWORD (wParam) - CM_DUTYCYCLE_10 ; return (true) ; } #ifdef RTR_SUPPORT if (LOWORD (wParam) >= CM_FIRSTVIDEOSOURCE && LOWORD (wParam) <= CM_LASTVIDEOSOURCE) { char str [256] ; MENUITEMINFO mi ; mi.cbSize = sizeof (MENUITEMINFO) ; mi.fMask = MIIM_TYPE ; mi.dwTypeData = str ; mi.cch = sizeof (str) ; if (GetMenuItemInfo(hVidcapMenu, LOWORD (wParam), false, &mi)) { PVCheckMenuRadioItem (CM_FIRSTVIDEOSOURCE, CM_LASTVIDEOSOURCE, LOWORD (wParam)) ; status_printf (StatusMessage, "Selected video source '%s'", str) ; SetVideoSourceName(str); } return (true) ; } #endif if (LOWORD (wParam) >= CM_FIRSTEDITNOTIFY && LOWORD (wParam) <= CM_LASTEDITNOTIFY) { switch (LOWORD (wParam) - CM_FIRSTEDITNOTIFY) { case NotifyTabChange : if ((lParam & EDIT_MSG_SELECTED) == 0) { build_editor_menu (hMainMenu) ; PVEnableMenuItem (CM_FILESAVE, (lParam & EDIT_CURRENT_MODIFIED) ? MF_ENABLED : MF_GRAYED) ; PVEnableMenuItem (CM_FILECLOSE, MF_ENABLED) ; s = EditGetFilename(true) ; if (s != NULL && *s != '\0') { sprintf (str, rendersleep ? "POV-Ray (paused) - %s" : "POV-Ray - %s", s) ; SetCaption (str) ; } else SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ; } else { build_main_menu (hMainMenu, true) ; PVEnableMenuItem (CM_FILESAVE, MF_GRAYED) ; PVEnableMenuItem (CM_FILECLOSE, MF_GRAYED) ; SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ; } break ; case NotifyModifiedChange : PVEnableMenuItem (CM_FILESAVE, lParam ? MF_ENABLED : MF_GRAYED) ; s = EditGetFilename(true) ; if (s != NULL && *s != '\0') { sprintf (str, rendersleep ? "POV-Ray (paused) - %s" : "POV-Ray - %s", s) ; SetCaption (str) ; } else SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ; break ; case NotifyFocusSaveModified : FeatureNotify ("FocusSaveModified", "POV-Ray - Modified Files Auto-Saved", "Your modified files were automatically saved when you switched to another " "application. This is necessary for the Auto-Reload feature to work. If you " "do not want this to happen, turn auto-reload off via the Editor menu.\n\n" "Click Help for more information.", "auto-reload", false) ; break ; case NotifyExitRequest : handle_main_command (CM_FILEEXIT, 0) ; break ; } return (true) ; } switch (LOWORD (wParam)) { case CM_HIDENEWUSERHELP : set_newuser_menus (hide_newuser_help) ; return (0) ; case CM_IO_NO_RESTRICTIONS : case CM_IO_RESTRICT_WRITE : case CM_IO_RESTRICT_READWRITE : io_restrictions = LOWORD (wParam) - CM_IO_NO_RESTRICTIONS ; PVCheckMenuRadioItem (CM_IO_NO_RESTRICTIONS, CM_IO_RESTRICT_READWRITE, LOWORD (wParam)) ; PutHKCU ("Scripting", "IO Restrictions", io_restrictions) ; SetupFrontend(); return (0) ; case CM_SHOWMAINWINDOW : if (main_window_hidden) { if (ListenMode) { char *s = "POV-Ray is in network listen mode. Press OK to continue listening or " "CANCEL to shut down and exit." ; if (MessageBox (main_window, s, "POV-Ray - Network Listen Mode", MB_OKCANCEL) == IDOK) return (0) ; TaskBarDeleteIcon (main_window, 0) ; DestroyWindow (main_window) ; return (0) ; } ShowWindow (main_window, SW_SHOW) ; ShowWindow (main_window, SW_RESTORE) ; if (RenderwinIsChild == false && HideRenderWithMain == true) if (GetRenderWindow() != NULL) GetRenderWindow()->Show(); PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ; main_window_hidden = 0 ; TaskBarDeleteIcon (main_window, 0) ; } else { if (use_taskbar) { char *s = "POV-Ray (Restore: DblClk ; Menu: Mouse Btn 2)" ; if (ListenMode) s = "POV-Ray: Network Listen Mode - DblClick for Options" ; if (TaskBarAddIcon (main_window, 0, ourIcon, s)) { ShowWindow (main_window, SW_MINIMIZE) ; ShowWindow (main_window, SW_HIDE) ; if (RenderwinIsChild == false && HideRenderWithMain == true) if (GetRenderWindow() != NULL) GetRenderWindow()->Hide(); PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Restore &Main Window from System Tray") ; main_window_hidden = true ; } } } return (0) ; case CM_FILENEW : EditOpenFile (NULL) ; return (0) ; case CM_FILEOPEN : EditBrowseFile (true) ; return (0) ; case CM_FILESAVE : EditSaveFile (NULL) ; return (0) ; case CM_FILECLOSE : EditCloseFile (NULL) ; return (0) ; case CM_RENDERSLEEP : if (Session.BackendFailed()) break ; if (!Session.IsPausable()) break ; if (Session.Paused()) { if (Session.Resume()) { SetCaption ("POV-Ray for Windows") ; FlashWindow (main_window, 0) ; SleepTimeEnd = clock () ; SleepTimeTotal += SleepTimeEnd - SleepTimeStart ; say_status_message (StatusPPS, "") ; rendersleep = false ; SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, 0) ; } else SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, MAKELONG (1, 0)) ; } else if (Session.Pause () == false) SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, 0) ; break ; case CM_DROPEDITOR : case CM_DROPRENDERER : PVCheckMenuItem (CM_DROPEDITOR, LOWORD (wParam) == CM_DROPEDITOR ? MF_CHECKED : MF_UNCHECKED) ; PVCheckMenuItem (CM_DROPRENDERER, LOWORD (wParam) == CM_DROPRENDERER ? MF_CHECKED : MF_UNCHECKED) ; drop_to_editor = LOWORD (wParam) == CM_DROPEDITOR ; break ; case CM_RENDERPRIORITY_BACKGROUND : case CM_RENDERPRIORITY_LOW : case CM_RENDERPRIORITY_NORMAL : case CM_RENDERPRIORITY_HIGH : render_priority = LOWORD (wParam) ; PVCheckMenuRadioItem (CM_RENDERPRIORITY_BACKGROUND, CM_RENDERPRIORITY_HIGH, render_priority) ; // only change process priority when the renderer is running if (rendering) set_render_priority (render_priority) ; return (true) ; case CM_COMPLETION_EXIT : case CM_COMPLETION_NOTHING : case CM_COMPLETION_MESSAGE : PVCheckMenuItem (on_completion, MF_UNCHECKED) ; on_completion = LOWORD (wParam) ; PVCheckMenuItem (on_completion, MF_CHECKED) ; return (true) ; case CM_PREVWINDOW : EditNextTab (false) ; return (true) ; case CM_NEXTWINDOW : EditNextTab (true) ; return (true) ; case CM_USETOOLBAR : if (rebar_window == NULL) return (true) ; ShowWindow (rebar_window, use_toolbar ? SW_SHOW : SW_HIDE) ; // this seems to be needed to get the rebar to redraw properly with v4.72 of comctrl32.dll. InvalidateRect (main_window, NULL, true) ; toolheight = 0 ; GetClientRect (main_window, &rect) ; SendMessage (main_window, WM_SIZE, SIZE_RESTORED, MAKELPARAM (rect.right, rect.bottom)) ; return (true) ; case CM_SINGLEINSTANCE : PutHKCU ("General", "OneInstance", one_instance) ; return (true) ; case CM_FILEEXIT : if (rendering) { if (MessageBox (main_window, "POV-Ray is currently rendering - do you want to stop ?", "Stop rendering ?", MB_ICONQUESTION | MB_YESNO) == IDYES) { if (!EditCanClose (true)) return (true) ; if (!quit) quit = time (NULL) ; cancel_render () ; } } else { if (!EditCanClose (true)) return (true) ; DestroyWindow (main_window) ; } return (true) ; case CM_FILERENDER : case CM_STOPRENDER : if (Session.BackendFailed()) return (true) ; if (!rendering) { if (EditSaveModified (NULL) == 0) return (true) ; // EDIT_MSG_SELECTED is only ever set if use_editors == true if ((EditGetFlags () & EDIT_MSG_SELECTED) == 0) { if ((s = EditGetFilename(false)) == NULL) { PovMessageBox ("No file to render in current editor tab!", "Cannot render") ; return (true) ; } n = get_file_type (s) ; if (n == filePOV || n == fileINI || !ExternalDragFunction (s, dfRenderEditor)) PostMessage (main_window, EDITOR_RENDER_MESSAGE, 0, (LPARAM) s) ; return (true) ; } SetForegroundWindow (main_window) ; if (!ExternalDragFunction (source_file_name, dfRenderMessage)) start_rendering (false) ; } else { if (Session.GetBackendState () >= kStopping) return (true) ; if (OkToStopRendering ()) { if (rendersleep) { SleepTimeEnd = clock () ; SleepTimeTotal += SleepTimeEnd - SleepTimeStart ; rendersleep = false ; } stop_rendering = true ; cancel_render () ; } } return (true) ; case CM_SAVE_SETTINGS : PutHKCU ("General", "SaveSettingsOnExit", save_settings) ; return (true) ; case CM_DUMPPANE : dump_pane_to_clipboard () ; return (true) ; case CM_CLEARMESSAGES : clear_messages () ; PovInvalidateRect (message_window, NULL, false) ; UpdateWindow (message_window) ; return (true) ; case CM_FORCE8BITS : detect_graphics_config () ; if (hPalApp) DeleteObject (hPalApp) ; hPalApp = WinLegacyDisplay::CreatePalette (NULL, 0, render_bitmap_depth != 24) ; buffer_message (mIDE, render_bitmap_depth == 24 ? "Using 24-bit internal bitmap\n" : renderwin_8bits ? "Using 8-bit dithered internal bitmap (menu setting)\n" : "Using 8-bit dithered internal bitmap (4 or 8-bit video mode)\n") ; return (true) ; case CM_RENDERABOVEMAIN : // TODO FIXME CJC #if 0 // simply re-parenting doesn't seem to have the desired effect. sigh. WinDisplay *rw = GetRenderWindow(); if (rw != NULL) { oldHwnd = render_window ; render_window = NULL ; ShowWindow (oldHwnd, SW_HIDE) ; SetForegroundWindow (main_window) ; DestroyWindow (oldHwnd) ; renderwin_manually_closed = false ; create_render_window (true) ; ShowWindow (render_window, SW_SHOW) ; } #endif PVEnableMenuItem (CM_RENDERHIDE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ; PVEnableMenuItem (CM_RENDERACTIVE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ; return (true) ; case CM_USEEDITOR : editors_enabled = !editors_enabled; PutHKCU ("General", "UseEditors", editors_enabled) ; PVCheckMenuItem (CM_USEEDITOR, editors_enabled ? MF_CHECKED : MF_UNCHECKED) ; if (editors_enabled == use_editors) return true; if (MessageBox (main_window, "POV-Ray for Windows needs to re-start for this to take effect immediately.\n\n" "Re-start POV-Ray ?", "Re-start POV-Ray for Windows ?", MB_ICONEXCLAMATION | MB_YESNO) == IDYES) { GetModuleFileName (hInstance, filename, sizeof (filename) - 1) ; if (save_settings) { SendMessage (toolbar_combobox, CB_GETLBTEXT, SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0), (LPARAM) SecondaryRenderIniFileSection) ; if (restore_command_line) { strcpy (command_line, old_command_line) ; SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ; restore_command_line = false ; } write_INI_settings () ; EditSaveState () ; } DestroyWindow (main_window) ; execute_tool (filename) ; } return (true) ; case CM_HELPABOUT : ShowAboutBox () ; return (true) ; case CM_TOOLBARCMDLINE : if (!rendering) { SetFocus (toolbar_cmdline) ; SendMessage (toolbar_cmdline, EM_SETSEL, 0, -1) ; } return (true) ; case CM_RENDERINSERT : if (!rendering) RenderInsertMenu () ; return (true) ; case CM_COMMANDLINE : if (!rendering) { if (DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_COMMANDLINE), main_window, (DLGPROC) PovCommandLineDialogProc, (LPARAM) main_window)) { if (!ExternalDragFunction (source_file_name, dfRenderCommandLine)) start_rendering (false) ; } } return (true) ; case CM_TILEDBACKGROUND : PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, tile_background ? "&Use Plain Background" : "&Use Tiled Background") ; if (tile_background && hBmpBackground == NULL) { if ((hBmpBackground = NonBogusLoadBitmap (hInstance, MAKEINTRESOURCE (BMP_BACKGROUND00))) != NULL) { GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ; background_width = bm.bmWidth ; background_height = bm.bmHeight ; tile_background = true ; PovInvalidateRect (message_window, NULL, true) ; } else { tile_background = false ; // make sure this messagebox is AFTER we set tile_background to false ! PovMessageBox ("Failed to load internal bitmap", "Error") ; PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, "&Select Tiled Background") ; background_file [0] = '\0' ; } return (true) ; } else PovInvalidateRect (message_window, NULL, true) ; return (true) ; case CM_BACKGROUNDCOLOUR : memset (&cc, 0, sizeof (CHOOSECOLOR)) ; cc.lStructSize = sizeof (CHOOSECOLOR) ; cc.hwndOwner = main_window ; cc.rgbResult = background_colour ; cc.Flags = CC_RGBINIT | CC_FULLOPEN ; cc.lpCustColors = custom_colours ; if (ChooseColor (&cc)) { background_colour = cc.rgbResult ; PovInvalidateRect (message_window, NULL, true) ; } return (true) ; case CM_BACKGROUNDBITMAP : if ((s = get_background_file (main_window)) != NULL) { if ((hDIB = LoadDIB (s)) != NULL) { strcpy (background_file, s) ; DeleteObject (hBmpBackground) ; hBmpBackground = DIBToBitmap (hDIB, hPalApp) ; DeleteObject (hDIB) ; GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ; background_width = bm.bmWidth ; background_height = bm.bmHeight ; tile_background = true ; PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, "&Select Plain Background") ; background_shade = RGB (1, 1, 1) ; PovInvalidateRect (message_window, NULL, true) ; } else PovMessageBox ("Failed to load bitmap file", "Error") ; } return (true) ; case CM_BACKGROUNDSTD + 0 : case CM_BACKGROUNDSTD + 1 : case CM_BACKGROUNDSTD + 2 : case CM_BACKGROUNDSTD + 3 : case CM_BACKGROUNDSTD + 4 : case CM_BACKGROUNDSTD + 5 : case CM_BACKGROUNDSTD + 6 : case CM_BACKGROUNDSTD + 7 : case CM_BACKGROUNDSTD + 8 : case CM_BACKGROUNDSTD + 9 : if ((hBMP = NonBogusLoadBitmap (hInstance, MAKEINTRESOURCE (BMP_BACKGROUND00 + (LOWORD (wParam) - CM_BACKGROUNDSTD)))) != NULL) { DeleteObject (hBmpBackground) ; hBmpBackground = hBMP ; if (GetObject (hBmpBackground, sizeof (BITMAP), (LPVOID) &bm) == 0) { PovMessageBox ("Failed to load internal bitmap", "Error") ; tile_background = false ; return (true) ; } background_width = bm.bmWidth ; background_height = bm.bmHeight ; background_file [0] = '0' + (char) (LOWORD (wParam) - CM_BACKGROUNDSTD) ; background_file [1] = '\0' ; switch (LOWORD (wParam)) { case CM_BACKGROUNDSTD + 0 : background_shade = RGB (1, 1, 1) ; if (lParam != 1) text_colours[0] = RGB (255, 255, 255) ; break ; case CM_BACKGROUNDSTD + 1 : background_shade = RGB (0, 0, 0) ; if (lParam != 1) text_colours[0] = RGB (255, 255, 255) ; break ; case CM_BACKGROUNDSTD + 2 : background_shade = RGB (1, 1, 1) ; if (lParam != 1) text_colours[0] = RGB (255, 255, 255) ; break ; case CM_BACKGROUNDSTD + 3 : background_shade = RGB (1, 1, 1) ; if (lParam != 1) text_colours[0] = RGB (255, 255, 255) ; break ; case CM_BACKGROUNDSTD + 4 : background_shade = RGB (1, 1, 1) ; if (lParam != 1) text_colours[0] = RGB (255, 255, 255) ; break ; case CM_BACKGROUNDSTD + 5 : background_shade = RGB (1, 1, 1) ; if (lParam != 1) text_colours[0] = RGB (0, 0, 0) ; break ; } tile_background = true ; PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, "&Select Plain Background") ; PovInvalidateRect (message_window, NULL, true) ; } else PovMessageBox ("Failed to load internal bitmap", "Error") ; return (true) ; case CM_TEXTCOLOUR_NORMAL : case CM_TEXTCOLOUR_WARNING : case CM_TEXTCOLOUR_ERROR : memset (&cc, 0, sizeof (CHOOSECOLOR)) ; cc.lStructSize = sizeof (CHOOSECOLOR) ; cc.hwndOwner = main_window ; cc.rgbResult = text_colours[LOWORD (wParam) - CM_TEXTCOLOUR_FIRST] ; cc.Flags = CC_RGBINIT | CC_FULLOPEN ; cc.lpCustColors = custom_colours ; if (ChooseColor (&cc)) { text_colours[LOWORD (wParam) - CM_TEXTCOLOUR_FIRST] = cc.rgbResult ; PovInvalidateRect (message_window, NULL, true) ; } return (true) ; case CM_FONT : get_font () ; return (true) ; case CM_RENDERSHOW : if (GetRenderWindow() != NULL) { GetRenderWindow()->Show(); PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ; PVEnableMenuItem (CM_RENDERCLOSE, MF_ENABLED) ; } return (true) ; case CM_RENDERCLOSE : if (GetRenderWindow() != NULL) { if (GetForegroundWindow () == GetRenderwinHandle()) if (RenderwinIsChild) SetForegroundWindow (main_window) ; GetRenderWindow()->Hide(); PVEnableMenuItem (CM_RENDERSHOW, MF_ENABLED) ; PVEnableMenuItem (CM_RENDERCLOSE, MF_GRAYED) ; } return (true) ; case CM_RENDERDESTROY : if (GetForegroundWindow () == (HWND) lParam) SetForegroundWindow (main_window) ; DestroyWindow ((HWND) lParam) ; return (true) ; case CM_CLEARQUEUE : queued_file_count = 0 ; update_queue_status (true) ; return (true) ; case CM_FILEQUEUE : DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_FILEQUEUE), main_window, (DLGPROC) PovFileQueueDialogProc, (LPARAM) main_window) ; return (true) ; case CM_SOURCEFILE : if (!rendering) { if ((s = file_open (main_window)) != NULL) { strcpy (source_file_name, s) ; splitpath (source_file_name, lastRenderPath, lastRenderName) ; validatePath (lastRenderPath) ; if (!ExternalDragFunction (source_file_name, dfRenderSourceFile)) start_rendering (false) ; } } return (true) ; case CM_RENDERSOUNDS : hh_aklink.pszKeywords = "sounds" ; DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_SOUNDS), main_window, (DLGPROC) PovSoundsDialogProc, (LPARAM) main_window) ; return (true) ; case CM_RENDERTHREADCOUNT : hh_aklink.pszKeywords = "thread count" ; // TODO DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_THREADS), main_window, (DLGPROC) PovThreadCountDialogProc, (LPARAM) main_window) ; return (true) ; case CM_DEMO : if (!rendering && !running_demo) { if (save_demo_file (demo_file_name, demo_ini_name) != NULL) { if (!demo_mode) { running_demo = true ; if (DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_SHORTCOMMANDLINE), main_window, (DLGPROC) PovShortCommandLineDialogProc, (LPARAM) main_window)) { if (!restore_command_line) strcpy (old_command_line, command_line) ; restore_command_line = true ; sprintf (command_line, "Include_Ini='%s' Input_File_Name='%s' ", demo_ini_name, demo_file_name) ; _strupr (command_line) ; strcat (command_line, old_command_line) ; ignore_auto_ini = true ; start_rendering (true) ; } } else { if (!restore_command_line) strcpy (old_command_line, command_line) ; restore_command_line = true ; sprintf (command_line, "Include_Ini='%s' Input_File_Name='%s' ", demo_ini_name, demo_file_name) ; running_demo = true ; start_rendering (true) ; } } } return (true) ; case CM_BENCHMARK : case CM_BENCHMARKONETHREAD : if (rendering) return (0) ; if (!benchmark_mode) { n = Get_Benchmark_Version () ; hh_aklink.pszKeywords = "Run Benchmark" ; sprintf (str, "This command will run the standard POV-Ray benchmark version %x.%02x.\n", n / 256, n % 256) ; strcat (str, "This will take some time, and there will be no display or file output.\n\n") ; strcat (str, "Note that the benchmark has changed since v3.6 and cannot be compared with it.\n\n") ; if (LOWORD (wParam) == CM_BENCHMARK) { sprintf(str + strlen(str), "The benchmark will be rendered using %d threads. Continue?", ThreadCount) ; benchmark_multithread = true ; } else { strcat (str, "The benchmark will be rendered using a single thread. Continue?") ; benchmark_multithread = false ; } if (MessageBox (main_window, str, "Standard Benchmark", MB_YESNO | MB_ICONINFORMATION | MB_HELP) == IDNO) return (0) ; } GetTempPath (_MAX_PATH - 16, demo_file_name) ; appendPathSeparator(demo_file_name) ; strcpy (demo_ini_name, demo_file_name) ; strcat (demo_file_name, "POVBENCH.$$1") ; strcat (demo_ini_name, "POVBENCH.$$2") ; if (Write_Benchmark_File (demo_file_name, demo_ini_name)) { running_benchmark = running_demo = true ; int threadCount = benchmark_mode || benchmark_multithread ? ThreadCount : 1 ; message_printf ("Running standard POV-Ray benchmark version %x.%02x using %d thread%s\n", n / 256, n % 256, threadCount, threadCount > 1 ? "s" : "") ; buffer_message (mDivider, "\n") ; status_printf (0, "Running standard POV-Ray benchmark version %x.%02x\n", n / 256, n % 256) ; start_rendering (true) ; } else PovMessageBox ("Failed to write temporary files", "Benchmark Failed") ; return (true) ; case CM_LOADTOOLMENU : ExternalEvent (EventLoadToolMenu, 0) ; load_tool_menu (ToolIniFileName) ; break ; case CM_HELPLOOKUP : if (GetFocus () == GetRenderwinHandle ()) { hh_aklink.pszKeywords = "Render Window" ; HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ; return (true) ; } if (GetFocus () == toolbar_cmdline) { hh_aklink.pszKeywords = "Toolbar Command Line" ; HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ; return (true) ; } if (GetFocus () == toolbar_combobox) { hh_aklink.pszKeywords = "Preset Rendering Options" ; HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ; return (true) ; } if ((EditGetFlags () & EDIT_MSG_SELECTED) != 0) HtmlHelp (NULL, engineHelpPath, HH_DISPLAY_TOC, 0) ; else EditContextHelp () ; return (true) ; case CM_HELPPOVWIN : hh_aklink.pszKeywords = "welcome" ; HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ; return (true) ; case CM_HELPSCENE : hh_aklink.pszKeywords = "Scene Description Language" ; HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ; return (true) ; case CM_GOPOVRAYORG : ShellExecute (NULL, NULL, "http://www.povray.org/", NULL, NULL, SW_SHOWNORMAL) ; return (true) ; case CM_HELPBUGS : hh_aklink.pszKeywords = "Bug Reports" ; HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ; return (true) ; case CM_POVLEGAL : if (stat (engineHelpPath, &st) == 0) { hh_aklink.pszKeywords = "POV-Ray License" ; if (HtmlHelp (main_window, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink)) return (true) ; } DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_VIEW), main_window, (DLGPROC) PovLegalDialogProc, (LPARAM) main_window) ; return (true) ; case CM_CHECKUPDATENOW: #if POV_RAY_IS_OFFICIAL == 1 ManualUpdateCheck(); #endif return true; } return (false) ; } LRESULT CALLBACK PovMainWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { int i ; char *s ; char str [4096] ; bool f ; HDC hdc ; RECT rect ; POINT pt ; NMHDR *nmh ; DWORD result = 0 ; HPALETTE oldPalette ; TOOLTIPTEXT *t ; COPYDATASTRUCT *cd ; vfeSession& Session (GetSession()); PROCESS_MEMORY_COUNTERS memInfo; switch (message) { case WM_COPYDATA : cd = (COPYDATASTRUCT *) lParam ; if (cd->dwData == EDIT_FILE) { strncpy (str, (char *) cd->lpData, sizeof (str) - 1) ; str [sizeof (str) - 1] = '\0' ; if (EditGetFlags () & EDIT_CAN_OPEN) EditOpenFile (str) ; return (0) ; } if (cd->dwData == RENDER_FILE) { strncpy (str, (char *) cd->lpData, sizeof (str) - 1) ; str [sizeof (str) - 1] = '\0' ; if (rendering) return (0) ; strcpy (source_file_name, str) ; start_rendering (false) ; return (0) ; } return (1) ; case COPY_COMMANDLINE_MESSAGE : command_line [sizeof (command_line) - 1] = '\0' ; strncpy (command_line, (LPCSTR) lParam, sizeof (command_line) - 1) ; SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ; SendMessage (toolbar_cmdline, EM_SETSEL, 0, strlen (command_line)) ; SetFocus (toolbar_cmdline) ; return (true) ; case WM_HELP : // we expect that whatever routine caused the WM_HELP would have set up the keyword HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ; return (true) ; case KEYWORD_LOOKUP_MESSAGE : hh_aklink.pszKeywords = (LPCSTR) lParam ; if (strncmp (hh_aklink.pszKeywords, "oooo", 4) == 0) hh_aklink.pszKeywords = "" ; if (strncmp (hh_aklink.pszKeywords, "//", 2) == 0) hh_aklink.pszKeywords = "" ; HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ; return (true) ; case TASKBAR_NOTIFY_MESSAGE : if (lParam == WM_LBUTTONDBLCLK) { if (ListenMode) { char *s = "POV-Ray is in network listen mode. Press OK to continue listening or " "CANCEL to shut down and exit." ; if (MessageBox (main_window, s, "POV-Ray - Network Listen Mode", MB_OKCANCEL | MB_SYSTEMMODAL) == IDOK) return (0) ; TaskBarDeleteIcon (main_window, 0) ; DestroyWindow (main_window) ; return (0) ; } ShowWindow (main_window, SW_SHOW) ; ShowWindow (main_window, SW_RESTORE) ; if (RenderwinIsChild == false && HideRenderWithMain == true) if (GetRenderWindow() != NULL) GetRenderWindow()->Show(); PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ; main_window_hidden = 0 ; TaskBarDeleteIcon (main_window, 0) ; return (0) ; } if (lParam == WM_RBUTTONDOWN) { if (ListenMode) return (0) ; if (hPopupMenus != NULL) { GetCursorPos (&pt) ; SetForegroundWindow (main_window) ; TrackPopupMenu (GetSubMenu (hPopupMenus, 0), TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, main_window, NULL) ; return (0) ; } } return (0) ; case WM_ENTERSIZEMOVE : if (!IsW95UserInterface) break ; resizing = true ; break ; case WM_EXITSIZEMOVE : if (!IsW95UserInterface) break ; resizing = false ; InvalidateRect (message_window, NULL, true) ; break ; case WM_SETFOCUS : // After a dialog has been displayed, Windows will give the focus // back to our main window. We need to farm the focus off to whatever // window should have it. EditSetFocus () will handle this for us. EditSetFocus () ; return (0) ; case EDITOR_RENDER_MESSAGE : if (rendering) { if (OkToStopRendering ()) { stop_rendering = true ; cancel_render () ; } return (0) ; } strcpy (source_file_name, (char *) lParam) ; if (is_non_primary_file(source_file_name)) { char fn[_MAX_PATH + 1]; strcpy(fn, source_file_name); _strlwr(fn); // see if we have a previous decision recorded for this file. map::const_iterator altit = IncludeAlternateDecisionMap.find(fn); if (altit == IncludeAlternateDecisionMap.end() || altit->second == true) { // either there is no decision recorded, or the decision was 'yes' // in either case we need to find the alternate filename map::const_iterator it = IncludeToSourceMap.find(fn); if (it != IncludeToSourceMap.end()) { // we've found the alternate filename. do we need to ask the user about it? if (altit == IncludeAlternateDecisionMap.end()) { // yes we do. switch (DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_RENDERALTERNATEFILE), main_window, (DLGPROC) RenderAlternativeFileDialogProc, (LPARAM) it->second.c_str())) { case IDYES: // record the decision IncludeAlternateDecisionMap.insert(pair(fn, true)); strcpy(source_file_name, it->second.c_str()); break; case IDOK: // we don't record this decision strcpy(source_file_name, it->second.c_str()); break; case IDNO: // record the decision IncludeAlternateDecisionMap.insert(pair(fn, false)); break; case IDCANCEL: return (0) ; } } else strcpy(source_file_name, it->second.c_str()); } } } splitpath (source_file_name, lastRenderPath, lastRenderName) ; if (!ExternalDragFunction (source_file_name, dfRenderEditor)) start_rendering (false) ; return (0) ; case CREATE_RENDERWIN_MESSAGE : if (dynamic_cast(reinterpret_cast(lParam)) != NULL) return (dynamic_cast(reinterpret_cast(lParam))->CreateRenderWindow()); return (0) ; case GUIEXT_CREATE_EDITOR : if (wParam == 0) { message_printf ("External application or GUIEXT sent zero-length wParam for GUIEXT_CREATE_EDITOR\n") ; return (0) ; } if (IsBadReadPtr ((void *) lParam, wParam + 1)) { message_printf ("External application or GUIEXT sent bad paramstr address for GUIEXT_CREATE_EDITOR\n") ; return (0) ; } if (((char *) lParam) [wParam] != '\0') { message_printf ("External application or GUIEXT sent non-NULL terminated paramstr for GUIEXT_CREATE_EDITOR\n") ; return (0) ; } return (EditExternalOpenFile ((char *) lParam)) ; case WM_NOTIFY : nmh = (NMHDR *) lParam ; if (nmh->hwndFrom == tab_window) { EditPassOnMessage (hwnd, message, wParam, lParam, &result) ; break ; } if (nmh->hwndFrom == rebar_window) { switch (nmh->code) { case RBN_HEIGHTCHANGE : if (!use_toolbar) break ; GetClientRect (rebar_window, &rect) ; // under XP with comctrl v6 it has been noticed that this event will occur // when the main window is minimized, before the parent's WM_SIZE message // is received, and that the return value from GetClientRect () seems to // be rather strange (e.g. 0,0,202,0 where the actual height is about 75.) if (rect.right == rect.left) break ; toolheight = rect.bottom ; CalculateClientWindows (true) ; // need this due to an issue with Windows 95 if (top_message_row) { ShowScrollBar (message_window, SB_VERT, false) ; ShowScrollBar (message_window, SB_VERT, true) ; } if (need_hscroll ()) { ShowScrollBar (message_window, SB_HORZ, false) ; ShowScrollBar (message_window, SB_HORZ, true) ; } break ; } break ; } if (nmh->hwndFrom == StatusTooltip) { if (HandleStatusTooltip(nmh)) return 0; break; } switch (nmh->code) { case TTN_NEEDTEXT : t = (TOOLTIPTEXT *) lParam ; if (use_tooltips == 0) { t->lpszText = NULL ; t->hinst = 0 ; break ; } t->hinst = hInstance ; t->lpszText = MAKEINTRESOURCE (t->hdr.idFrom) ; return (0) ; } break ; case RENDER_MESSAGE : s = getCommandLine () ; if (rendering && (strlen (s) || wParam)) { PovMessageBox ("Cannot accept new command - already rendering", "Warning") ; return (0) ; } if (main_window_hidden) { ShowWindow (main_window, SW_SHOW) ; ShowWindow (main_window, SW_RESTORE) ; if (RenderwinIsChild == false && HideRenderWithMain == true) if (GetRenderWindow() != NULL) GetRenderWindow()->Show(); PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ; main_window_hidden = 0 ; TaskBarDeleteIcon (main_window, 0) ; return (0) ; } if (wParam == 0) { if (strlen (s) == 0) return (0) ; if (!restore_command_line) strcpy (old_command_line, command_line) ; restore_command_line = true ; strcpy (command_line, s) ; start_rendering (true) ; strcpy (command_line, old_command_line) ; SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ; restore_command_line = false ; } else handle_main_command (CM_DEMO, 0) ; return (0) ; case WM_CREATE : main_window = hwnd ; hMainMenu = CreateMenu () ; build_main_menu (hMainMenu, false) ; SetMenu (main_window, hMainMenu) ; break ; case WM_QUERYENDSESSION : if (rendering) { if (MessageBox (main_window, "POV-Ray is currently rendering - do you want to stop ?", "Stop rendering ?", MB_ICONQUESTION | MB_YESNO) != IDYES) return (false) ; if (!EditCanClose (true)) return (false) ; if (!quit) quit = time (NULL) ; cancel_render () ; return (true) ; } return (EditCanClose (true)) ; case WM_ENDSESSION : if (wParam != 0) { setRunOnce () ; if (save_settings) { SendMessage (toolbar_combobox, CB_GETLBTEXT, SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0), (LPARAM) SecondaryRenderIniFileSection) ; if (restore_command_line) { strcpy (command_line, old_command_line) ; SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ; restore_command_line = false ; } write_INI_settings () ; EditSaveState () ; } } break ; case WM_COMMAND : if ((HANDLE) lParam == toolbar_cmdline) { // need to use EN_CHANGE rather than EN_KILLFOCUS as the command-line dialog // will grab and possibly modify command_line before focus is lost, should it // be activated while the edit control has focus. if (HIWORD (wParam) == EN_CHANGE) { SendMessage (toolbar_cmdline, WM_GETTEXT, sizeof (command_line) - 1, (LPARAM) command_line) ; return (0) ; } } if ((HANDLE) lParam == toolbar_combobox) { if (HIWORD (wParam) == CBN_CLOSEUP) { cb_expect_selchange++ ; return (0) ; } if (HIWORD (wParam) == CBN_SELCHANGE) { i = SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0) ; if (i == SendMessage (toolbar_combobox, CB_GETCOUNT, 0, 0) - 1) { SendMessage (toolbar_combobox, CB_SETCURSEL, tb_combo_sel, 0) ; if (cb_expect_selchange) { hh_aklink.pszKeywords = "Adding New Resolutions" ; HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ; } } else tb_combo_sel = i ; cb_expect_selchange = 0 ; return (0) ; } } if (EditPassOnMessage (hwnd, message, wParam, lParam, &result)) return (result) ; if (ExtensionsEnabled) if (LOWORD (wParam) >= CM_FIRSTGUIEXT && LOWORD (wParam) <= CM_LASTGUIEXT) return (ExternalMenuSelect (LOWORD (wParam))) ; if (handle_main_command (wParam, lParam)) return (0) ; break ; case WM_INITMENU : EditUpdateMenus ((HMENU) wParam) ; EditPassOnMessage (hwnd, message, wParam, lParam, &result) ; break ; case WM_ACTIVATEAPP : EditPassOnMessage (hwnd, message, wParam, lParam, &result) ; break ; case WM_TIMER : if (!BackendFailedFlag && Session.BackendFailed()) { BackendFailedFlag = true; if (rendering) { rendering = false; update_menu_for_render (false) ; PVEnableMenuItem (CM_FILERENDER, MF_DISABLED) ; PVEnableMenuItem (CM_STOPRENDER, MF_DISABLED) ; SendMessage (toolbar_window, TB_HIDEBUTTON, (WPARAM) CM_FILERENDER, MAKELONG (0, 0)) ; SendMessage (toolbar_window, TB_HIDEBUTTON, (WPARAM) CM_STOPRENDER, MAKELONG (0, 0)) ; status_buffer [0] = '\0' ; say_status_message (StatusMessage, "Render backend Failed - please re-start POV-Ray"); delay_next_status = 2500; buffer_message (mFatal, "Render backend Failed - please re-start POV-Ray\n") ; if (render_complete_sound_enabled) PlaySound (render_error_sound, NULL, SND_ASYNC | SND_NODEFAULT) ; } } if (rendering && !Session.BackendFailed() && Session.GetPercentComplete() != LastRenderPercentage) { LastRenderPercentage = Session.GetPercentComplete(); if (GetRenderWindow() != NULL) { sprintf (str, "%d%% complete", LastRenderPercentage) ; GetRenderWindow()->SetCaption(str); } if (main_window_hidden) { sprintf (str, "POV-Ray [%d%% complete] (Restore: DblClk ; Menu: Mouse2)", LastRenderPercentage) ; TaskBarModifyIcon (main_window, 0, str) ; } SendMessage (StatusPanelItems [IDC_STATUS_PROGRESS].hwnd, PBM_SETPOS, (WPARAM) LastRenderPercentage, 0) ; SetCaption (NULL) ; } if (delay_next_status) { delay_next_status -= 250 ; if (delay_next_status < 0) delay_next_status = 0 ; } if (status_buffer [0] != '\0' && delay_next_status == 0) { say_status_message (StatusMessage, status_buffer) ; status_buffer [0] = '\0' ; } memInfo.cb = sizeof(memInfo); GetProcessMemoryInfo(GetCurrentProcess(), &memInfo, sizeof(memInfo)); status_printf(StatusMem, "\t%uMB", (unsigned int) (memInfo.WorkingSetSize / 1048576)); if (TrackMem && memInfo.WorkingSetSize > PeakMem) PeakMem = memInfo.WorkingSetSize; // NOTE: if we ever change the timer rate, we need to update the editor code too. EditPassOnMessage (hwnd, message, wParam, lParam, &result) ; if (timer_ticks++ % 4 != 3) break ; seconds++ ; #if POV_RAY_IS_OFFICIAL == 1 if (seconds % 600 == 0) DoUpdateCheck () ; #endif ExternalEvent (EventTimer, seconds) ; if (MenuBarDraw) { DrawMenuBar (main_window) ; MenuBarDraw = false ; } if (!rendering) { if (auto_render) { if (queued_file_count) { queued_file_count-- ; update_queue_status (true) ; strcpy (source_file_name, queued_files [0]) ; memcpy (queued_files [0], queued_files [1], sizeof (queued_files) - sizeof (queued_files [0])) ; splitpath (source_file_name, dir, NULL) ; SetCurrentDirectory (dir) ; if (seconds < 60 && GetHKCU("Info", "Rendering", 0) != 0) { // don't run the file if we were rendering when POV exited. // [Rendering should only be set if there was an abnormal exit.] PutHKCU ("Info", "Rendering", 0U) ; message_printf ("Skipping queued file '%s' (possible abnormal exit)\n", source_file_name) ; buffer_message (mDivider, "\n") ; } else if (!ExternalDragFunction (source_file_name, dfRenderFileQueue)) start_rendering (false) ; } } } else { PrintRenderTimes (false, false) ; if (seconds % 10 == 0) { if (PreventSleep && !rendersleep) SetThreadExecutionState(ES_AWAYMODE_REQUIRED | ES_SYSTEM_REQUIRED); if (rendersleep) FlashWindow (main_window, true) ; } } return (0) ; case WM_PALETTECHANGED : // make sure it wasn't us who changed the palette, otherwise we can get into an infinite loop. if ((HWND) wParam == main_window) return (0) ; // FALL THROUGH to WM_QUERYNEWPALETTE case WM_QUERYNEWPALETTE : if (hPalApp) { hdc = GetDC (main_window) ; oldPalette = SelectPalette (hdc, hPalApp, false) ; f = (RealizePalette (hdc) != 0); SelectPalette (hdc, oldPalette, false) ; ReleaseDC (main_window, hdc) ; if (f) { PovInvalidateRect (hwnd, NULL, true) ; if ((EditGetFlags () & EDIT_MSG_SELECTED) == 0) PovInvalidateRect (message_window, NULL, true) ; if (GetRenderwinHandle() != NULL) PovInvalidateRect (GetRenderwinHandle(), NULL, true) ; } } return (0) ; case WM_SIZE : if (main_window_hidden) { // perhaps another process has sent us a SIZE_RESTORED or something if (GetRenderWindow() != NULL) if (RenderwinIsChild == false && HideRenderWithMain == true) GetRenderWindow()->Show(); PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ; main_window_hidden = 0 ; TaskBarDeleteIcon (main_window, 0) ; } mainwin_placement.length = sizeof (WINDOWPLACEMENT) ; GetWindowPlacement (main_window, &mainwin_placement) ; SendMessage (rebar_window, WM_SIZE, wParam, lParam) ; SendMessage (StatusWindow, WM_SIZE, wParam, lParam) ; ResizeStatusBar (StatusWindow) ; switch (wParam) { case SIZE_MINIMIZED : SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ; if (GetRenderWindow() != NULL) if (RenderwinIsChild == false && HideRenderWithMain == true) GetRenderWindow()->Hide(); ExternalEvent (EventSize, wParam) ; return (0) ; case SIZE_RESTORED : SendMessage (StatusWindow, WM_SIZE, wParam, lParam) ; s = EditGetFilename(true) ; if (s != NULL && *s != '\0') { sprintf (str, rendersleep ? "POV-Ray (paused) - %s" : "POV-Ray - %s", s) ; SetCaption (str) ; } else SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ; // ***** fall through ***** case SIZE_MAXIMIZED : if (GetRenderwinHandle() != NULL) if (RenderwinIsChild == false && HideRenderWithMain == true) ShowWindow (GetRenderwinHandle(), MakeRenderwinActive ? SW_SHOW : SW_SHOWNA) ; SendMessage (toolbar_window, TB_AUTOSIZE, 0, 0) ; if (use_toolbar && rebar_window != NULL) { GetClientRect (rebar_window, &rect) ; toolheight = rect.bottom ; } CalculateClientWindows (true) ; // need this due to an issue with Windows 95 if (top_message_row) { ShowScrollBar (message_window, SB_VERT, false) ; ShowScrollBar (message_window, SB_VERT, true) ; } if (need_hscroll ()) { ShowScrollBar (message_window, SB_HORZ, false) ; ShowScrollBar (message_window, SB_HORZ, true) ; } ExternalEvent (EventSize, wParam) ; break ; case SIZE_MAXHIDE : case SIZE_MAXSHOW : default : ExternalEvent (EventSize, wParam) ; return (0) ; } return (0) ; case WM_MOVE : mainwin_placement.length = sizeof (WINDOWPLACEMENT) ; GetWindowPlacement (main_window, &mainwin_placement) ; ExternalEvent (EventMove, lParam) ; return (0) ; case WM_ERASEBKGND : if (IsIconic (main_window)) { BitBlt ((HDC) wParam, 0, 0, 36, 36, NULL, 0, 0, BLACKNESS) ; return (1) ; } break ; case WM_DROPFILES : DragFunction ((HDROP) wParam) ; return (0) ; case WM_CHAR : switch ((char) wParam) { case 0x0f : // ctrl-o EditBrowseFile (true) ; return (0) ; case 0x0e : // ctrl-n (close enough to shift-ctrl-n ;) EditOpenFile (NULL) ; return (0) ; } if (EditPassOnMessage (hwnd, message, wParam, lParam, &result)) return (0) ; break ; case WM_KEYDOWN : for (i = 0 ; key2scroll [i].wVirtkey != 0xffff ; i++) { if (wParam == key2scroll [i].wVirtkey) { SendMessage (message_window, key2scroll [i].iMessage, key2scroll [i].wRequest, 0L) ; return (0) ; } } break ; case WM_MENUSELECT : if (EditPassOnMessage (hwnd, message, wParam, lParam, &result)) return (result) ; handle_menu_select (wParam, lParam) ; return (0) ; case WM_SHOWWINDOW : break ; case WM_CLOSE : if (debugging) message_printf ("Close requested, rendering is %d, quit is %u\n", rendering, quit) ; if (rendering && !quit) { if (MessageBox (main_window, "POV-Ray is currently rendering - do you want to stop ?", "Stop rendering", MB_ICONQUESTION | MB_YESNO) == IDNO) { if (debugging) message_printf ("User tells us we can't close\n") ; return (0) ; } } if (!EditCanClose (true)) { if (debugging) message_printf ("Editor tells us we can't close\n") ; return (0) ; } ExternalEvent (EventClose, 0) ; if (timer_id != 0) KillTimer (main_window, timer_id) ; DragAcceptFiles (main_window, false) ; if (!rendering || quit) { DestroyWindow (main_window) ; } else { if (!quit) quit = time (NULL) ; cancel_render () ; } return (0) ; case WM_DESTROY : if (debugging) message_printf ("Destroy requested, rendering is %d, quit is %u\n", rendering, quit) ; if (!quit) { quit = time (NULL) ; if (rendering) cancel_render () ; } ExternalEvent (EventDestroy, 0) ; if (save_settings) { SendMessage (toolbar_combobox, CB_GETLBTEXT, SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0), (LPARAM) SecondaryRenderIniFileSection) ; if (restore_command_line) { strcpy (command_line, old_command_line) ; SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ; restore_command_line = false ; } write_INI_settings () ; EditSaveState () ; } PostQuitMessage (0) ; return (0) ; } return (DefWindowProc (hwnd, message, wParam, lParam)) ; } LRESULT CALLBACK PovMessageWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { int nhs ; int msg ; int mousewheel ; HDC hdc ; RECT rect ; POINT pt ; PAINTSTRUCT ps ; static bool captured = false ; static POINT mbdownPoint ; switch (message) { case WM_MOUSEWHEEL : mousewheel = (short) (wParam >> 16) / WHEEL_DELTA ; if ((LOWORD (wParam) & (MK_MBUTTON | MK_CONTROL)) == 0) { msg = mousewheel < 0 ? SB_LINEDOWN : SB_LINEUP ; mousewheel *= 3 ; } else msg = mousewheel < 0 ? SB_PAGEDOWN : SB_PAGEUP ; mousewheel = abs (mousewheel) ; while (mousewheel--) PovMessageWndProc (hwnd, WM_VSCROLL, msg, 0) ; return (0) ; case WM_KEYDOWN : PostMessage (main_window, message, wParam, lParam) ; return (0) ; case WM_LBUTTONDOWN : SetCapture (hwnd) ; captured = true ; GetCursorPos (&mbdownPoint) ; return (0) ; case WM_LBUTTONUP : if (!captured) return (0) ; ReleaseCapture () ; captured = false ; GetCursorPos (&pt) ; GetWindowRect (hwnd, &rect) ; if (pt.x < rect.left || pt.y < rect.top || pt.x > rect.right || pt.y > rect.bottom) return (0) ; if (abs (mbdownPoint.x - pt.x) > 3 || abs (mbdownPoint.y - pt.y) > 3) { hh_aklink.pszKeywords = "text streams" ; MessageBox (hwnd, "You may use the Edit menu to copy the contents of this message pane to the clipboard\n\n" "Press Help to learn how to direct the POV-Ray text output streams to a file", "Text Selection Not Supported In This Window", MB_OK | MB_ICONINFORMATION | MB_HELP) ; } return (0) ; case WM_RBUTTONDOWN : if (hPopupMenus != NULL) { pt.x = LOWORD (lParam) ; pt.y = HIWORD (lParam) ; ClientToScreen (hwnd, &pt) ; TrackPopupMenu (GetSubMenu (hPopupMenus, 0), TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, main_window, NULL) ; } return (0) ; case WM_ERASEBKGND : return (1) ; case WM_PAINT : hdc = BeginPaint (hwnd, &ps) ; if (hPalApp) { SelectPalette (hdc, hPalApp, false) ; RealizePalette (hdc) ; } paint_display_window (hdc) ; EndPaint (hwnd, &ps) ; return (0) ; case WM_SIZE : if (message_count) { GetClientRect (hwnd, &rect) ; message_scroll_pos_x = 0 ; message_scroll_pos_y = message_count - rect.bottom / message_ychar ; if (message_scroll_pos_y < 0) message_scroll_pos_y = 0 ; } update_message_display (None) ; PovInvalidateRect (hwnd, NULL, true) ; return (0) ; case WM_VSCROLL : switch (LOWORD (wParam)) { case SB_LINEDOWN : if (message_scroll_pos_y < message_count - message_rows) { message_scroll_pos_y++ ; ScrollWindow (hwnd, 0, -message_ychar, NULL, NULL) ; update_message_display (None) ; UpdateWindow (hwnd) ; } break ; case SB_LINEUP : if (message_scroll_pos_y > 0) { message_scroll_pos_y-- ; ScrollWindow (hwnd, 0, message_ychar, NULL, NULL) ; update_message_display (None) ; UpdateWindow (hwnd) ; } break ; case SB_PAGEDOWN : if (message_scroll_pos_y < message_count - message_rows) { message_scroll_pos_y += message_rows ; if (message_scroll_pos_y > message_count - message_rows) message_scroll_pos_y = message_count - message_rows ; PovInvalidateRect (hwnd, NULL, true) ; update_message_display (None) ; } break ; case SB_PAGEUP : if (message_scroll_pos_y > 0) { message_scroll_pos_y -= message_rows ; if (message_scroll_pos_y < 0) message_scroll_pos_y = 0 ; PovInvalidateRect (hwnd, NULL, true) ; update_message_display (None) ; } break ; case SB_THUMBPOSITION : case SB_THUMBTRACK : message_scroll_pos_y = HIWORD (wParam) ; PovInvalidateRect (hwnd, NULL, true) ; update_message_display (None) ; break ; } return (0) ; case WM_HSCROLL : nhs = need_hscroll () ; switch (LOWORD (wParam)) { case SB_LINERIGHT : if (message_scroll_pos_x < nhs) { message_scroll_pos_x++ ; ScrollWindow (hwnd, -message_xchar, 0, NULL, NULL) ; update_message_display (None) ; UpdateWindow (hwnd) ; } break ; case SB_LINELEFT : if (message_scroll_pos_x > 0) { message_scroll_pos_x-- ; ScrollWindow (hwnd, message_xchar, 0, NULL, NULL) ; update_message_display (None) ; UpdateWindow (hwnd) ; } break ; case SB_PAGERIGHT : if (message_scroll_pos_x < nhs) { message_scroll_pos_x += message_cols ; if (message_scroll_pos_x > nhs) message_scroll_pos_x = nhs ; PovInvalidateRect (hwnd, NULL, true) ; update_message_display (None) ; } break ; case SB_PAGELEFT : if (message_scroll_pos_x > 0) { message_scroll_pos_x -= message_cols ; if (message_scroll_pos_x < 0) message_scroll_pos_x = 0 ; PovInvalidateRect (hwnd, NULL, true) ; update_message_display (None) ; } break ; case SB_THUMBPOSITION : case SB_THUMBTRACK : message_scroll_pos_x = HIWORD (wParam) ; PovInvalidateRect (hwnd, NULL, true) ; update_message_display (None) ; break ; } return (0) ; } return (DefWindowProc (hwnd, message, wParam, lParam)) ; } INT_PTR CALLBACK PovStatusPanelDialogProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG : MoveWindow (hDlg, 0, 0, 204, 41, false) ; SetupStatusPanel (hDlg) ; SetStatusPanelItemText (IDC_STATUS_DATA_FRAME, "N/A") ; return (false) ; } return (false) ; } LRESULT CALLBACK PovAboutWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { int button; int offset = 0; int i; HDC hdc ; HDC hdcMemory ; bool f ; DWORD threadId = 0 ; DWORD threadParam = 0 ; POINT pt; HBITMAP oldBmp ; HPALETTE oldPalette ; PAINTSTRUCT ps ; struct stat st ; LPDRAWITEMSTRUCT lpdis ; static char *url = NULL; switch (message) { case WM_CREATE : about_showing = true ; url = NULL; break ; case WM_DESTROY : about_showing = false ; EnableWindow (main_window, TRUE) ; DeleteObject (hBmpAbout) ; if (about_palette) { DeleteObject (about_palette) ; about_palette = NULL ; } hBmpAbout = NULL ; break ; case WM_MOUSEMOVE: pt.x = LOWORD (lParam); pt.y = HIWORD (lParam); for (i = 0; i < NUM_ABOUT_LINKS; i++) { if (PtInRect(AboutLinks + i, pt)) { SetCursor(LoadCursor(NULL, IDC_HAND)); url = AboutURLs[i]; return 0; } } SetCursor(LoadCursor(NULL, IDC_ARROW)); url = NULL; return 0; case WM_SETCURSOR: return 1; case WM_LBUTTONUP: if (url != NULL) { SetCursor(LoadCursor(NULL, IDC_WAIT)); // will get changed on next mouse move ShellExecute (NULL, NULL, url, NULL, NULL, SW_SHOWNORMAL) ; } return (0) ; case WM_COMMAND : if (HIWORD (wParam) != BN_CLICKED) return (false) ; for (button = 0 ; button < 3 ; button++) if (about_buttons [button] == (HWND) lParam) break ; if (button == 3) break ; switch (button) { case 0 : // if help file is missing or something, default to internal viewer if (stat (engineHelpPath, &st) == 0) { hh_aklink.pszKeywords = "POV-Ray License" ; if (HtmlHelp (main_window, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink)) return (0) ; } DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_VIEW), main_window, (DLGPROC) PovLegalDialogProc, (LPARAM) main_window) ; break ; case 1 : save_povlegal () ; break ; case 2 : about_showing = false ; EnableWindow (main_window, TRUE) ; SetFocus (main_window) ; DestroyWindow (hwnd) ; break ; } return (0) ; case WM_DRAWITEM : lpdis = (LPDRAWITEMSTRUCT) lParam ; for (button = 0 ; button < 3 ; button++) if (about_buttons [button] == lpdis->hwndItem) break ; if (button == 3) return (0) ; if ((lpdis->itemState & ODS_SELECTED) != 0) offset = 400; else if (GetWindowLongPtr(lpdis->hwndItem, GWLP_USERDATA) != 0) offset = 200; hdc = lpdis->hDC ; if (about_palette) SelectPalette (hdc, about_palette, true) ; hdcMemory = CreateCompatibleDC (hdc) ; oldBmp = (HBITMAP) SelectObject (hdcMemory, hBmpAbout) ; BitBlt (hdc, 0, 0, 165, 30, hdcMemory, offset, button * 30 + about_height, SRCCOPY) ; SelectObject (hdcMemory, oldBmp) ; DeleteDC (hdcMemory) ; return (1) ; case WM_KEYDOWN : if (wParam == VK_RETURN || wParam == VK_ESCAPE || wParam == VK_SPACE) { EnableWindow (main_window, TRUE) ; SetFocus (main_window) ; DestroyWindow (hwnd) ; return (0) ; } return (0) ; case WM_PAINT : hdc = BeginPaint (hwnd, &ps) ; if (about_palette) { SelectPalette (hdc, about_palette, false) ; RealizePalette (hdc) ; } hdcMemory = CreateCompatibleDC (hdc) ; oldBmp = (HBITMAP) SelectObject (hdcMemory, hBmpAbout) ; BitBlt (hdc, 0, 0, about_width, about_height, hdcMemory, 0, 0, SRCCOPY) ; SelectObject (hdcMemory, oldBmp) ; DeleteDC (hdcMemory) ; EndPaint (hwnd, &ps) ; return (0) ; case WM_PALETTECHANGED : // make sure it wasn't us who changed the palette, otherwise we can get into an infinite loop. if ((HWND) wParam == hwnd) return (0) ; // FALL THROUGH to WM_QUERYNEWPALETTE case WM_QUERYNEWPALETTE : if (about_palette) { hdc = GetDC (hwnd) ; oldPalette = SelectPalette (hdc, about_palette, false) ; f = (RealizePalette (hdc) != 0); SelectPalette (hdc, oldPalette, false) ; ReleaseDC (hwnd, hdc) ; if (f) PovInvalidateRect (hwnd, NULL, true) ; } return (0) ; } return (DefWindowProc (hwnd, message, wParam, lParam)) ; } LRESULT CALLBACK PovAboutButtonWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { TRACKMOUSEEVENT tme; switch (message) { case WM_MOUSEMOVE: if (GetWindowLongPtr(hwnd, GWLP_USERDATA) != 0) break; tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE; tme.dwHoverTime = 0; tme.hwndTrack = hwnd; TrackMouseEvent(&tme); InvalidateRect (hwnd, NULL, false); SetWindowLongPtr(hwnd, GWLP_USERDATA, 1); break; case WM_MOUSELEAVE: InvalidateRect (hwnd, NULL, false); SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); break; case WM_KEYDOWN: if (wParam != VK_ESCAPE) break; EnableWindow (main_window, TRUE) ; SetFocus (main_window) ; DestroyWindow (about_window) ; return (0) ; } return (CallWindowProc (about_button_wndproc, hwnd, message, wParam, lParam)) ; } void ShowAboutBox (void) { int oldMode ; MSG msg ; HDC hdcMemory ; char *s = POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER ; SIZE size ; HFONT oldFont ; BITMAP bm ; HBITMAP oldBmp ; COLORREF oldColour ; if ((hBmpAbout = NonBogusLoadBitmapAndPalette (hInstance, MAKEINTRESOURCE (BMP_ABOUT))) != NULL) { GetObject (hBmpAbout, sizeof (BITMAP), (LPSTR) &bm) ; about_width = bm.bmWidth ; about_height = bm.bmHeight - 180 ; about_palette = hPalBitmap ; if (about_font == NULL) create_about_font () ; hdcMemory = CreateCompatibleDC (NULL) ; oldFont = (HFONT) SelectObject (hdcMemory, about_font) ; oldMode = SetBkMode (hdcMemory, TRANSPARENT) ; oldColour = SetTextColor (hdcMemory, RGB (0x96, 0xD3, 0xFF)) ; oldBmp = (HBITMAP) SelectObject (hdcMemory, hBmpAbout) ; GetTextExtentPoint (hdcMemory, s, (int) strlen (s), &size) ; ExtTextOut (hdcMemory, 387, 14, 0, NULL, s, (int) strlen (s), NULL) ; SetTextColor (hdcMemory, oldColour) ; SetBkMode (hdcMemory, oldMode) ; SelectObject (hdcMemory, oldFont) ; SelectObject (hdcMemory, oldBmp) ; DeleteDC (hdcMemory) ; about_window = CreateWindowEx (0,//WS_EX_TOOLWINDOW, PovAboutWinClass, "POV-Ray", WS_POPUP, (screen_width - about_width) / 2, (screen_height - about_height) / 2, about_width, about_height, main_window, NULL, hInstance, NULL) ; for (int i = 0; i < 3; i++) { about_buttons[i] = CreateWindow ("BUTTON", "", WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, i * 184 + 27, 451, 165, 30, about_window, NULL, hInstance, NULL) ; about_button_wndproc = (WNDPROC) (ULONG_PTR) SetWindowLongPtr (about_buttons[i], GWLP_WNDPROC, (ULONG_PTR) PovAboutButtonWndProc) ; } CenterWindowRelative (main_window, about_window, false, true) ; ShowWindow (about_window, SW_SHOWNORMAL) ; SetFocus (about_window) ; EnableWindow (main_window, FALSE) ; while (about_showing && GetMessage (&msg, NULL, 0, 0) != 0 && quit == 0) { if (!TranslateAccelerator (main_window, hAccelerators, &msg)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } } } } /**************************************************************************************/ /* END OF WINDOW PROCEDURES */ /**************************************************************************************/ int register_classes (void) { WNDCLASSEX wc ; // the parameter to RegisterClass is considered CONST, so we // can assume that the structure is not changed by the calls. wc.cbSize = sizeof (wc) ; wc.hIconSm = NULL ; wc.cbClsExtra = 0 ; wc.cbWndExtra = 0 ; wc.hInstance = hInstance ; wc.lpszMenuName = NULL ; wc.hbrBackground = NULL ; // Register the main window class. wc.style = CS_BYTEALIGNCLIENT ; wc.lpfnWndProc = PovMainWndProc ; wc.hIcon = ourIcon ; wc.hCursor = LoadCursor (NULL, IDC_ARROW) ; wc.lpszClassName = PovMainWinClass ; if (RegisterClassEx (&wc) == false) return (false) ; // Register the message window class. wc.style = CS_BYTEALIGNCLIENT ; wc.lpfnWndProc = PovMessageWndProc ; wc.hIcon = NULL ; wc.hCursor = LoadCursor (NULL, IDC_ARROW) ; wc.lpszClassName = PovMessageWinClass ; if (RegisterClassEx (&wc) == false) return (false) ; // Register the about window class. wc.style = CS_BYTEALIGNCLIENT ; wc.lpfnWndProc = PovAboutWndProc ; wc.hIcon = ourIcon ; wc.hCursor = LoadCursor (NULL, IDC_ARROW) ; wc.lpszClassName = PovAboutWinClass ; if (RegisterClassEx (&wc) == false) return (false) ; // Register the render window classes wc.style = CS_BYTEALIGNCLIENT ; wc.lpfnWndProc = WinLegacyDisplay::StaticWindowProc ; wc.hIcon = renderIcon ; wc.hCursor = LoadCursor (NULL, IDC_CROSS) ; wc.hbrBackground = NULL ; wc.lpszClassName = PovLegacyRenderWinClass ; wc.cbWndExtra = 8 ; if (RegisterClassEx (&wc) == false) return (false) ; return (true) ; } void cleanup_all (void) { // TODO: nuke any render threads still running ExternalCleanupAll () ; EditUnload () ; if (use_taskbar) TaskBarDeleteIcon (main_window, 0) ; clear_messages (false) ; clear_dir_restrictions () ; DeleteCriticalSection (&critical_section) ; display_cleanup (true) ; if (hBmpBackground != NULL) DeleteObject (hBmpBackground) ; if (hBmpRendering != NULL) DeleteObject (hBmpRendering) ; if (hBmpIcon != NULL) DeleteObject (hBmpIcon) ; if (hMenuBar) DestroyMenu (hMenuBar) ; if (hMainMenu) DestroyMenu (hMainMenu) ; if (hPopupMenus) DestroyMenu (hPopupMenus) ; if (hPalApp) DeleteObject (hPalApp) ; if (message_font) DeleteObject (message_font) ; if (about_font) DeleteObject (about_font) ; if (tab_font) DeleteObject (tab_font) ; if (ourIcon) DestroyIcon (ourIcon) ; if (renderIcon) DestroyIcon (renderIcon) ; UnregisterClass (PovLegacyRenderWinClass, hInstance) ; UnregisterClass (PovMessageWinClass, hInstance) ; UnregisterClass (PovMainWinClass, hInstance) ; } #ifdef _MSC_VER void LZTimerOn (void) { if (!QueryPerformanceCounter ((LARGE_INTEGER *) &PerformanceCounter1)) PerformanceCounter1 = 0 ; } void LZTimerOff (void) { if (!QueryPerformanceCounter ((LARGE_INTEGER *) &PerformanceCounter2)) PerformanceCounter2 = 0 ; } ulong LZTimerCount (void) { if (PerformanceCounter1 == 0 || PerformanceCounter2 < PerformanceCounter1) return (0) ; return ((ulong) ((PerformanceCounter2 - PerformanceCounter1) / PerformanceScale)) ; } __int64 LZTimerRawCount (void) { if (PerformanceCounter1 == 0 || PerformanceCounter2 < PerformanceCounter1) return (0) ; return (PerformanceCounter2 - PerformanceCounter1) ; } #endif // #ifdef _MSC_VER } static void __cdecl newhandler (void) { throw std::bad_alloc () ; } using namespace povwin ; void GenerateDumpMeta(bool brief) { char str[128]; char *s = DumpMeta; char *InstalledOn ; HDC hdc ; HKEY key ; DWORD len; DWORD header = 0 ; DWORD n ; FILETIME file_time ; SYSTEMTIME system_time ; SYSTEM_INFO sysinfo ; OSVERSIONINFO version_info ; MEMORYSTATUSEX mem_status ; GetNativeSystemInfo(&sysinfo) ; if (!brief) { if ((InstalledOn = GetInstallTime()) == NULL) { GetSystemTime (&system_time) ; if (SystemTimeToFileTime (&system_time, &file_time)) reg_printf (true, "Software\\POV-Ray", INSTALLTIMEKEY, "%I64u", ((__int64) file_time.dwHighDateTime << 32) | file_time.dwLowDateTime) ; if ((InstalledOn = GetInstallTime ()) == NULL) InstalledOn = "Unknown" ; } s += sprintf(s, "installdate=%s\n", InstalledOn) ; } s += sprintf(s, "cpuarchitecture=%u\n", (DWORD) sysinfo.wProcessorArchitecture) ; s += sprintf(s, "numberofcpus=%u\n", sysinfo.dwNumberOfProcessors) ; s += sprintf(s, "processortype=%u\n", sysinfo.dwProcessorType) ; s += sprintf(s, "processorlevel=%u\n", (DWORD) sysinfo.wProcessorLevel) ; s += sprintf(s, "processorrevision=%u\n", (DWORD) sysinfo.wProcessorRevision) ; if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "HARDWARE\\Description\\System\\CentralProcessor\\0", 0, KEY_READ, &key) == ERROR_SUCCESS) { len = sizeof (n) ; if (RegQueryValueEx (key, "~MHZ", 0, NULL, (BYTE *) &n, &len) == ERROR_SUCCESS) s += sprintf(s, "cpufrequency=%u\n", n) ; len = sizeof (n) ; if (RegQueryValueEx (key, "FeatureSet", 0, NULL, (BYTE *) &n, &len) == ERROR_SUCCESS) s += sprintf(s, "cpufeatureset=%u\n", n) ; len = sizeof (str) ; if (RegQueryValueEx (key, "ProcessorNameString", 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS) s += sprintf(s, "cpuname=%s\n", str) ; len = sizeof (str) ; if (RegQueryValueEx (key, "Identifier", 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS) s += sprintf(s, "cpuidentifier=%s\n", str) ; len = sizeof (str) ; if (RegQueryValueEx (key, "VendorIdentifier", 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS) s += sprintf(s, "cpuvendoridentifier=%s\n", str) ; RegCloseKey (key) ; } version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO) ; GetVersionEx (&version_info) ; s += sprintf(s, "osversion=%u.%u\n", version_info.dwMajorVersion, version_info.dwMinorVersion) ; s += sprintf(s, "osbuild=%u\n", version_info.dwBuildNumber) ; s += sprintf(s, "csdversion=%s\n", version_info.szCSDVersion) ; if (!brief) { hdc = GetDC (NULL) ; s += sprintf(s, "bitsperpixel=%u\n", GetDeviceCaps (hdc, BITSPIXEL)) ; s += sprintf(s, "horzres=%u\n", GetDeviceCaps (hdc, HORZRES)) ; s += sprintf(s, "vertres=%u\n", GetDeviceCaps (hdc, VERTRES)) ; ReleaseDC (NULL, hdc) ; } mem_status.dwLength = sizeof (MEMORYSTATUSEX) ; GlobalMemoryStatusEx(&mem_status) ; s += sprintf(s, "physicalmemory=%I64u\n", mem_status.ullTotalPhys) ; } bool WriteDumpMeta(struct _EXCEPTION_POINTERS *ExceptionInfo, const char *filename) { FILE *f; PCONTEXT c = ExceptionInfo->ContextRecord ; static char fn[_MAX_PATH]; strcpy(fn, filename); strcat(fn, ".metadata"); if ((f = fopen(fn, "wt")) == NULL) return false; fwrite(DumpMeta, strlen(DumpMeta), 1, f); fprintf(f, "faulttype=%u\n", ExceptionInfo->ExceptionRecord->ExceptionCode); #ifdef _WIN64 fprintf(f, "faultaddress=%I64u\n", ExceptionInfo->ContextRecord->Rip); fprintf(f, "faultplatform=win64\n"); #else fprintf(f, "faultaddress=%u\n", ExceptionInfo->ContextRecord->Eip); fprintf(f, "faultplatform=win32\n"); #endif fprintf(f, "povversion=%s\n", POV_RAY_VERSION) ; fprintf(f, "compilerversion=%s\n", COMPILER_VER) ; fprintf(f, "platformversion=%s\n", PVENGINE_VER) ; fprintf(f, "remotesession=%u\n", GetSystemMetrics(SM_REMOTESESSION)) ; fclose(f); return true; } // TODO: re-write this!!! char *WriteDump(struct _EXCEPTION_POINTERS *pExceptionInfo, bool full, long timestamp) { // firstly see if dbghelp.dll is around and has the function we need // look next to the EXE first, as the one in System32 might be old // (e.g. Windows 2000) HMODULE hDll = NULL; static char szDbgHelpPath[_MAX_PATH]; if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH )) { char *pSlash = findLastPathSeparator( szDbgHelpPath ); if (pSlash) { strcpy( pSlash+1, "DBGHELP.DLL" ); hDll = ::LoadLibrary( szDbgHelpPath ); } } if (hDll==NULL) { // load any version we can hDll = ::LoadLibrary( "DBGHELP.DLL" ); } LPCTSTR szResult = NULL; if (hDll) { MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" ); if (pDump) { char szScratch [_MAX_PATH]; static char szDumpPath[_MAX_PATH]; if (full) sprintf(szScratch, "POV-Ray-" POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER "-%08X.dmp", timestamp); else sprintf(szScratch, "POV-Ray-" POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER "-%08X.minidump", timestamp); // work out a good place for the dump file if (!GetTempPath( _MAX_PATH - 64, szDumpPath)) _tcscpy( szDumpPath, "c:\\" ); _tcscat( szDumpPath, szScratch ); // create the file HANDLE hFile = ::CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile!=INVALID_HANDLE_VALUE) { _MINIDUMP_EXCEPTION_INFORMATION ExInfo; ExInfo.ThreadId = ::GetCurrentThreadId(); ExInfo.ExceptionPointers = pExceptionInfo; ExInfo.ClientPointers = NULL; // write the dump BOOL bOK = pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, full ? MiniDumpWithFullMemory : (MINIDUMP_TYPE)(MiniDumpWithDataSegs|MiniDumpWithHandleData|MiniDumpWithIndirectlyReferencedMemory), &ExInfo, NULL, NULL ); ::CloseHandle(hFile); if (bOK) { if (!WriteDumpMeta(pExceptionInfo, szDumpPath)) { MessageBox (main_window, "Failed to save dump metadata file", "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION); return NULL; } return szDumpPath; } sprintf( szScratch, "Failed to save dump file to '%s' (error %d)", szDumpPath, GetLastError() ); MessageBox (main_window, szScratch, "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION); return NULL; } sprintf( szScratch, "Failed to create dump file '%s' (error %d)", szDumpPath, GetLastError() ); MessageBox (main_window, szScratch, "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION); return NULL; } MessageBox (main_window, "Sorry, DBGHELP.DLL is too old - cannot create dump.", "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION); return NULL; } MessageBox (main_window, "Sorry, we can't locate DBGHELP.DLL - cannot create dump.", "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION); return NULL; } #ifdef BUILD_SSE2 void NoSSE2 (void) { MessageBox (NULL, "This build of POV-Ray requires that your processor provides SSE2 support.\n" "Please use the standard non-SSE2 version of POV-Ray on this computer.", "POV-Ray for Windows", MB_ICONSTOP | MB_OK) ; exit (-1) ; } inline int TestSSE2 (void) { __try { __asm { movapd xmm0,xmm1 } } __except(NoSSE2(),1) { } return (0) ; } #endif void InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) { throw POV_EXCEPTION(kParamErr, "Run-Time Library Invalid Parameter Handler invoked"); } int PASCAL WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) { #ifdef BUILD_SSE2 TestSSE2 () ; #endif int show_state ; int i ; int id = 0 ; int w, h ; char str [_MAX_PATH * 2] ; char *s = szCmdLine ; bool exit_loop = false ; bool have_cpu_info = false; unsigned n ; MSG msg ; HDC hDC ; HDIB hDIB ; RECT rect ; HWND hwnd ; DWORD help_cookie ; DWORD threadId = 0 ; DWORD threadParam = 0 ; BITMAP bm ; HBITMAP hBMP ; struct stat statbuf ; SYSTEM_INFO sysinfo ; WINDOWPLACEMENT placement ; // REMINDER: don't try to write to the message pane until initialise_message_display() has been called. _set_invalid_parameter_handler(InvalidParameterHandler); #ifdef _DEBUG _unlink ("c:\\temp\\povdebug.txt") ; _unlink ("c:\\temp\\povmem.txt") ; #endif GenerateDumpMeta(false); set_new_handler(newhandler) ; SetUnhandledExceptionFilter(ExceptionHandler); // need this now to set virtual_screen_width etc., in case we display a dialog // before the main setup (we call it again once we've read the INI file). detect_graphics_config () ; try { CreateFrontend(); } catch (pov_base::Exception& e) { sprintf (str, "Failed to initialize frontend: %s", e.what()) ; MessageBox (NULL, str, "POV-Ray Critical Error", MB_ICONSTOP) ; return (1) ; } hInstance = hInst ; hMainThread = GetCurrentThread () ; GetSystemInfo (&sysinfo) ; ThreadCount = sysinfo.dwNumberOfProcessors ; NumberOfCPUs = sysinfo.dwNumberOfProcessors ; if (GetCPUCount(&NumLogicalCPUs, &NumCPUCores, &NumPhysicalCPUs) && NumLogicalCPUs > 1) { have_cpu_info = true; ThreadCount = NumLogicalCPUs ; NumberOfCPUs = NumCPUCores ; } while (*s == ' ' || *s == '\t') s++ ; if (_stricmp (s, "/install") == 0 || _strnicmp (s, "/install ", 9) == 0 || _stricmp (s, "/qinstall") == 0 || _strnicmp (s, "/qinstall ", 10) == 0) { bool quiet = s [1] == 'q' || s [1] == 'Q' ; while (*s && *s != ' ') s++ ; argv[1] = argv[2] = NULL; parse_commandline(s); return (InstallSettings (argv[1], argv[2], quiet)) ; } getHome () ; if (BinariesPath [0] == '\0') { inferHome () ; if (BinariesPath [0] == '\0') { MessageBox (NULL, "ERROR : Cannot find Home entry in registry (and cannot infer it).\n\n" "This entry should have been set by the installation program.\n\n" "POV-Ray can usually infer the installation path but that requires a\n" "standard layout of directories, which also seems to be absent.\n\n" "If you did not install using the correct installation procedure, please\n" "do this before running POV-Ray for Windows. You can also try running\n" "with the '/INSTALL' or '/INSTALL []' option.", "Critical Error", MB_ICONSTOP) ; return (1) ; } } appendPathSeparator(BinariesPath) ; if (DocumentsPath[0] == '\0') { if (SHGetFolderPath (NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, DocumentsPath) != S_OK) { MessageBox (NULL, "ERROR : Cannot find DocPath entry in registry (and cannot infer it).\n\n" "This entry should have been set by the installation program.\n\n" "POV-Ray can usually infer the installation path but that requires a\n" "standard layout of directories, which also seems to be absent.\n\n" "If you did not install using the correct installation procedure, please\n" "do this before running POV-Ray for Windows. You can also try running\n" "with the '/INSTALL' or '/INSTALL ' option.", "Critical Error", MB_ICONSTOP) ; } strcat(DocumentsPath, "\\" REGKEY); if (!dirExists(DocumentsPath)) CreateDirectory(DocumentsPath, NULL); strcat(DocumentsPath, "\\" REGVERKEY); if (!dirExists(DocumentsPath)) CreateDirectory(DocumentsPath, NULL); } appendPathSeparator(DocumentsPath) ; sprintf(str, "%sini", DocumentsPath); if (!dirExists(str)) CreateDirectory(str, NULL); sprintf(ToolIniFileName, "%sini\\pvtools.ini", DocumentsPath); sprintf(EngineIniFileName, "%sini\\pvengine.ini", DocumentsPath); if (checkEditKey37() == false && checkEditKey36() == true) copy36EditSettings(); if (checkRegKey () == false || FreshInstall == true) if (!CloneOptions()) MessageBox (NULL, "ERROR : Could not clone options - POV-Ray may not work correctly for this user.", "Critical Error", MB_ICONERROR) ; #ifdef POVRAY_IS_BETA if (FreshInstall) { // on installing a new beta, we always turn on check new version now that we no longer // implement a short timeout. the user may switch it off if they like; we will not perform // an automatic version check in this session since FreshInstall is set, in order to give // them a chance to do it. check_new_version = true; PutHKCU("General", "CheckNewVersion", true); } #endif #ifndef MAP_INI_TO_REGISTRY if (!fileExists(EngineIniFileName)) { // no INI file: see if we can copy the 3.6 INI options, should they exist if (debugging) debug_output("no pvengine.ini: seeing if there is a v3.6 ini\n") ; string str(get36Home()); if (str.empty() == false) { string oldINIpath = str + "ini\\pvengine.ini"; if (fileExists(oldINIpath.c_str())) { if (debugging) debug_output("cloning INI file %s to %s\n", oldINIpath.c_str(), EngineIniFileName) ; cloneOldIni(str, DocumentsPath); } else { if (debugging) debug_output("creating default INI file %s\n", EngineIniFileName) ; cloneOldIni("", DocumentsPath); } } else { if (debugging) debug_output("creating default INI file %s\n", EngineIniFileName) ; cloneOldIni("", DocumentsPath); } } #endif if (homeInferred) { if (_stricmp (LastInferredHome, BinariesPath) != 0) { sprintf (str, "POV-Ray for Windows did not find the expected registry entries present.\n" "This typically means that it has not been installed via the installation program.\n" "You can correct this by running with the '/INSTALL' or '/INSTALL ' option.\n\n" "POV-Ray has inferred the installation path to be the following:\n\n" "\t%s\n\n" "This message will be displayed each time the inferred path changes.", BinariesPath) ; MessageBox (NULL, str, "Warning", MB_ICONINFORMATION) ; } reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "LastInferredHome", "%s", BinariesPath) ; } sprintf(ToolIniFileName, "%sini\\pvtools.ini", DocumentsPath); sprintf (DefaultRenderIniFileName, "%sini\\povray.ini", DocumentsPath) ; GetModuleFileName (hInst, str, sizeof (str) - 1) ; splitpath (str, modulePath, NULL) ; validatePath (modulePath) ; sprintf (engineHelpPath, "%shelp\\povray37.chm", BinariesPath) ; HtmlHelp (NULL, NULL, HH_INITIALIZE, (DWORD_PTR) &help_cookie) ; memset (&hh_aklink, 0, sizeof (hh_aklink)) ; hh_aklink.cbStruct = sizeof (hh_aklink) ; hh_aklink.fIndexOnFail = true ; hh_aklink.pszWindow = "POV-Ray Help" ; SHGetFolderPath (NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, FontPath) ; one_instance = GetHKCU("General", "OneInstance", 1) != 0 ; if ((hwnd = FindWindow (PovMainWinClass, NULL)) != NULL) { if (one_instance) { if (IsIconic (hwnd)) ShowWindow (hwnd, SW_RESTORE) ; SetForegroundWindow (hwnd) ; FeatureNotify ("OneInstanceSet", "POV-Ray - 'Keep Single Instance' Feature", "You have started POV-Ray for Windows while another copy is running, " "and the 'Keep Single Instance' option is turned on (see Options menu). " "In this case the other copy is activated rather than starting a new " "instance of the program.\n\nClick &Help for information on this feature.", "Keep Single Instance", false) ; // special case: there's a chance we're being called as a result of a windows file association // default, which allows users to associate POV-Ray with arbitrary files. in this case, no // /EDIT or /RENDER verb will be present; just the filename. what we do here is see if the // passed string is a real file by calling fileExists(). if it is, then we assume /EDIT is // desired. n = strlen(szCmdLine); if (n < _MAX_PATH && n > 2 && szCmdLine[0] == '"' && szCmdLine[n - 1] == '"') { memcpy(str, szCmdLine + 1, n - 2); str[n - 2] = '\0'; if (fileExists(str)) { FeatureNotify ("EditByDefault", "POV-Ray - Filename passed on command-line", "Quoted filenames which are the sole command-line parameter are now " "opened in the editor by default. If you wish to render them instead " "please pass the /RENDER switch, provide more than one parameter, or " "use single quotes around the path.\n\n" "Click &Help for more information.", "associations", false) ; add_edit_file(str); szCmdLine = ""; } } SetForegroundWindow (hwnd) ; if ((s = preparse_instance_commandline (szCmdLine)) != NULL) { parse_commandline(s); if (argc > 1) { PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ; return (1) ; } COPYDATASTRUCT cd ; cd.dwData = EDIT_FILE ; for (i = 0 ; i < EditFileCount ; i++) { s = EditFiles [i] ; if ((isalpha (s [0]) && s [1] == ':') || (isPathSeparator(s [0]) && isPathSeparator(s [1]))) { cd.cbData = (int) strlen (s) + 1 ; cd.lpData = s ; } else { GetCurrentDirectory (sizeof (str), str) ; if (!isPathSeparator(s [0])) { strcat (str, "\\") ; strcat (str, s) ; } else strcpy (str + 2, s) ; cd.cbData = (int) strlen (str) + 1 ; cd.lpData = str ; } SendMessage (hwnd, WM_COPYDATA, NULL, (LPARAM) &cd) ; free (EditFiles [i]) ; EditFiles [i] = NULL ; } EditFileCount = 0 ; if (render_requested) { cd.dwData = RENDER_FILE ; s = requested_render_file ; if ((isalpha (s [0]) && s [1] == ':') || (isPathSeparator(s [0]) && isPathSeparator(s [1]))) { cd.cbData = (int) strlen (s) + 1 ; cd.lpData = s ; } else { GetCurrentDirectory (sizeof (str), str) ; if (!isPathSeparator(s [0])) { strcat (str, "\\") ; strcat (str, s) ; } else strcpy (str + 2, s) ; cd.cbData = (int) strlen (str) + 1 ; cd.lpData = str ; } SendMessage (hwnd, WM_COPYDATA, NULL, (LPARAM) &cd) ; } SetForegroundWindow (hwnd) ; } else return (1) ; return (0) ; } else { // one_instance isn't set. we should continue as per normal. // however see if we need to notify the user about this. FeatureNotify ("OneInstanceUnset", "POV-Ray - 'Keep Single Instance' Feature", "You have started POV-Ray for Windows while another copy is running, " "and the 'Keep Single Instance' option is turned off (see Options menu). " "In this case a new instance of the program is started rather than " "activating the existing instance of the program.\n\nClick &Help for more " "information on this feature.", "Keep Single Instance", false) ; } } if (_strnicmp (szCmdLine, "/DEBUG", 6) == 0) { debugging = true ; debug_output(NULL) ; } SetThreadPriority (hMainThread, THREAD_PRIORITY_ABOVE_NORMAL) ; version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO) ; GetVersionEx (&version_info) ; use_editors = editors_enabled ; IsW98 = HaveWin98OrLater () ; IsWNT = HaveNT4OrLater () ; IsW2k = HaveWin2kOrLater () ; IsWXP = HaveWinXPOrLater () ; IsVista = HaveVistaOrLater () ; // yes, we actually used to support the windows 3.1 UI ... IsW95UserInterface = true ; ourIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IsWXP ? IDI_PVENGINE_XP : IDI_PVENGINE)) ; renderIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IsWXP ? IDI_RENDERWINDOW_XP : IDI_RENDERWINDOW)) ; if (hPrev == NULL) if (register_classes () == false) MessageBox (NULL, "ERROR : Could not register classes", "Error", MB_ICONSTOP) ; IsComCtl5 = GetDllVersion (TEXT ("comctl32.dll")) >= MAKELONG (5,0) ; IsComCtl6 = GetDllVersion (TEXT ("comctl32.dll")) >= MAKELONG (6,0) ; // need to init menus before we read INI settings init_menus () ; // need to do this before we detect the graphics config read_INI_settings () ; detect_graphics_config () ; clear_system_palette () ; hPalApp = WinLegacyDisplay::CreatePalette (NULL, 0, render_bitmap_depth != 24) ; if (!QueryPerformanceFrequency ((LARGE_INTEGER *) &PerformanceFrequency)) PerformanceFrequency = 0 ; if (PerformanceFrequency > 1999999) PerformanceScale = PerformanceFrequency / 1000000 ; // 'IsW95UserInterface' dates from when Windows 95 and NT4 were introduced // (at that time we still supported the old Windows 3.1 UI) // IsW95UserInterface = GetHKCU("General", "UseW95UserInterface", 1) != 0 ; IsW95UserInterface = true; info_render_complete = GetHKCU("Info", "RenderCompleteSound", 0) != 0 ; SetupFrontend(); if (!IsW95UserInterface) { PVEnableMenuItem (CM_SHOWMAINWINDOW, MF_GRAYED) ; use_taskbar = false ; } create_about_font () ; InitializeCriticalSection (&critical_section) ; GetHKCU("General", "CommandLine", "", old_command_line, sizeof (old_command_line)) ; strcpy (command_line, old_command_line) ; // special case: POV may get associated with an arbitrary file type by the user. // in such cases we won't be given any verbs to indicate what to do with the file, // and in many instances our default action (which is to assume the file is either // SDL or INI) is not appropriate. so we make an exception here for such cases. // // if the sole command-line parameter is a QUOTED filename referring to a file which // exists, we assume /EDIT is desired (this may break some scripts that assume the // default; in such cases the script should explicitly pass /RENDER). the shell // always quotes files passed in this way; by testing for the quotes we can // eliminate some unnecessary tests. n = strlen(szCmdLine); if (n < _MAX_PATH && n > 2 && szCmdLine[0] == '"' && szCmdLine[n - 1] == '"') { memcpy(str, szCmdLine + 1, n - 2); str[n - 2] = '\0'; if (fileExists(str)) { FeatureNotify ("EditByDefault", "POV-Ray - Filename passed on command-line", "Quoted filenames which are the sole command-line parameter are now " "opened in the editor by default. If you wish to render them instead " "please pass the /RENDER switch (or provide more than one parameter).\n\n" "Click &Help for more information.", "associations", false) ; add_edit_file(str); szCmdLine = ""; } } if ((szCmdLine = preparse_commandline (szCmdLine)) != NULL) { if (benchmark_mode) demo_mode = false; if (parse_commandline (szCmdLine) > 1 && !demo_mode && !benchmark_mode) { restore_command_line = true ; strncpy (command_line, szCmdLine, sizeof (command_line) - 1) ; } } if (debugging) if (_getcwd (str, sizeof (str) - 1) != NULL) debug_output("CWD is %s\n", str) ; if (editors_enabled) { if (EditDLLPath != NULL) { sprintf (str, "%s" EDITDLLNAME, EditDLLPath) ; if (!LoadEditorDLL (str, false)) use_editors = false ; } else { sprintf (str, "%s\\" EDITDLLNAME, modulePath) ; if (!LoadEditorDLL (str, true)) { sprintf (str, "%sbin\\" EDITDLLNAME, BinariesPath) ; if (!LoadEditorDLL (str, false)) use_editors = false ; } } } else use_editors = false; GetHKCU("General", VERSIONVAL, "[unknown]", str, (DWORD) strlen (str)) ; if (debugging) debug_output("Registry records version %s, and we are %s\n", str, POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER) ; if (strcmp (str, POV_RAY_VERSION COMPILER_VER "." PVENGINE_VER) != 0) { // we don't want to set the newVersion flag if the only thing that changed // was the compiler used to generate the binary. in this case we add an // explicit check for the intel, msvc, and watcom versions. if ((s = strstr (str, ".icl")) != NULL) strcpy (s, s + 4) ; else if ((s = strstr (str, ".msvc")) != NULL) strcpy (s, s + 5) ; else if ((s = strstr (str, ".watcom")) != NULL) strcpy (s, s + 7) ; // strip off any trailing digits from the compiler version if (s) while (isdigit (*s)) strcpy (s, s + 1) ; if (strcmp (str, POV_RAY_VERSION "." PVENGINE_VER) != 0) newVersion = true ; } if ((run_count = GetHKCU("General", "RunCount", 0)) == 0 || newVersion) { if (screen_depth < 8) { MessageBox (NULL, "NOTE : POV-Ray for Windows was not designed to run in 16-color mode. " "While the program will operate, it is recommended that you use a minimum " "graphics mode of 800x600x256.", "Warning - running in 16-color mode", MB_ICONEXCLAMATION) ; tile_background = false ; } if (screen_width < 800) { MessageBox (NULL, "NOTE : POV-Ray for Windows was not designed to run at less than 800x600.\n\n" "While the program will operate, it is recommended that you use a minimum " "graphics mode of 800x600x256.", "Warning - running at less than 800x600", MB_ICONEXCLAMATION) ; } } PutHKCU ("General", "RunCount", ++run_count) ; if (screen_depth < 8) tile_background = false ; /* Create the main window */ placement = mainwin_placement ; placement.length = sizeof (WINDOWPLACEMENT) ; w = mainwin_placement.rcNormalPosition.right - mainwin_placement.rcNormalPosition.left ; h = mainwin_placement.rcNormalPosition.bottom - mainwin_placement.rcNormalPosition.top ; if (w <= 128) w = 700 ; if (h <= 128) h = screen_height - 75 ; main_window = CreateWindowEx (0, PovMainWinClass, "POV-Ray for Windows", WS_OVERLAPPEDWINDOW, mainwin_placement.rcNormalPosition.left, mainwin_placement.rcNormalPosition.top, w, h, NULL, NULL, hInst, NULL) ; if (main_window == NULL) { MessageBox (NULL, "ERROR : Could not create main window.", "Critical Error", MB_ICONSTOP) ; cleanup_all () ; return (1) ; } EditSetNotifyBase (main_window, CM_FIRSTEDITNOTIFY) ; if ((StatusWindow = CreateStatusbar (main_window)) == NULL) { MessageBox (main_window, "ERROR : Could not create statusbar", "Critical Error", MB_ICONSTOP) ; cleanup_all () ; return (1) ; } if (tile_background && background_file [1]) { if ((hDIB = LoadDIB (background_file)) != NULL) { hBmpBackground = DIBToBitmap (hDIB, hPalApp) ; DeleteObject (hDIB) ; GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ; background_width = bm.bmWidth ; background_height = bm.bmHeight ; } else { PovMessageBox ("Failed to load bitmap file", "Error") ; strcpy (background_file, "0") ; } } if (tile_background && hBmpBackground == NULL && screen_depth >= 8) { if (isdigit (background_file [0]) && background_file [1] == '\0') id = background_file [0] - '0' ; SendMessage (main_window, WM_COMMAND, CM_BACKGROUNDSTD + id, 1L) ; } if ((hBMP = LoadBitmap (hInstance, MAKEINTRESOURCE (BMP_ICON))) != NULL) hBmpIcon = hBMP ; if (lastBitmapPath [0] == '\0') sprintf (lastBitmapPath, "%sTiles", BinariesPath) ; if (lastRenderPath [0] == '\0') { sprintf (lastRenderPath, "%sScenes\\Advanced", DocumentsPath) ; strcpy (lastRenderName, "Biscuit.pov") ; } if (lastQueuePath [0] == '\0') sprintf (lastQueuePath, "%sScenes", DocumentsPath) ; GetHKCU("Editor", "LastPath", "", str, sizeof (str)) ; validatePath (lastRenderPath) ; if (str [0] == '\0') PutHKCU("Editor", "LastPath", lastRenderPath) ; if (lastRenderName [0] != '\0' && !demo_mode && !benchmark_mode) joinPath (source_file_name, lastRenderPath, lastRenderName) ; if (use_editors) if ((tab_window = InitialiseEditor (main_window, StatusWindow, BinariesPath, DocumentsPath)) == NULL) use_editors = false ; message_window = CreateWindowEx (WS_EX_CLIENTEDGE, PovMessageWinClass, "", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 0, 0, use_editors ? tab_window : main_window, NULL, hInst, NULL) ; if (message_window == NULL) { MessageBox (NULL, "ERROR : Could not create message window.", "Critical Error", MB_ICONSTOP) ; cleanup_all () ; return (1) ; } if (initialise_message_display ()) { cleanup_all () ; return (1) ; } EditSetMessageWindow (message_window) ; if ((rebar_window = create_rebar (main_window)) == NULL) { MessageBox (main_window, "ERROR : Could not create internal window #1", "Critical Error", MB_ICONSTOP) ; cleanup_all () ; return (1) ; } if ((toolbar_window = create_toolbar (rebar_window)) == NULL) { MessageBox (main_window, "ERROR : Could not create internal window #2", "Critical Error", MB_ICONSTOP) ; cleanup_all () ; return (1) ; } if (!use_toolbar) { ShowWindow (rebar_window, SW_HIDE) ; toolheight = 0 ; } extract_ini_sections_ex (SecondaryRenderIniFileName, toolbar_combobox) ; SendMessage (toolbar_combobox, CB_ADDSTRING, 0, (LPARAM) "More Resolutions ...") ; tb_combo_sel = select_combo_item_ex (toolbar_combobox, SecondaryRenderIniFileSection) ; if (tb_combo_sel == -1) tb_combo_sel = 0 ; setup_menus (use_editors) ; build_main_menu (hMainMenu, use_editors) ; set_toggles () ; if (!use_editors) { SendMessage (toolbar_window, TB_ENABLEBUTTON, CM_FILENEW, 0L) ; SendMessage (toolbar_window, TB_ENABLEBUTTON, CM_FILEOPEN, 0L) ; SendMessage (toolbar_window, TB_ENABLEBUTTON, CM_FILESAVE, 0L) ; } else EditRestoreState (!NoRestore) ; if (editors_enabled) PVCheckMenuItem (CM_USEEDITOR, MF_CHECKED) ; PVEnableMenuItem (CM_RENDERHIDE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ; PVEnableMenuItem (CM_RENDERACTIVE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ; PVCheckMenuItem (on_completion, MF_CHECKED) ; PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ; PVEnableMenuItem (CM_RENDERSLEEP, MF_GRAYED) ; PVCheckMenuRadioItem (CM_RENDERPRIORITY_BACKGROUND, CM_RENDERPRIORITY_HIGH, render_priority) ; PVCheckMenuItem (drop_to_editor ? CM_DROPEDITOR : CM_DROPRENDERER, MF_CHECKED) ; PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ; PVEnableMenuItem (CM_RENDERCLOSE, MF_GRAYED) ; PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, tile_background ? "&Select Plain Background" : "&Select Tiled Background") ; PVCheckMenuRadioItem (CM_DUTYCYCLE_10, CM_DUTYCYCLE_100, CM_DUTYCYCLE_10 + Duty_Cycle) ; if (screen_depth < 8) { PVEnableMenuItem (CM_TILEDBACKGROUND, MF_GRAYED) ; PVEnableMenuItem (CM_BACKGROUNDBITMAP, MF_GRAYED) ; for (i = 0 ; i < 16 ; i++) PVEnableMenuItem (CM_BACKGROUNDSTD + i, MF_GRAYED) ; } set_newuser_menus (hide_newuser_help) ; if (ThreadCount == 1) { PVDeleteMenuItem (CM_BENCHMARK) ; PVModifyMenu (CM_BENCHMARKONETHREAD, MF_STRING, CM_BENCHMARKONETHREAD, "Run &Benchmark") ; } switch (placement.showCmd) { case SW_SHOWNORMAL : show_state = SW_SHOW ; break ; case SW_SHOWMINIMIZED : // show_state = SW_SHOWMINNOACTIVE ; show_state = SW_SHOW ; break ; case SW_SHOWMAXIMIZED : show_state = SW_SHOWMAXIMIZED ; break ; default : show_state = SW_SHOW ; break ; } if (ListenMode) show_state = SW_HIDE ; placement.showCmd = show_state ; placement.flags = (placement.ptMinPosition.x == -1 && placement.ptMinPosition.y == -1) ? 0 : WPF_SETMINPOSITION ; if (placement.rcNormalPosition.right <= 0 || placement.rcNormalPosition.bottom <= 0) { placement.rcNormalPosition.right = placement.rcNormalPosition.left + message_xchar * 115 ; placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + message_ychar * 75 ; } placement.length = sizeof (WINDOWPLACEMENT) ; SetWindowPlacement (main_window, &placement) ; if (show_state != SW_SHOWMAXIMIZED) FitWindowInWindow (NULL, main_window) ; if ((timer_id = SetTimer (main_window, 1, 250, NULL)) != 0) DragAcceptFiles (main_window, true) ; // only needed for earlier versions of common control DLL ... if (use_toolbar && !IsComCtl5) { hDC = GetDC (toolbar_window) ; GetClientRect (toolbar_window, &rect) ; FillRect (hDC, &rect, (HBRUSH) GetStockObject (LTGRAY_BRUSH)) ; ReleaseDC (toolbar_window, hDC) ; } // fixes visual glitch with ComCtl6 if (use_toolbar && IsComCtl6) { hDC = GetDC (main_window) ; GetClientRect (rebar_window, &rect) ; FillRect (hDC, &rect, (HBRUSH) GetStockObject (LTGRAY_BRUSH)) ; ReleaseDC (main_window, hDC) ; } if (ExtensionsEnabled) LoadGUIExtensions () ; if (renderwin_left < 0 || renderwin_left > screen_width - 32 || renderwin_top < 0 || renderwin_top > screen_height - 32) { MONITORINFO mi; mi.cbSize = sizeof(MONITORINFO); if (GetMonitorInfo(MonitorFromWindow(main_window, MONITOR_DEFAULTTOPRIMARY), &mi)) { // apply the principle of least astonishment: otherwise the render window could // turn up on a monitor which may be switched off or otherwise not being paid // attention to, with no (obvious) way for the user to move it. we make one // exception: if the render window is placed on the primary display, we won't // move it to the current display, since it's assumed the primary display is // always going to be visible. if (renderwin_left < mi.rcWork.left) renderwin_left = mi.rcWork.left ; if (renderwin_top < mi.rcWork.top) renderwin_top = mi.rcWork.top ; if (renderwin_left > mi.rcWork.right - 128) renderwin_left = mi.rcWork.right - 128 ; if (renderwin_top > mi.rcWork.bottom - 128) renderwin_top = mi.rcWork.bottom - 128 ; } } buffer_message (mIDE, "Persistence of Vision Raytracer(tm) for Windows.\n") ; buffer_message (mIDE, "POV-Ray for Windows is part of the POV-Ray(tm) suite of programs.\n") ; buffer_message (mIDE, " This is version " POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER ".\n") ; buffer_message (mIDE, "Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.\n") ; buffer_message (mIDE, " " DISCLAIMER_MESSAGE_1 "\n") ; buffer_message (mIDE, " " DISCLAIMER_MESSAGE_2 "\n") ; buffer_message (mIDE, " Select Help|About (or press Alt+B) for more information and a copy of the license.\n") ; buffer_message (mIDE, "The terms POV-Ray and Persistence of Vision Raytracer are trademarks of\n") ; buffer_message (mIDE, " Persistence of Vision Raytracer Pty. Ltd.\n") ; if (render_bitmap_depth != 24) { buffer_message (mIDE, "\n") ; buffer_message (mIDE, renderwin_8bits ? "Using 8-bit dithered internal bitmap (menu setting)\n" : "Using 8-bit dithered internal bitmap (4 or 8-bit video mode)\n") ; } buffer_message (mIDE, "\n") ; strcpy (tool_commands [0], "notepad.exe \"%ipovray.ini\"") ; #if POV_RAY_IS_OFFICIAL != 1 WIN_PrintOtherCredits () ; buffer_message (mIDE, "This unofficial build is derived from the POV-Ray for Windows source code.\n") ; #endif buffer_message (mDivider, "\n") ; #if defined(USE_AVX_FMA4_FOR_NOISE) // technically we should ask the backend what it's using, but given this is not a remoted version // of POVWIN, we just call the test here. if (CPU_FMA4_DETECT() != 0) { buffer_message (mIDE, "FMA4 instruction support detected: using FMA4-optimized noise functions.\n") ; buffer_message (mDivider, "\n") ; } #endif load_tool_menu (ToolIniFileName) ; if (GetHKCU("FileQueue", "ReloadOnStartup", 0)) { queued_file_count = GetHKCU("FileQueue", "QueueCount", 0) ; if (queued_file_count > MAX_QUEUE) queued_file_count = MAX_QUEUE ; for (i = 0 ; i < queued_file_count ; i++) { sprintf (str, "QueuedFile%d", i) ; GetHKCU("FileQueue", str, "", queued_files [i], sizeof (queued_files [0])) ; } if (queued_file_count != 0) message_printf ("Loaded %d entr%s into file queue\n", queued_file_count, queued_file_count == 1 ? "y" : "ies") ; update_queue_status (false) ; } if (have_cpu_info) message_printf("Detected %u CPU%s providing %u physical core%s and %u logical one%s.\n", NumPhysicalCPUs, NumPhysicalCPUs > 1 ? "'s" : "", NumCPUCores, NumCPUCores > 1 ? "s" : "", NumLogicalCPUs, NumLogicalCPUs > 1 ? "s" : ""); buffer_message (mDivider, "\n") ; if (GetHKCU("General", "CheckColorsInc", 1) == 1) { sprintf (str, "%sinclude\\colors.inc", DocumentsPath) ; if (stat (str, &statbuf) != 0) { char temp[2048]; sprintf(temp, "WARNING : Cannot find COLORS.INC in expected location:\n\n%s\n\n" "This file is important for the normal operation of POV-Ray. It is included " "with the POV-Ray for Windows distribution. If you did not install using the " "correct installation procedure please attend to this before running POV-Ray " "for Windows.\n\nIf, however, you have chosen to change the location of this file " "or do not need it, you may ignore this warning as long as you have updated " "POVRAY.INI to the new path, or do not use any standard scenes that require it.\n\n" "Do you want to see this warning again ?", str); if (MessageBox (NULL, temp, "Warning - COLORS.INC is missing", MB_ICONEXCLAMATION | MB_YESNO) == IDNO) PutHKCU ("General", "CheckColorsInc", 0U) ; } } if (demo_mode) { message_printf ("Running demonstration\n") ; argc = 0 ; handle_main_command (CM_DEMO, 0) ; } if (benchmark_mode) { message_printf ("Running benchmark\n") ; argc = 0 ; handle_main_command (CM_BENCHMARK, 0) ; } SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ; if (debugging) { message_printf ("My window handle is %p\n", main_window) ; if (HaveWin95OrLater ()) message_printf ("Win95 or later detected\n") ; if (HaveWin98OrLater ()) message_printf ("Win98 or later detected\n") ; if (HaveNT4OrLater ()) message_printf ("WinNT or later detected\n") ; if (HaveWin2kOrLater ()) message_printf ("Win2k or later detected\n") ; if (HaveWinXPOrLater ()) message_printf ("WinXP or later detected\n") ; if (IsW95UserInterface) message_printf ("Windows 95 user interface flag is set\n") ; } for (i = 0 ; i < EditFileCount ; i++) { if (EditGetFlags () & EDIT_CAN_OPEN) EditOpenFile (EditFiles [i]) ; free (EditFiles [i]) ; EditFiles [i] = NULL ; } EditFileCount = 0 ; if (newVersion || FreshInstall) { if (EditGetFlags() & EDIT_CAN_OPEN) { sprintf(str, "%srevision.txt", DocumentsPath); if (fileExists(str)) EditOpenFile(str) ; if (EditGetFlags() & EDIT_CAN_OPEN) { sprintf(str, "%schanges.txt", DocumentsPath); if (fileExists(str)) EditOpenFile(str) ; } } // TODO: remove this after a few betas tile_background = false; text_colours[0] = RGB (255, 255, 255); text_colours[1] = RGB (255, 255, 0); text_colours[2] = RGB (0, 255, 255); background_colour = RGB (31, 0, 63); } if (run_count > 1 && !demo_mode && !benchmark_mode) { n = GetHKCU("General", "ItsAboutTime", 0) ; if (_time32 (NULL) > n /*|| newVersion*/) { ShowAboutBox () ; PutHKCU ("General", "ItsAboutTime", n ? _time32 (NULL) + DAYS(14) : _time32 (NULL) + DAYS(1)) ; } } #if POV_RAY_IS_OFFICIAL == 1 DoUpdateCheck () ; #endif // automatically call the rendering engine if there were any parameters on the command line if (!rendering && (argc > 1 || render_requested)) { if (render_requested) { wrapped_printf ("Requested render file is '%s'", requested_render_file) ; strcpy (source_file_name, requested_render_file) ; } if (argc > 1) wrapped_printf ("Calling rendering engine with parameters '%s'", command_line) ; start_rendering (!render_requested) ; } if (homeInferred) message_printf ("Warning: running with inferred home path due to missing registry entry.\n\n") ; #ifdef _DEBUG if (sizeof (ExternalVarStruct) != 0x9350) PovMessageBox ("Compatibility problem - ExternalVarStruct has changed size", "Warning") ; #endif if (ListenMode) handle_main_command (CM_SHOWMAINWINDOW, 0) ; if (debugging) debug_output("Entering GetMessage loop\n") ; try { while (!exit_loop) { // since the render thread can really slow things down for the UI (this becomes // a problem if the user sets the render priority to high and then finds the // UI unresponsive when attempting to change it back), we only sleep here if // there's no events in the queue that we feel the need to handle immediately. // (if one of these messages turns up while we're sleeping we'll get woken). // N.B. longer wait times resulted in complaints from some testers, apparently // there's some machines out there that don't exit the wait for some types of // input. MsgWaitForMultipleObjects (0, NULL, FALSE, 10, QS_ALLINPUT) ; // MsgWaitForMultipleObjects (0, NULL, FALSE, 10, QS_HOTKEY | QS_KEY | QS_MOUSEBUTTON) ; if (StartInsertRender) { if (!rendering) start_rendering (false) ; StartInsertRender = false ; } if (quit != 0) if (quit + 15 < time (NULL)) break ; ProcessSession(); while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { exit_loop = true ; break ; } // we have to disable all these calls because HTML Help has a bug (on some // platforms - I can't work out the exact conditions that trigger it) which // will cause the cursor to flash between normal and the busy state (normally // an hourglass) several times a second, continually (even if help isn't open). // See job #124. #ifdef HTMLHELP_FIXED if (HtmlHelp (NULL, NULL, HH_PRETRANSLATEMESSAGE, (DWORD) &msg)) continue ; #else // we need to pass on these messages, otherwise help navigation messages // will go to us instead of the help window if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN) if (!IsChild (main_window, msg.hwnd)) if (HtmlHelp (NULL, NULL, HH_PRETRANSLATEMESSAGE, (DWORD_PTR) &msg)) continue ; #endif if (!TranslateAccelerator (main_window, hAccelerators, &msg)) { TranslateMessage (&msg) ; if (msg.hwnd == toolbar_cmdline) { if (msg.message == WM_CHAR) if (handle_toolbar_cmdline (msg.wParam, msg.lParam)) continue ; } DispatchMessage (&msg) ; } ProcessSession(); } } } catch(std::exception& e) { sprintf (str, "Caught exception: %s", e.what()) ; if (debugging) debug_output ("%s\n", str) ; MessageBox (NULL, str, "POV-Ray Critical Error", MB_ICONSTOP) ; exit(1); } if (debugging) debug_output ("Dropping out of message loop\n") ; try { DeleteFrontend(); cleanup_all () ; } catch(pov_base::Exception& e) { // don't do much about POV exceptions here: often, they will relate to the front end // not cleaning up fast enough (i.e. due to a lot of memory de-allocation) if (debugging) debug_output ("Caught exception: %s\n", e.what()) ; } catch(std::exception& e) { sprintf (str, "Caught exception: %s", e.what()) ; if (debugging) debug_output ("%s\n", str) ; MessageBox (NULL, str, "POV-Ray Critical Error", MB_ICONSTOP) ; } _fcloseall () ; #ifndef _WIN64 // win64 - get exception during HH_UNINITIALIZE HtmlHelp (NULL, NULL, HH_UNINITIALIZE, (DWORD) help_cookie) ; #endif if (debugging) debug_output ("exiting WinMain()\n") ; return (0) ; }