ae063325de58feb9f46d46f08948fbaaece6e313
[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;
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) PInd = 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)& thePI)
244 {
245   PInd = thePI;
246 }
247
248 Handle(Draw_ProgressIndicator) Draw::GetProgressBar()
249 {
250   return PInd;
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       for (Message_SequenceOfPrinters::Iterator aPrinterIter (Message::DefaultMessenger()->Printers());
508            aPrinterIter.More(); aPrinterIter.Next())
509       {
510         if (Handle(Message_PrinterOStream) aPrinter = Handle(Message_PrinterOStream)::DownCast (aPrinterIter.Value()))
511         {
512           aPrinter->SetToColorize (Standard_False);
513         }
514       }
515     }
516     ReadInitFile (aRunFile);
517     // provide a clean exit, this is useful for some analysis tools
518     if ( ! isInteractiveForced )
519 #ifndef _WIN32
520       return;
521 #else
522       ExitProcess(0);
523 #endif
524   }
525
526   // execute command from command line
527   if (!aCommand.IsEmpty())
528   {
529 #ifdef _WIN32
530     if (!Draw_Batch)
531     {
532       // on Windows except batch mode, commands are executed in separate thread
533       while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
534       TCollection_ExtendedString aCmdWide(aCommand);
535       wcscpy_s(console_command, aCmdWide.ToWideString());
536       console_semaphore = HAS_CONSOLE_COMMAND;
537       while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
538     }
539     else
540 #endif
541     Draw_Interprete (aCommand.ToCString()); // Linux and Windows batch mode
542     // provide a clean exit, this is useful for some analysis tools
543     if ( ! isInteractiveForced )
544 #ifndef _WIN32
545       return;
546 #else
547       ExitProcess(0);
548 #endif
549   }
550
551   // *****************************************************************
552   // X loop
553   // *****************************************************************
554   if (! Draw_Batch) {
555 #ifdef _WIN32
556     Run_Appli(hWnd);
557 #else
558     Run_Appli(Draw_Interprete);
559 #endif
560   }
561   else
562   {
563     const int MAXCMD = 2048;
564     char cmd[MAXCMD];
565     for (int ncmd = 1;; ++ncmd)
566     {
567       std::cout << "Draw[" << ncmd << "]> ";
568       if (std::cin.getline (cmd, MAXCMD).fail())
569       {
570         break;
571       }
572       Draw_Interprete(cmd);
573     }
574   }
575 #ifdef _WIN32
576   // Destruction de l'application
577   Destroy_Appli(hInst);
578 #endif
579 }
580 //#endif
581
582 // User functions called before and after each command
583 void (*Draw_BeforeCommand)() = NULL;
584 void (*Draw_AfterCommand)(Standard_Integer) = NULL;
585
586 Standard_Boolean Draw_Interprete(const char* com)
587 {
588
589   static Standard_Boolean first = Standard_True;
590   static Tcl_DString command;
591
592   if (first) {
593     first = Standard_False;
594     Tcl_DStringInit(&command);
595   }
596
597 #ifdef _WIN32
598   // string is already converted into UTF-8
599   Tcl_DStringAppend(&command, com, -1);
600 #elif ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
601   // OCC63: Since Tcl 8.1 it uses UTF-8 encoding for internal representation of strings
602   Tcl_ExternalToUtfDString ( NULL, com, -1, &command );
603 #else
604   Tcl_DStringAppend(&command,com,-1);
605 #endif
606
607   if (!theCommands.Complete(Tcl_DStringValue(&command)))
608     return Standard_False;
609
610   // *******************************************************************
611   // Command interpreter
612   // *******************************************************************
613
614 //  Standard_Integer i = 0;
615 //  Standard_Integer j = 0;
616
617   Standard_Boolean wasspying = Draw_Spying;
618
619   OSD_Timer tictac;
620   Standard_Boolean hadchrono = Draw_Chrono;
621   if (hadchrono) tictac.Start();
622
623   if (Draw_BeforeCommand) (*Draw_BeforeCommand) ();
624
625   Standard_Integer c;
626
627   c = theCommands.RecordAndEval(Tcl_DStringValue(&command));
628
629   if (Draw_AfterCommand) (*Draw_AfterCommand)(c);
630
631   if (wasspying && Draw_Spying) {
632     if (c > 0) spystream << "# ";
633     spystream << Tcl_DStringValue(&command) << "\n";
634   }
635
636   dout.Flush();
637
638   if (*theCommands.Result())
639   {
640     std::cout << theCommands.Result() << std::endl;
641   }
642
643   if (Draw_Chrono && hadchrono) {
644     tictac.Stop();
645     tictac.Show();
646   }
647
648   Tcl_DStringFree(&command);
649
650   return Standard_True;
651 }
652
653 //
654 // for TCl
655 //
656
657 Standard_Integer Tcl_AppInit (Tcl_Interp *)
658 {
659   return 0;
660 }
661
662 //
663 // for debug call
664 //
665
666
667
668 Standard_Integer  Draw_Call (char *c)
669 {
670    Standard_Integer r = theCommands.Eval(c);
671    std::cout << theCommands.Result() << std::endl;
672    return r;
673 }
674
675 //=================================================================================
676 //
677 //=================================================================================
678 void Draw::Load (Draw_Interpretor& theDI,
679                  const TCollection_AsciiString& theKey,
680                  const TCollection_AsciiString& theResourceFileName,
681                  const TCollection_AsciiString& theDefaultsDirectory,
682                  const TCollection_AsciiString& theUserDefaultsDirectory,
683                  const Standard_Boolean theIsVerbose)
684 {
685   static Plugin_MapOfFunctions theMapOfFunctions;
686   OSD_Function aFunc = NULL;
687   if (!theMapOfFunctions.Find (theKey, aFunc))
688   {
689     TCollection_AsciiString aPluginLibrary;
690     Handle(Resource_Manager) aPluginResource = new Resource_Manager (theResourceFileName, theDefaultsDirectory, theUserDefaultsDirectory, theIsVerbose);
691     if (!aPluginResource->Find (theKey, aPluginLibrary))
692     {
693       Message::SendFail() << "could not find the resource:" << theKey;
694       Standard_SStream aMsg; aMsg << "Could not find the resource:" << theKey << std::endl;
695       throw Draw_Failure (aMsg.str().c_str());
696     }
697
698 #if !defined(_WIN32) || defined(__MINGW32__)
699     aPluginLibrary = TCollection_AsciiString ("lib") + aPluginLibrary;
700 #endif
701 #ifdef _WIN32
702     aPluginLibrary += ".dll";
703 #elif __APPLE__
704     aPluginLibrary += ".dylib";
705 #elif defined (HPUX) || defined(_hpux)
706     aPluginLibrary += ".sl";
707 #else
708     aPluginLibrary += ".so";
709 #endif
710     OSD_SharedLibrary aSharedLibrary (aPluginLibrary.ToCString());
711     if (!aSharedLibrary.DlOpen (OSD_RTLD_LAZY))
712     {
713       const TCollection_AsciiString anError (aSharedLibrary.DlError());
714       Standard_SStream aMsg;
715       aMsg << "Could not open: " << aPluginLibrary << "; reason: " << anError;
716 #ifdef OCCT_DEBUG
717       std::cout << "could not open: "  << aPluginLibrary << " ; reason: "<< anError << std::endl;
718 #endif
719       throw Draw_Failure(aMsg.str().c_str());
720     }
721
722     aFunc = aSharedLibrary.DlSymb ("PLUGINFACTORY");
723     if (aFunc == NULL)
724     {
725       const TCollection_AsciiString anError (aSharedLibrary.DlError());
726       Standard_SStream aMsg;
727       aMsg << "Could not find the factory in: " << aPluginLibrary << anError;
728       throw Draw_Failure(aMsg.str().c_str());
729     }
730     theMapOfFunctions.Bind (theKey, aFunc);
731   }
732
733   void (*fp) (Draw_Interpretor&) = NULL;
734   fp = (void (*)(Draw_Interpretor&) )aFunc;
735   (*fp) (theDI);
736 }
737
738 namespace
739 {
740   const Standard_Integer THE_MAX_INTEGER_COLOR_COMPONENT = 255;
741   const Standard_ShortReal THE_MAX_REAL_COLOR_COMPONENT = 1.0f;
742
743   //! Parses string and get an integer color component (only values within range 0 .. 255 are allowed)
744   //! @param theColorComponentString the string representing the color component
745   //! @param theIntegerColorComponent an integer color component that is a result of parsing
746   //! @return true if parsing was successful, or false otherwise
747   static bool parseNumericalColorComponent (const Standard_CString theColorComponentString,
748                                             Standard_Integer&      theIntegerColorComponent)
749   {
750     Standard_Integer anIntegerColorComponent;
751     if (!Draw::ParseInteger (theColorComponentString, anIntegerColorComponent))
752     {
753       return false;
754     }
755     if ((anIntegerColorComponent < 0) || (anIntegerColorComponent > THE_MAX_INTEGER_COLOR_COMPONENT))
756     {
757       return false;
758     }
759     theIntegerColorComponent = anIntegerColorComponent;
760     return true;
761   }
762
763   //! Parses the string and gets a real color component from it (only values within range 0.0 .. 1.0 are allowed)
764   //! @param theColorComponentString the string representing the color component
765   //! @param theRealColorComponent a real color component that is a result of parsing
766   //! @return true if parsing was successful, or false otherwise
767   static bool parseNumericalColorComponent (const Standard_CString theColorComponentString,
768                                             Standard_ShortReal&    theRealColorComponent)
769   {
770     Standard_Real aRealColorComponent;
771     if (!Draw::ParseReal (theColorComponentString, aRealColorComponent))
772     {
773       return false;
774     }
775     const Standard_ShortReal aShortRealColorComponent = static_cast<Standard_ShortReal> (aRealColorComponent);
776     if ((aShortRealColorComponent < 0.0f) || (aShortRealColorComponent > THE_MAX_REAL_COLOR_COMPONENT))
777     {
778       return false;
779     }
780     theRealColorComponent = aShortRealColorComponent;
781     return true;
782   }
783
784   //! Parses the string and gets a real color component from it (integer values 2 .. 255 are scaled to the 0.0 .. 1.0
785   //! range, values 0 and 1 are leaved as they are)
786   //! @param theColorComponentString the string representing the color component
787   //! @param theColorComponent a color component that is a result of parsing
788   //! @return true if parsing was successful, or false otherwise
789   static bool parseColorComponent (const Standard_CString theColorComponentString,
790                                    Standard_ShortReal&    theColorComponent)
791   {
792     Standard_Integer anIntegerColorComponent;
793     if (parseNumericalColorComponent (theColorComponentString, anIntegerColorComponent))
794     {
795       if (anIntegerColorComponent == 1)
796       {
797         theColorComponent = THE_MAX_REAL_COLOR_COMPONENT;
798       }
799       else
800       {
801         theColorComponent = anIntegerColorComponent * 1.0f / THE_MAX_INTEGER_COLOR_COMPONENT;
802       }
803       return true;
804     }
805     return parseNumericalColorComponent (theColorComponentString, theColorComponent);
806   }
807
808   //! Parses the array of strings and gets an integer color (only values within range 0 .. 255 are allowed and at least
809   //! one of components must be greater than 1)
810   //! @tparam TheNumber the type of resulting color vector elements
811   //! @param theNumberOfColorComponents the number of color components
812   //! @param theColorComponentStrings the array of strings representing color components
813   //! @param theNumericalColor a 4-component vector that is a result of parsing
814   //! @return true if parsing was successful, or false otherwise
815   template <typename TheNumber>
816   static bool parseNumericalColor (Standard_Integer&            theNumberOfColorComponents,
817                                    const char* const* const     theColorComponentStrings,
818                                    NCollection_Vec4<TheNumber>& theNumericalColor)
819   {
820     for (Standard_Integer aColorComponentIndex = 0; aColorComponentIndex < theNumberOfColorComponents;
821          ++aColorComponentIndex)
822     {
823       const char* const aColorComponentString = theColorComponentStrings[aColorComponentIndex];
824       TheNumber         aNumericalColorComponent;
825       if (parseNumericalColorComponent (aColorComponentString, aNumericalColorComponent))
826       {
827         theNumericalColor[aColorComponentIndex] = aNumericalColorComponent;
828       }
829       else
830       {
831         if (aColorComponentIndex == 3)
832         {
833           theNumberOfColorComponents = 3;
834         }
835         else
836         {
837           return false;
838         }
839       }
840     }
841     return true;
842   }
843
844   //! Parses an array of strings and get an integer color (only values within range 0 .. 255 are allowed and at least
845   //! one of components must be greater than 1)
846   //! @param theNumberOfColorComponents the number of color components
847   //! @param theColorComponentStrings the array of strings representing color components
848   //! @param theColor a color that is a result of parsing
849   //! @return true if parsing was successful, or false otherwise
850   static bool parseIntegerColor (Standard_Integer&        theNumberOfColorComponents,
851                                  const char* const* const theColorComponentStrings,
852                                  Quantity_ColorRGBA&      theColor)
853   {
854     const Standard_Integer THE_COLOR_COMPONENT_NOT_PARSED = -1;
855     NCollection_Vec4<int>   anIntegerColor (THE_COLOR_COMPONENT_NOT_PARSED);
856     if (!parseNumericalColor (theNumberOfColorComponents, theColorComponentStrings, anIntegerColor)
857       || anIntegerColor.maxComp() <= 1)
858     {
859       return false;
860     }
861     if (anIntegerColor.a() == THE_COLOR_COMPONENT_NOT_PARSED)
862     {
863       anIntegerColor.a() = THE_MAX_INTEGER_COLOR_COMPONENT;
864     }
865
866     const NCollection_Vec4<float> aRealColor = NCollection_Vec4<float> (anIntegerColor) / static_cast<float> (THE_MAX_INTEGER_COLOR_COMPONENT);
867     theColor = Quantity_ColorRGBA (Quantity_ColorRGBA::Convert_sRGB_To_LinearRGB (aRealColor));
868     return true;
869   }
870
871   //! Parses an array of strings and get a real color (only values within range 0.0 .. 1.0 are allowed)
872   //! @param theNumberOfColorComponents the number of color components
873   //! @param theColorComponentStrings the array of strings representing color components
874   //! @param theColor a color that is a result of parsing
875   //! @return true if parsing was successful, or false otherwise
876   static bool parseRealColor (Standard_Integer&        theNumberOfColorComponents,
877                               const char* const* const theColorComponentStrings,
878                               Quantity_ColorRGBA&      theColor)
879   {
880     NCollection_Vec4<float> aRealColor (THE_MAX_REAL_COLOR_COMPONENT);
881     if (!parseNumericalColor (theNumberOfColorComponents, theColorComponentStrings, aRealColor))
882     {
883       return false;
884     }
885     theColor = Quantity_ColorRGBA (aRealColor);
886     return true;
887   }
888 }
889
890 //=======================================================================
891 // function : parseColor
892 // purpose  :
893 //=======================================================================
894 Standard_Integer Draw::parseColor (const Standard_Integer   theArgNb,
895                                    const char* const* const theArgVec,
896                                    Quantity_ColorRGBA&      theColor,
897                                    const bool               theToParseAlpha)
898 {
899   if ((theArgNb >= 1) && Quantity_ColorRGBA::ColorFromHex (theArgVec[0], theColor, !theToParseAlpha))
900   {
901     return 1;
902   }
903   if (theArgNb >= 1 && Quantity_ColorRGBA::ColorFromName (theArgVec[0], theColor))
904   {
905     if (theArgNb >= 2 && theToParseAlpha)
906     {
907       const Standard_CString anAlphaStr = theArgVec[1];
908       Standard_ShortReal     anAlphaComponent;
909       if (parseColorComponent (anAlphaStr, anAlphaComponent))
910       {
911         theColor.SetAlpha (anAlphaComponent);
912         return 2;
913       }
914     }
915     return 1;
916   }
917   if (theArgNb >= 3)
918   {
919     const Standard_Integer aNumberOfColorComponentsToParse = Min (theArgNb, theToParseAlpha ? 4 : 3);
920     Standard_Integer aNumberOfColorComponentsParsed = aNumberOfColorComponentsToParse;
921     if (parseIntegerColor (aNumberOfColorComponentsParsed, theArgVec, theColor))
922     {
923       return aNumberOfColorComponentsParsed;
924     }
925     aNumberOfColorComponentsParsed = aNumberOfColorComponentsToParse;
926     if (parseRealColor (aNumberOfColorComponentsParsed, theArgVec, theColor))
927     {
928       return aNumberOfColorComponentsParsed;
929     }
930     return 0;
931   }
932   return 0;
933 }
934
935 //=======================================================================
936 //function : ParseOnOff
937 //purpose  :
938 //=======================================================================
939 Standard_Boolean Draw::ParseOnOff (Standard_CString  theArg,
940                                    Standard_Boolean& theIsOn)
941 {
942   TCollection_AsciiString aFlag(theArg);
943   aFlag.LowerCase();
944   if (aFlag == "on"
945    || aFlag == "1")
946   {
947     theIsOn = Standard_True;
948     return Standard_True;
949   }
950   else if (aFlag == "off"
951         || aFlag == "0")
952   {
953     theIsOn = Standard_False;
954     return Standard_True;
955   }
956   return Standard_False;
957 }