0025748: Parallel version of progress indicator
[occt.git] / src / Draw / Draw.cxx
1 // Created on: 1993-08-13
2 // Created by: Bruno DUMORTIER
3 // Copyright (c) 1993-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <Draw.hxx>
19 #include <Draw_Appli.hxx>
20 #include <Draw_Drawable3D.hxx>
21 #include <Draw_Failure.hxx>
22 #include <Draw_Interpretor.hxx>
23 #include <Draw_ProgressIndicator.hxx>
24 #include <Draw_Window.hxx>
25 #include <gp_Pnt2d.hxx>
26 #include <Message.hxx>
27 #include <Message_Messenger.hxx>
28 #include <Message_PrinterOStream.hxx>
29 #include <OSD.hxx>
30 #include <OSD_Environment.hxx>
31 #include <OSD_File.hxx>
32 #include <OSD_Process.hxx>
33 #include <OSD_SharedLibrary.hxx>
34 #include <OSD_Timer.hxx>
35 #include <Plugin_MapOfFunctions.hxx>
36 #include <Resource_Manager.hxx>
37 #include <Standard_ErrorHandler.hxx>
38 #include <Standard_Stream.hxx>
39 #include <Standard_Version.hxx>
40 #include <TCollection_AsciiString.hxx>
41
42 #include <tcl.h>
43
44 #include <Standard_WarningDisableFunctionCast.hxx>
45
46 // on MSVC, use #pragma to define name of the Tcl library to link with,
47 // depending on Tcl version number
48 #ifdef _MSC_VER
49 // two helper macros are needed to convert version number macro to string literal
50 #define STRINGIZE1(a) #a
51 #define STRINGIZE2(a) STRINGIZE1(a)
52 #pragma comment (lib, "tcl" STRINGIZE2(TCL_MAJOR_VERSION) STRINGIZE2(TCL_MINOR_VERSION) ".lib")
53 #pragma comment (lib, "tk"  STRINGIZE2(TCL_MAJOR_VERSION) STRINGIZE2(TCL_MINOR_VERSION) ".lib")
54 #undef STRINGIZE2
55 #undef STRINGIZE1
56 #endif
57
58 extern Standard_Boolean Draw_ParseFailed;
59
60 Standard_EXPORT Draw_Viewer dout;
61 Standard_EXPORT Draw_Interpretor theCommands;
62 Standard_EXPORT Standard_Boolean Draw_Batch = Standard_False;
63 Standard_EXPORT Standard_Boolean Draw_Spying = Standard_False;
64 Standard_EXPORT Standard_Boolean Draw_Chrono = Standard_False;
65 Standard_EXPORT Standard_Boolean Draw_VirtualWindows = Standard_False;
66 Standard_EXPORT Standard_Boolean ErrorMessages = Standard_True;
67
68 static const char* ColorNames[MAXCOLOR] = {
69   "White","Red","Green","Blue","Cyan","Gold","Magenta",
70   "Maroon","Orange","Pink","Salmon","Violet","Yellow","Khaki","Coral"
71   };
72
73 std::filebuf Draw_Spyfile;
74
75 static std::ostream spystream(&Draw_Spyfile);
76
77 static Handle(Draw_ProgressIndicator) global_Progress = NULL;
78
79 Standard_EXPORT Standard_Boolean Draw_Interprete(const char* command);
80 // true if complete command
81
82 // *******************************************************************
83 // read an init file
84 // *******************************************************************
85
86 static void interpreteTclCommand (const TCollection_AsciiString& theCmd)
87 {
88 #ifdef _WIN32
89   if (!Draw_Batch)
90   {
91     try
92     {
93       while (console_semaphore == HAS_CONSOLE_COMMAND)
94       {
95         Sleep(10);
96       }
97       {
98         TCollection_ExtendedString aCmdWide (theCmd);
99         wcscpy_s (console_command, aCmdWide.ToWideString());
100       }
101       console_semaphore = HAS_CONSOLE_COMMAND;
102       while (console_semaphore == HAS_CONSOLE_COMMAND)
103       {
104         Sleep(10);
105       }
106     }
107     catch (...)
108     {
109       std::cout << "Error while reading a script file.\n";
110       ExitProcess(0);
111     }
112   }
113   else
114 #endif
115   {
116     Draw_Interprete (theCmd.ToCString());
117   }
118 }
119
120 static void ReadInitFile (const TCollection_AsciiString& theFileName)
121 {
122   TCollection_AsciiString aCmd = theFileName;
123 #ifdef _WIN32
124   aCmd.ChangeAll ('\\', '/');
125 #endif
126   aCmd = TCollection_AsciiString ("source -encoding utf-8 \"") + aCmd + "\"";
127   interpreteTclCommand (aCmd);
128 }
129
130 //! Define environment variable available from Tcl and OCCT.
131 static void setOcctTclEnv (const TCollection_AsciiString& theName,
132                            TCollection_AsciiString& thePath)
133 {
134   if (thePath.IsEmpty())
135   {
136     return;
137   }
138
139   thePath.ChangeAll ('\\', '/');
140   OSD_Environment aRedPathEnv (theName);
141   aRedPathEnv.SetValue (thePath);
142   aRedPathEnv.Build();
143
144   const TCollection_AsciiString aPutEnv = theName + "=" + thePath;
145   Tcl_PutEnv (aPutEnv.ToCString());
146 }
147
148 //! Look for resource within standard installation layouts relative to executable location.
149 //!
150 //! Bin (INSTALL_DIR_BIN):
151 //!  - Windows: <prefix>/win64/vc10/bin(d)
152 //!  - Unix:    <prefix>/bin
153 //! Resources (INSTALL_DIR_RESOURCE):
154 //!  - Windows: <prefix>/src
155 //!  - Unix:    <prefix>/share/opencascade-7.0.0/resources
156 //! Samples (INSTALL_DIR_SAMPLES):
157 //!  - Windows: <prefix>/samples
158 //!  - Unix:    <prefix>/share/opencascade-7.0.0/samples
159 //! Tests (INSTALL_DIR_TESTS):
160 //!  - Windows: <prefix>/tests
161 //!  - Unix:    <prefix>/share/opencascade-7.0.0/tests
162 //!
163 //! @param theCasRoot  [out] found CASROOT location (e.g. installation folder)
164 //! @param theResRoot  [out] found resources root location
165 //! @param theResName   [in] resource to find ("resources", "samples", etc.)
166 //! @param theProbeFile [in] file to probe within resources location (e.g. "DrawResources/DrawDefault" within "resources")
167 static bool searchResources (TCollection_AsciiString& theCasRoot,
168                              TCollection_AsciiString& theResRoot,
169                              const TCollection_AsciiString& theResName,
170                              const TCollection_AsciiString& theProbeFile)
171 {
172   const TCollection_AsciiString aResLayouts[] =
173   {
174     TCollection_AsciiString("/share/opencascade-" OCC_VERSION_STRING_EXT "/") + theResName,
175     TCollection_AsciiString("/share/opencascade-" OCC_VERSION_COMPLETE "/") + theResName,
176     TCollection_AsciiString("/share/opencascade-" OCC_VERSION_STRING "/") + theResName,
177     TCollection_AsciiString("/share/opencascade/") + theResName,
178     TCollection_AsciiString("/share/occt-" OCC_VERSION_STRING_EXT "/") + theResName,
179     TCollection_AsciiString("/share/occt-" OCC_VERSION_COMPLETE "/") + theResName,
180     TCollection_AsciiString("/share/occt-" OCC_VERSION_STRING "/") + theResName,
181     TCollection_AsciiString("/share/occt/") + theResName,
182     TCollection_AsciiString("/") + theResName,
183     TCollection_AsciiString("/share/opencascade"),
184     TCollection_AsciiString("/share/occt"),
185     TCollection_AsciiString("/share"),
186     TCollection_AsciiString("/src"),
187     TCollection_AsciiString("")
188   };
189
190   const TCollection_AsciiString anExeDir (OSD_Process::ExecutableFolder());
191   for (Standard_Integer aLayIter = 0;; ++aLayIter)
192   {
193     const TCollection_AsciiString& aResLayout = aResLayouts[aLayIter];
194     const TCollection_AsciiString  aProbeFile = aResLayout + "/" + theProbeFile;
195     if (OSD_File (anExeDir + aProbeFile).Exists())
196     {
197       theCasRoot = anExeDir;
198       theResRoot = theCasRoot + aResLayout;
199       return true;
200     }
201     // <prefix>/bin(d)
202     else if (OSD_File (anExeDir + "../" + aProbeFile).Exists())
203     {
204       theCasRoot = anExeDir + "..";
205       theResRoot = theCasRoot + aResLayout;
206       return true;
207     }
208     // <prefix>/gcc/bin(d)
209     else if (OSD_File (anExeDir + "../../" + aProbeFile).Exists())
210     {
211       theCasRoot = anExeDir + "../..";
212       theResRoot = theCasRoot + aResLayout;
213       return true;
214     }
215     // <prefix>/win64/vc10/bin(d)
216     else if (OSD_File (anExeDir + "../../../" + aProbeFile).Exists())
217     {
218       theCasRoot = anExeDir + "../../..";
219       theResRoot = theCasRoot + aResLayout;
220       return true;
221     }
222
223     if (aResLayout.IsEmpty())
224     {
225       return false;
226     }
227   }
228 }
229
230 //=======================================================================
231 //function : GetInterpretor
232 //purpose  :
233 //=======================================================================
234 Draw_Interpretor& Draw::GetInterpretor()
235 {
236   return theCommands;
237 }
238
239 //=======================================================================
240 //function :
241 //purpose  : Set/Get Progress Indicator
242 //=======================================================================
243 void Draw::SetProgressBar(const Handle(Draw_ProgressIndicator)& theProgress)
244 {
245   global_Progress = theProgress;
246 }
247
248 Handle(Draw_ProgressIndicator) Draw::GetProgressBar()
249 {
250   return global_Progress;
251 }
252
253 #ifndef _WIN32
254 /*--------------------------------------------------------*\
255 |  exitProc: finalization handler for Tcl/Tk thread. Forces parent process to die
256 \*--------------------------------------------------------*/
257 void exitProc(ClientData /*dc*/)
258 {
259   if (!Draw_Batch) {
260     for (Standard_Integer id = 0; id < MAXVIEW; id++)
261       dout.DeleteView(id);
262   }
263 }
264 #endif
265
266 // *******************************************************************
267 // main
268 // *******************************************************************
269 #ifdef _WIN32
270 Standard_EXPORT void Draw_Appli(HINSTANCE hInst, HINSTANCE hPrevInst, int nShow, int argc, wchar_t** argv, const FDraw_InitAppli Draw_InitAppli)
271 #else
272 void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli)
273 #endif
274 {
275
276 // prepend extra DLL search path to override system libraries like opengl32.dll
277 #ifdef _WIN32
278   OSD_Environment aUserDllEnv ("CSF_UserDllPath");
279   const TCollection_ExtendedString aUserDllPath (aUserDllEnv.Value());
280   if (!aUserDllPath.IsEmpty())
281   {
282     // This function available since Win XP SP1 #if (_WIN32_WINNT >= 0x0502).
283     // We retrieve dynamically here (kernel32 should be always preloaded).
284     typedef BOOL (WINAPI *SetDllDirectoryW_t)(const wchar_t* thePathName);
285     HMODULE aKern32Module = GetModuleHandleW (L"kernel32");
286     SetDllDirectoryW_t aFunc = (aKern32Module != NULL)
287                              ? (SetDllDirectoryW_t )GetProcAddress (aKern32Module, "SetDllDirectoryW") : NULL;
288     if (aFunc != NULL)
289     {
290       aFunc (aUserDllPath.ToWideString());
291     }
292     else
293     {
294       //std::cerr << "SetDllDirectoryW() is not available on this system!\n";
295     }
296     if (aKern32Module != NULL)
297     {
298       FreeLibrary (aKern32Module);
299     }
300   }
301 #endif
302
303   // *****************************************************************
304   // analyze arguments
305   // *****************************************************************
306   Draw_Batch = Standard_False;
307   TCollection_AsciiString aRunFile, aCommand;
308   Standard_Boolean isInteractiveForced = Standard_False;
309
310   // parse command line
311   for (int anArgIter = 1; anArgIter < argc; ++anArgIter)
312   {
313     TCollection_AsciiString anArg (argv[anArgIter]);
314     anArg.LowerCase();
315     if (anArg == "-h"
316      || anArg == "--help")
317     {
318       std::cout << "Open CASCADE " << OCC_VERSION_STRING_EXT << " DRAW Test Harness\n\n";
319       std::cout << "Options:\n";
320       std::cout << "  -b: batch mode (no GUI, no viewers)\n";
321       std::cout << "  -v: no GUI, use virtual (off-screen) windows for viewers\n";
322       std::cout << "  -i: interactive mode\n";
323       std::cout << "  -f file: execute script from file\n";
324       std::cout << "  -c command args...: execute command (with optional arguments)\n\n";
325       std::cout << "Options -b, -v, and -i are mutually exclusive.\n";
326       std::cout << "If -c or -f are given, -v is default; otherwise default is -i.\n";
327       std::cout << "Options -c and -f are alternatives and should be at the end \n";
328       std::cout << "of the command line.\n";
329       std::cout << "Option -c can accept set of commands separated by ';'.\n";
330       return;
331     }
332     else if (anArg == "-b")
333     {
334       Draw_Batch = Standard_True;
335     }
336     else if (anArg == "-v")
337     {
338       // force virtual windows
339       Draw_VirtualWindows = Standard_True;
340     }
341     else if (anArg == "-i")
342     {
343       // force interactive
344       Draw_VirtualWindows = Standard_False;
345       isInteractiveForced = Standard_True;
346     }
347     else if (anArg == "-f") // -f option should be LAST!
348     {
349       Draw_VirtualWindows = !isInteractiveForced;
350       if (++anArgIter < argc)
351       {
352         aRunFile = TCollection_AsciiString (argv[anArgIter]);
353       }
354       break;
355     }
356     else if (anArg == "-c") // -c option should be LAST!
357     {
358       Draw_VirtualWindows = !isInteractiveForced;
359       if (++anArgIter < argc)
360       {
361         aCommand = TCollection_AsciiString (argv[anArgIter]);
362       }
363       while (++anArgIter < argc)
364       {
365         aCommand.AssignCat (" ");
366         aCommand.AssignCat (argv[anArgIter]);
367       }
368       break;
369     }
370     else
371     {
372       std::cout << "Error: unsupported option " << TCollection_AsciiString (argv[anArgIter]) << "\n";
373     }
374   }
375
376   // *****************************************************************
377   // set signals
378   // *****************************************************************
379   OSD::SetSignal(Standard_False);
380
381 #ifdef _WIN32
382   // in interactive mode, force Windows to report dll loading problems interactively
383   if ( ! Draw_VirtualWindows && ! Draw_Batch )
384     ::SetErrorMode (0);
385 #endif
386
387   // *****************************************************************
388   // init X window and create display
389   // *****************************************************************
390 #ifdef _WIN32
391   HWND hWnd = NULL;
392 #endif
393
394   if (!Draw_Batch)
395 #ifdef _WIN32
396     Draw_Batch=!Init_Appli(hInst, hPrevInst, nShow, hWnd);
397 #else
398     Draw_Batch=!Init_Appli();
399 #endif
400   else
401   {
402     std::cout << "DRAW is running in batch mode" << std::endl;
403     theCommands.Init();
404     Tcl_Init(theCommands.Interp());
405   }
406
407   if (! Draw_Batch)
408   {
409     // Default colors
410     for (int i = 0; i < MAXCOLOR; ++i)
411     {
412       if (!dout.DefineColor (i, ColorNames[i]))
413       {
414         std::cout <<"Could not allocate default color " << ColorNames[i] << std::endl;
415       }
416     }
417   }
418
419   // *****************************************************************
420   // set maximum precision for cout
421   // *****************************************************************
422   std::cout.precision(15);
423
424   // *****************************************************************
425   // standard commands
426   // *****************************************************************
427   Draw::BasicCommands(theCommands);
428   Draw::VariableCommands(theCommands);
429   Draw::UnitCommands(theCommands);
430   if (!Draw_Batch) Draw::GraphicCommands(theCommands);
431
432   // *****************************************************************
433   // user commands
434   // *****************************************************************
435   Draw_InitAppli(theCommands);
436
437 #ifndef _WIN32
438   Tcl_CreateExitHandler(exitProc, 0);
439 #endif
440
441   // *****************************************************************
442   // read init files
443   // *****************************************************************
444   // default
445   const TCollection_AsciiString aDrawDef (OSD_Environment ("DRAWDEFAULT").Value());
446   if (!aDrawDef.IsEmpty())
447   {
448     ReadInitFile (aDrawDef);
449   }
450   else
451   {
452     TCollection_AsciiString aDrawHome;
453     TCollection_AsciiString aCasRoot (OSD_Environment ("CASROOT").Value());
454     if (!aCasRoot.IsEmpty())
455     {
456       aDrawHome = aCasRoot + "/src/DrawResources";
457     }
458     else
459     {
460       // search for relative locations within standard development environment
461       TCollection_AsciiString aResPath;
462       if (searchResources (aCasRoot, aResPath, "resources", "DrawResources/DrawDefault"))
463       {
464         aDrawHome = aResPath + "/DrawResources";
465         setOcctTclEnv ("CASROOT",  aCasRoot);
466         setOcctTclEnv ("DRAWHOME", aDrawHome);
467         setOcctTclEnv ("CSF_OCCTResourcePath", aResPath);
468       }
469
470       TCollection_AsciiString aSamplesPath;
471       if (OSD_Environment ("CSF_OCCTSamplesPath").Value().IsEmpty()
472        && searchResources (aCasRoot, aSamplesPath, "samples", "tcl/Readme.txt"))
473       {
474         setOcctTclEnv ("CSF_OCCTSamplesPath", aSamplesPath);
475       }
476
477       TCollection_AsciiString aTestsPath;
478       if (OSD_Environment ("CSF_TestScriptsPath").Value().IsEmpty()
479        && searchResources (aCasRoot, aTestsPath, "tests", "parse.rules"))
480       {
481         setOcctTclEnv ("CSF_TestScriptsPath", aTestsPath);
482       }
483     }
484
485     if (!aDrawHome.IsEmpty())
486     {
487       const TCollection_AsciiString aDefStr = aDrawHome + "/DrawDefault";
488       ReadInitFile (aDefStr);
489     }
490     else
491     {
492 #ifdef _WIN32
493       ReadInitFile ("ddefault");
494 #else
495       std::cout << " the CASROOT variable is mandatory to Run OpenCascade "<< std::endl;
496       std::cout << "No default file" << std::endl;
497 #endif
498     }
499   }
500
501   // read commands from file
502   if (!aRunFile.IsEmpty())
503   {
504     if (!isInteractiveForced)
505     {
506       // disable console messages colorization to avoid spoiling log with color codes
507       theCommands.SetToColorize (Standard_False);
508     }
509     ReadInitFile (aRunFile);
510     // provide a clean exit, this is useful for some analysis tools
511     if ( ! isInteractiveForced )
512 #ifndef _WIN32
513       return;
514 #else
515       ExitProcess(0);
516 #endif
517   }
518
519   // execute command from command line
520   if (!aCommand.IsEmpty())
521   {
522 #ifdef _WIN32
523     if (!Draw_Batch)
524     {
525       // on Windows except batch mode, commands are executed in separate thread
526       while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
527       TCollection_ExtendedString aCmdWide(aCommand);
528       wcscpy_s(console_command, aCmdWide.ToWideString());
529       console_semaphore = HAS_CONSOLE_COMMAND;
530       while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
531     }
532     else
533 #endif
534     Draw_Interprete (aCommand.ToCString()); // Linux and Windows batch mode
535     // provide a clean exit, this is useful for some analysis tools
536     if ( ! isInteractiveForced )
537 #ifndef _WIN32
538       return;
539 #else
540       ExitProcess(0);
541 #endif
542   }
543
544   // *****************************************************************
545   // X loop
546   // *****************************************************************
547   if (! Draw_Batch) {
548 #ifdef _WIN32
549     Run_Appli(hWnd);
550 #else
551     Run_Appli(Draw_Interprete);
552 #endif
553   }
554   else
555   {
556     const int MAXCMD = 2048;
557     char cmd[MAXCMD];
558     for (int ncmd = 1;; ++ncmd)
559     {
560       std::cout << "Draw[" << ncmd << "]> ";
561       if (std::cin.getline (cmd, MAXCMD).fail())
562       {
563         break;
564       }
565       Draw_Interprete(cmd);
566     }
567   }
568 #ifdef _WIN32
569   // Destruction de l'application
570   Destroy_Appli(hInst);
571 #endif
572 }
573 //#endif
574
575 // User functions called before and after each command
576 void (*Draw_BeforeCommand)() = NULL;
577 void (*Draw_AfterCommand)(Standard_Integer) = NULL;
578
579 Standard_Boolean Draw_Interprete(const char* com)
580 {
581
582   static Standard_Boolean first = Standard_True;
583   static Tcl_DString command;
584
585   if (first) {
586     first = Standard_False;
587     Tcl_DStringInit(&command);
588   }
589
590 #ifdef _WIN32
591   // string is already converted into UTF-8
592   Tcl_DStringAppend(&command, com, -1);
593 #elif ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
594   // OCC63: Since Tcl 8.1 it uses UTF-8 encoding for internal representation of strings
595   Tcl_ExternalToUtfDString ( NULL, com, -1, &command );
596 #else
597   Tcl_DStringAppend(&command,com,-1);
598 #endif
599
600   if (!theCommands.Complete(Tcl_DStringValue(&command)))
601     return Standard_False;
602
603   // *******************************************************************
604   // Command interpreter
605   // *******************************************************************
606
607 //  Standard_Integer i = 0;
608 //  Standard_Integer j = 0;
609
610   Standard_Boolean wasspying = Draw_Spying;
611
612   OSD_Timer tictac;
613   Standard_Boolean hadchrono = Draw_Chrono;
614   if (hadchrono) tictac.Start();
615
616   if (Draw_BeforeCommand) (*Draw_BeforeCommand) ();
617
618   Standard_Integer c;
619
620   c = theCommands.RecordAndEval(Tcl_DStringValue(&command));
621
622   if (Draw_AfterCommand) (*Draw_AfterCommand)(c);
623
624   if (wasspying && Draw_Spying) {
625     if (c > 0) spystream << "# ";
626     spystream << Tcl_DStringValue(&command) << "\n";
627   }
628
629   dout.Flush();
630
631   if (*theCommands.Result())
632   {
633     if (c > 0 && theCommands.ToColorize())
634     {
635       Message_PrinterOStream::SetConsoleTextColor (&std::cout, Message_ConsoleColor_Red, true);
636     }
637     std::cout << theCommands.Result() << std::endl;
638     if (c > 0 && theCommands.ToColorize())
639     {
640       Message_PrinterOStream::SetConsoleTextColor (&std::cout, Message_ConsoleColor_Default, false);
641     }
642   }
643
644   if (Draw_Chrono && hadchrono) {
645     tictac.Stop();
646     tictac.Show();
647   }
648
649   Tcl_DStringFree(&command);
650
651   return Standard_True;
652 }
653
654 //
655 // for TCl
656 //
657
658 Standard_Integer Tcl_AppInit (Tcl_Interp *)
659 {
660   return 0;
661 }
662
663 //
664 // for debug call
665 //
666
667
668
669 Standard_Integer  Draw_Call (char *c)
670 {
671    Standard_Integer r = theCommands.Eval(c);
672    std::cout << theCommands.Result() << std::endl;
673    return r;
674 }
675
676 //=================================================================================
677 //
678 //=================================================================================
679 void Draw::Load (Draw_Interpretor& theDI,
680                  const TCollection_AsciiString& theKey,
681                  const TCollection_AsciiString& theResourceFileName,
682                  const TCollection_AsciiString& theDefaultsDirectory,
683                  const TCollection_AsciiString& theUserDefaultsDirectory,
684                  const Standard_Boolean theIsVerbose)
685 {
686   static Plugin_MapOfFunctions theMapOfFunctions;
687   OSD_Function aFunc = NULL;
688   if (!theMapOfFunctions.Find (theKey, aFunc))
689   {
690     TCollection_AsciiString aPluginLibrary;
691     Handle(Resource_Manager) aPluginResource = new Resource_Manager (theResourceFileName, theDefaultsDirectory, theUserDefaultsDirectory, theIsVerbose);
692     if (!aPluginResource->Find (theKey, aPluginLibrary))
693     {
694       Message::SendFail() << "could not find the resource:" << theKey;
695       Standard_SStream aMsg; aMsg << "Could not find the resource:" << theKey << std::endl;
696       throw Draw_Failure (aMsg.str().c_str());
697     }
698
699 #if !defined(_WIN32) || defined(__MINGW32__)
700     aPluginLibrary = TCollection_AsciiString ("lib") + aPluginLibrary;
701 #endif
702 #ifdef _WIN32
703     aPluginLibrary += ".dll";
704 #elif __APPLE__
705     aPluginLibrary += ".dylib";
706 #elif defined (HPUX) || defined(_hpux)
707     aPluginLibrary += ".sl";
708 #else
709     aPluginLibrary += ".so";
710 #endif
711     OSD_SharedLibrary aSharedLibrary (aPluginLibrary.ToCString());
712     if (!aSharedLibrary.DlOpen (OSD_RTLD_LAZY))
713     {
714       const TCollection_AsciiString anError (aSharedLibrary.DlError());
715       Standard_SStream aMsg;
716       aMsg << "Could not open: " << aPluginLibrary << "; reason: " << anError;
717 #ifdef OCCT_DEBUG
718       std::cout << "could not open: "  << aPluginLibrary << " ; reason: "<< anError << std::endl;
719 #endif
720       throw Draw_Failure(aMsg.str().c_str());
721     }
722
723     aFunc = aSharedLibrary.DlSymb ("PLUGINFACTORY");
724     if (aFunc == NULL)
725     {
726       const TCollection_AsciiString anError (aSharedLibrary.DlError());
727       Standard_SStream aMsg;
728       aMsg << "Could not find the factory in: " << aPluginLibrary << anError;
729       throw Draw_Failure(aMsg.str().c_str());
730     }
731     theMapOfFunctions.Bind (theKey, aFunc);
732   }
733
734   void (*fp) (Draw_Interpretor&) = NULL;
735   fp = (void (*)(Draw_Interpretor&) )aFunc;
736   (*fp) (theDI);
737 }
738
739 namespace
740 {
741   const Standard_Integer THE_MAX_INTEGER_COLOR_COMPONENT = 255;
742   const Standard_ShortReal THE_MAX_REAL_COLOR_COMPONENT = 1.0f;
743
744   //! Parses string and get an integer color component (only values within range 0 .. 255 are allowed)
745   //! @param theColorComponentString the string representing the color component
746   //! @param theIntegerColorComponent an integer color component that is a result of parsing
747   //! @return true if parsing was successful, or false otherwise
748   static bool parseNumericalColorComponent (const Standard_CString theColorComponentString,
749                                             Standard_Integer&      theIntegerColorComponent)
750   {
751     Standard_Integer anIntegerColorComponent;
752     if (!Draw::ParseInteger (theColorComponentString, anIntegerColorComponent))
753     {
754       return false;
755     }
756     if ((anIntegerColorComponent < 0) || (anIntegerColorComponent > THE_MAX_INTEGER_COLOR_COMPONENT))
757     {
758       return false;
759     }
760     theIntegerColorComponent = anIntegerColorComponent;
761     return true;
762   }
763
764   //! Parses the string and gets a real color component from it (only values within range 0.0 .. 1.0 are allowed)
765   //! @param theColorComponentString the string representing the color component
766   //! @param theRealColorComponent a real color component that is a result of parsing
767   //! @return true if parsing was successful, or false otherwise
768   static bool parseNumericalColorComponent (const Standard_CString theColorComponentString,
769                                             Standard_ShortReal&    theRealColorComponent)
770   {
771     Standard_Real aRealColorComponent;
772     if (!Draw::ParseReal (theColorComponentString, aRealColorComponent))
773     {
774       return false;
775     }
776     const Standard_ShortReal aShortRealColorComponent = static_cast<Standard_ShortReal> (aRealColorComponent);
777     if ((aShortRealColorComponent < 0.0f) || (aShortRealColorComponent > THE_MAX_REAL_COLOR_COMPONENT))
778     {
779       return false;
780     }
781     theRealColorComponent = aShortRealColorComponent;
782     return true;
783   }
784
785   //! Parses the string and gets a real color component from it (integer values 2 .. 255 are scaled to the 0.0 .. 1.0
786   //! range, values 0 and 1 are leaved as they are)
787   //! @param theColorComponentString the string representing the color component
788   //! @param theColorComponent a color component that is a result of parsing
789   //! @return true if parsing was successful, or false otherwise
790   static bool parseColorComponent (const Standard_CString theColorComponentString,
791                                    Standard_ShortReal&    theColorComponent)
792   {
793     Standard_Integer anIntegerColorComponent;
794     if (parseNumericalColorComponent (theColorComponentString, anIntegerColorComponent))
795     {
796       if (anIntegerColorComponent == 1)
797       {
798         theColorComponent = THE_MAX_REAL_COLOR_COMPONENT;
799       }
800       else
801       {
802         theColorComponent = anIntegerColorComponent * 1.0f / THE_MAX_INTEGER_COLOR_COMPONENT;
803       }
804       return true;
805     }
806     return parseNumericalColorComponent (theColorComponentString, theColorComponent);
807   }
808
809   //! Parses the array of strings and gets an integer color (only values within range 0 .. 255 are allowed and at least
810   //! one of components must be greater than 1)
811   //! @tparam TheNumber the type of resulting color vector elements
812   //! @param theNumberOfColorComponents the number of color components
813   //! @param theColorComponentStrings the array of strings representing color components
814   //! @param theNumericalColor a 4-component vector that is a result of parsing
815   //! @return true if parsing was successful, or false otherwise
816   template <typename TheNumber>
817   static bool parseNumericalColor (Standard_Integer&            theNumberOfColorComponents,
818                                    const char* const* const     theColorComponentStrings,
819                                    NCollection_Vec4<TheNumber>& theNumericalColor)
820   {
821     for (Standard_Integer aColorComponentIndex = 0; aColorComponentIndex < theNumberOfColorComponents;
822          ++aColorComponentIndex)
823     {
824       const char* const aColorComponentString = theColorComponentStrings[aColorComponentIndex];
825       TheNumber         aNumericalColorComponent;
826       if (parseNumericalColorComponent (aColorComponentString, aNumericalColorComponent))
827       {
828         theNumericalColor[aColorComponentIndex] = aNumericalColorComponent;
829       }
830       else
831       {
832         if (aColorComponentIndex == 3)
833         {
834           theNumberOfColorComponents = 3;
835         }
836         else
837         {
838           return false;
839         }
840       }
841     }
842     return true;
843   }
844
845   //! Parses an array of strings and get an integer color (only values within range 0 .. 255 are allowed and at least
846   //! one of components must be greater than 1)
847   //! @param theNumberOfColorComponents the number of color components
848   //! @param theColorComponentStrings the array of strings representing color components
849   //! @param theColor a color that is a result of parsing
850   //! @return true if parsing was successful, or false otherwise
851   static bool parseIntegerColor (Standard_Integer&        theNumberOfColorComponents,
852                                  const char* const* const theColorComponentStrings,
853                                  Quantity_ColorRGBA&      theColor)
854   {
855     const Standard_Integer THE_COLOR_COMPONENT_NOT_PARSED = -1;
856     NCollection_Vec4<int>   anIntegerColor (THE_COLOR_COMPONENT_NOT_PARSED);
857     if (!parseNumericalColor (theNumberOfColorComponents, theColorComponentStrings, anIntegerColor)
858       || anIntegerColor.maxComp() <= 1)
859     {
860       return false;
861     }
862     if (anIntegerColor.a() == THE_COLOR_COMPONENT_NOT_PARSED)
863     {
864       anIntegerColor.a() = THE_MAX_INTEGER_COLOR_COMPONENT;
865     }
866
867     const NCollection_Vec4<float> aRealColor = NCollection_Vec4<float> (anIntegerColor) / static_cast<float> (THE_MAX_INTEGER_COLOR_COMPONENT);
868     theColor = Quantity_ColorRGBA (Quantity_ColorRGBA::Convert_sRGB_To_LinearRGB (aRealColor));
869     return true;
870   }
871
872   //! Parses an array of strings and get a real color (only values within range 0.0 .. 1.0 are allowed)
873   //! @param theNumberOfColorComponents the number of color components
874   //! @param theColorComponentStrings the array of strings representing color components
875   //! @param theColor a color that is a result of parsing
876   //! @return true if parsing was successful, or false otherwise
877   static bool parseRealColor (Standard_Integer&        theNumberOfColorComponents,
878                               const char* const* const theColorComponentStrings,
879                               Quantity_ColorRGBA&      theColor)
880   {
881     NCollection_Vec4<float> aRealColor (THE_MAX_REAL_COLOR_COMPONENT);
882     if (!parseNumericalColor (theNumberOfColorComponents, theColorComponentStrings, aRealColor))
883     {
884       return false;
885     }
886     theColor = Quantity_ColorRGBA (aRealColor);
887     return true;
888   }
889 }
890
891 //=======================================================================
892 // function : parseColor
893 // purpose  :
894 //=======================================================================
895 Standard_Integer Draw::parseColor (const Standard_Integer   theArgNb,
896                                    const char* const* const theArgVec,
897                                    Quantity_ColorRGBA&      theColor,
898                                    const bool               theToParseAlpha)
899 {
900   if ((theArgNb >= 1) && Quantity_ColorRGBA::ColorFromHex (theArgVec[0], theColor, !theToParseAlpha))
901   {
902     return 1;
903   }
904   if (theArgNb >= 1 && Quantity_ColorRGBA::ColorFromName (theArgVec[0], theColor))
905   {
906     if (theArgNb >= 2 && theToParseAlpha)
907     {
908       const Standard_CString anAlphaStr = theArgVec[1];
909       Standard_ShortReal     anAlphaComponent;
910       if (parseColorComponent (anAlphaStr, anAlphaComponent))
911       {
912         theColor.SetAlpha (anAlphaComponent);
913         return 2;
914       }
915     }
916     return 1;
917   }
918   if (theArgNb >= 3)
919   {
920     const Standard_Integer aNumberOfColorComponentsToParse = Min (theArgNb, theToParseAlpha ? 4 : 3);
921     Standard_Integer aNumberOfColorComponentsParsed = aNumberOfColorComponentsToParse;
922     if (parseIntegerColor (aNumberOfColorComponentsParsed, theArgVec, theColor))
923     {
924       return aNumberOfColorComponentsParsed;
925     }
926     aNumberOfColorComponentsParsed = aNumberOfColorComponentsToParse;
927     if (parseRealColor (aNumberOfColorComponentsParsed, theArgVec, theColor))
928     {
929       return aNumberOfColorComponentsParsed;
930     }
931     return 0;
932   }
933   return 0;
934 }
935
936 //=======================================================================
937 //function : ParseOnOff
938 //purpose  :
939 //=======================================================================
940 Standard_Boolean Draw::ParseOnOff (Standard_CString  theArg,
941                                    Standard_Boolean& theIsOn)
942 {
943   TCollection_AsciiString aFlag(theArg);
944   aFlag.LowerCase();
945   if (aFlag == "on"
946    || aFlag == "1")
947   {
948     theIsOn = Standard_True;
949     return Standard_True;
950   }
951   else if (aFlag == "off"
952         || aFlag == "0")
953   {
954     theIsOn = Standard_False;
955     return Standard_True;
956   }
957   return Standard_False;
958 }