0028110: Configuration - specify Unicode charset instead of multibyte in project...
[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 <OSD.hxx>
27 #include <OSD_Environment.hxx>
28 #include <OSD_SharedLibrary.hxx>
29 #include <OSD_Timer.hxx>
30 #include <Plugin_MapOfFunctions.hxx>
31 #include <Resource_Manager.hxx>
32 #include <Standard_ErrorHandler.hxx>
33 #include <Standard_Stream.hxx>
34 #include <Standard_Version.hxx>
35 #include <TCollection_AsciiString.hxx>
36
37 #include <tcl.h>
38 // on MSVC, use #pragma to define name of the Tcl library to link with,
39 // depending on Tcl version number
40 #ifdef _MSC_VER
41 // two helper macros are needed to convert version number macro to string literal
42 #define STRINGIZE1(a) #a
43 #define STRINGIZE2(a) STRINGIZE1(a)
44 #pragma comment (lib, "tcl" STRINGIZE2(TCL_MAJOR_VERSION) STRINGIZE2(TCL_MINOR_VERSION) ".lib")
45 #pragma comment (lib, "tk"  STRINGIZE2(TCL_MAJOR_VERSION) STRINGIZE2(TCL_MINOR_VERSION) ".lib")
46 #undef STRINGIZE2
47 #undef STRINGIZE1
48 #endif
49
50 extern Standard_Boolean Draw_ParseFailed;
51
52 Standard_EXPORT Draw_Viewer dout;
53 Standard_EXPORT Draw_Interpretor theCommands;
54 Standard_EXPORT Standard_Boolean Draw_Batch;
55 Standard_EXPORT Standard_Boolean Draw_Spying = Standard_False;
56 Standard_EXPORT Standard_Boolean Draw_Chrono = Standard_False;
57 Standard_EXPORT Standard_Boolean Draw_VirtualWindows = Standard_False;
58 Standard_EXPORT Standard_Boolean ErrorMessages = Standard_True;
59
60 static const char* ColorNames[MAXCOLOR] = {
61   "White","Red","Green","Blue","Cyan","Gold","Magenta",
62   "Maroon","Orange","Pink","Salmon","Violet","Yellow","Khaki","Coral"
63   };
64
65 filebuf Draw_Spyfile;
66
67 static ostream spystream(&Draw_Spyfile);
68
69 static   Standard_Boolean XLoop;
70
71 static Handle(Draw_ProgressIndicator) PInd = NULL;
72
73 Standard_EXPORT Standard_Boolean Draw_Interprete(const char* command);
74 // true if complete command
75
76 // *******************************************************************
77 // read an init file
78 // *******************************************************************
79 #ifdef _WIN32
80 extern console_semaphore_value volatile console_semaphore;
81 extern wchar_t console_command[1000];
82 #endif
83
84 static void ReadInitFile (const TCollection_AsciiString& theFileName)
85 {
86   TCollection_AsciiString aPath = theFileName;
87 #ifdef _WIN32
88   if (!Draw_Batch)
89   {
90     try
91     {
92       aPath.ChangeAll ('\\', '/');
93       {
94         const TCollection_ExtendedString aCmdWide = TCollection_ExtendedString ("source -encoding utf-8 \"") + TCollection_ExtendedString (aPath) + "\"";
95         memcpy (console_command, aCmdWide.ToWideString(), Min (aCmdWide.Length() + 1, 980) * sizeof(wchar_t));
96       }
97       console_semaphore = HAS_CONSOLE_COMMAND;
98       while (console_semaphore == HAS_CONSOLE_COMMAND)
99       {
100         Sleep(10);
101       }
102     }
103     catch(...) {
104       cout << "Error while reading a script file." << endl;
105       ExitProcess(0);
106     }
107   } else {
108 #endif
109     char* com = new char [aPath.Length() + strlen ("source -encoding utf-8 ") + 2];
110     Sprintf (com, "source -encoding utf-8 %s", aPath.ToCString());
111     Draw_Interprete (com);
112     delete [] com;
113 #ifdef _WIN32
114   }
115 #endif
116 }
117
118 //=======================================================================
119 //function :
120 //purpose  : Set/Get Progress Indicator
121 //=======================================================================
122 void Draw::SetProgressBar(const Handle(Draw_ProgressIndicator)& thePI)
123 {
124   PInd = thePI;
125 }
126
127 Handle(Draw_ProgressIndicator) Draw::GetProgressBar()
128 {
129   return PInd;
130 }
131
132 #ifndef _WIN32
133 /*--------------------------------------------------------*\
134 |  exitProc: finalization handler for Tcl/Tk thread. Forces parent process to die
135 \*--------------------------------------------------------*/
136 void exitProc(ClientData /*dc*/)
137 {
138   if (!Draw_Batch) {
139     for (Standard_Integer id = 0; id < MAXVIEW; id++)
140       dout.DeleteView(id);
141   }
142 }
143 #endif
144
145 // *******************************************************************
146 // main
147 // *******************************************************************
148 #ifdef _WIN32
149 Standard_EXPORT void Draw_Appli(HINSTANCE hInst, HINSTANCE hPrevInst, int nShow, int argc, wchar_t** argv, const FDraw_InitAppli Draw_InitAppli)
150 #else
151 void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli)
152 #endif
153 {
154
155 // prepend extra DLL search path to override system libraries like opengl32.dll
156 #ifdef _WIN32
157   OSD_Environment aUserDllEnv ("CSF_UserDllPath");
158   const TCollection_ExtendedString aUserDllPath (aUserDllEnv.Value());
159   if (!aUserDllPath.IsEmpty())
160   {
161     // This function available since Win XP SP1 #if (_WIN32_WINNT >= 0x0502).
162     // We retrieve dynamically here (kernel32 should be always preloaded).
163     typedef BOOL (WINAPI *SetDllDirectoryW_t)(const wchar_t* thePathName);
164     HMODULE aKern32Module = GetModuleHandleW (L"kernel32");
165     SetDllDirectoryW_t aFunc = (aKern32Module != NULL)
166                              ? (SetDllDirectoryW_t )GetProcAddress (aKern32Module, "SetDllDirectoryW") : NULL;
167     if (aFunc != NULL)
168     {
169       aFunc (aUserDllPath.ToWideString());
170     }
171     else
172     {
173       //std::cerr << "SetDllDirectoryW() is not available on this system!\n";
174     }
175     if (aKern32Module != NULL)
176     {
177       FreeLibrary (aKern32Module);
178     }
179   }
180 #endif
181
182   // *****************************************************************
183   // analyze arguments
184   // *****************************************************************
185   Draw_Batch = Standard_False;
186   TCollection_AsciiString aRunFile, aCommand;
187   Standard_Boolean isInteractiveForced = Standard_False;
188
189   // parse command line
190   for (int anArgIter = 1; anArgIter < argc; ++anArgIter)
191   {
192     TCollection_AsciiString anArg (argv[anArgIter]);
193     anArg.LowerCase();
194     if (anArg == "-h"
195      || anArg == "--help")
196     {
197       std::cout << "Open CASCADE " << OCC_VERSION_STRING_EXT << " DRAW Test Harness\n\n";
198       std::cout << "Options:\n";
199       std::cout << "  -b: batch mode (no GUI, no viewers)\n";
200       std::cout << "  -v: no GUI, use virtual (off-screen) windows for viewers\n";
201       std::cout << "  -i: interactive mode\n";
202       std::cout << "  -f file: execute script from file\n";
203       std::cout << "  -c command args...: execute command (with optional arguments)\n\n";
204       std::cout << "Options -b, -v, and -i are mutually exclusive.\n";
205       std::cout << "If -c or -f are given, -v is default; otherwise default is -i.\n";
206       std::cout << "Options -c and -f are alternatives and should be at the end \n";
207       std::cout << "of the command line.\n";
208       std::cout << "Option -c can accept set of commands separated by ';'.\n";
209       return;
210     }
211     else if (anArg == "-b")
212     {
213       Draw_Batch = Standard_True;
214     }
215     else if (anArg == "-v")
216     {
217       // force virtual windows
218       Draw_VirtualWindows = Standard_True;
219     }
220     else if (anArg == "-i")
221     {
222       // force interactive
223       Draw_VirtualWindows = Standard_False;
224       isInteractiveForced = Standard_True;
225     }
226     else if (anArg == "-f") // -f option should be LAST!
227     {
228       Draw_VirtualWindows = !isInteractiveForced;
229       if (++anArgIter < argc)
230       {
231         aRunFile = TCollection_AsciiString (argv[anArgIter]);
232       }
233       break;
234     }
235     else if (anArg == "-c") // -c option should be LAST!
236     {
237       Draw_VirtualWindows = !isInteractiveForced;
238       if (++anArgIter < argc)
239       {
240         aCommand = TCollection_AsciiString (argv[anArgIter]);
241       }
242       while (++anArgIter < argc)
243       {
244         aCommand.AssignCat (" ");
245         aCommand.AssignCat (argv[anArgIter]);
246       }
247       break;
248     }
249     else
250     {
251       std::cout << "Error: unsupported option " << TCollection_AsciiString (argv[anArgIter]) << "\n";
252     }
253   }
254
255   // *****************************************************************
256   // set signals
257   // *****************************************************************
258   OSD::SetSignal(Standard_False);
259
260 #ifdef _WIN32
261   // in interactive mode, force Windows to report dll loading problems interactively
262   if ( ! Draw_VirtualWindows && ! Draw_Batch )
263     ::SetErrorMode (0);
264 #endif
265
266   // *****************************************************************
267   // init X window and create display
268   // *****************************************************************
269 #ifdef _WIN32
270   HWND hWnd = NULL;
271 #endif
272
273   if (!Draw_Batch)
274 #ifdef _WIN32
275     Draw_Batch=!Init_Appli(hInst, hPrevInst, nShow, hWnd);
276 #else
277     Draw_Batch=!Init_Appli();
278 #endif
279   else
280     cout << "DRAW is running in batch mode" << endl;
281
282   XLoop = !Draw_Batch;
283   if (XLoop)
284   {
285     // Default colors
286     for (int i = 0; i < MAXCOLOR; ++i)
287     {
288       if (!dout.DefineColor (i, ColorNames[i]))
289       {
290         std::cout <<"Could not allocate default color " << ColorNames[i] << std::endl;
291       }
292     }
293   }
294
295   // *****************************************************************
296   // set maximum precision for cout
297   // *****************************************************************
298   cout.precision(15);
299
300   // *****************************************************************
301   // standard commands
302   // *****************************************************************
303   Draw::BasicCommands(theCommands);
304   Draw::VariableCommands(theCommands);
305   Draw::UnitCommands(theCommands);
306   if (!Draw_Batch) Draw::GraphicCommands(theCommands);
307
308   // *****************************************************************
309   // user commands
310   // *****************************************************************
311   Draw_InitAppli(theCommands);
312
313 #ifndef _WIN32
314   Tcl_CreateExitHandler(exitProc, 0);
315 #endif
316
317   // *****************************************************************
318   // read init files
319   // *****************************************************************
320   // default
321
322   if (getenv ("DRAWDEFAULT") == NULL)
323   {
324     if (getenv ("CASROOT") == NULL)
325     {
326 #ifdef _WIN32
327       ReadInitFile ("ddefault");
328 #else
329       cout << " the CASROOT variable is mandatory to Run OpenCascade "<< endl;
330       cout << "No default file" << endl;
331 #endif
332     }
333     else
334     {
335       TCollection_AsciiString aDefStr (getenv ("CASROOT"));
336       aDefStr += "/src/DrawResources/DrawDefault";
337       ReadInitFile (aDefStr);
338     }
339   }
340   else
341   {
342     ReadInitFile (getenv ("DRAWDEFAULT"));
343   }
344
345   // read commands from file
346   if (!aRunFile.IsEmpty()) {
347     ReadInitFile (aRunFile);
348     // provide a clean exit, this is useful for some analysis tools
349     if ( ! isInteractiveForced )
350 #ifndef _WIN32
351       return;
352 #else
353       ExitProcess(0);
354 #endif
355   }
356
357   // execute command from command line
358   if (!aCommand.IsEmpty()) {
359     Draw_Interprete (aCommand.ToCString());
360     // provide a clean exit, this is useful for some analysis tools
361     if ( ! isInteractiveForced )
362 #ifndef _WIN32
363       return;
364 #else
365       ExitProcess(0);
366 #endif
367   }
368
369   // *****************************************************************
370   // X loop
371   // *****************************************************************
372   if (XLoop) {
373 #ifdef _WIN32
374     Run_Appli(hWnd);
375 #else
376     Run_Appli(Draw_Interprete);
377 #endif
378   }
379   else
380   {
381     char cmd[255];
382     for (;;)
383     {
384       cout << "Viewer>";
385       int i = -1;
386       do {
387         cin.get(cmd[++i]);
388       } while ((cmd[i] != '\n') && (!cin.fail()));
389       cmd[i] = '\0';
390       Draw_Interprete(cmd);
391     }
392   }
393 #ifdef _WIN32
394   // Destruction de l'application
395   Destroy_Appli(hInst);
396 #endif
397 }
398 //#endif
399
400 // User functions called before and after each command
401 void (*Draw_BeforeCommand)() = NULL;
402 void (*Draw_AfterCommand)(Standard_Integer) = NULL;
403
404 Standard_Boolean Draw_Interprete(const char* com)
405 {
406
407   static Standard_Boolean first = Standard_True;
408   static Tcl_DString command;
409
410   if (first) {
411     first = Standard_False;
412     Tcl_DStringInit(&command);
413   }
414
415 #ifdef _WIN32
416   // string is already converted into UTF-8
417   Tcl_DStringAppend(&command, com, -1);
418 #elif ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
419   // OCC63: Since Tcl 8.1 it uses UTF-8 encoding for internal representation of strings
420   Tcl_ExternalToUtfDString ( NULL, com, -1, &command );
421 #else
422   Tcl_DStringAppend(&command,com,-1);
423 #endif
424
425   if (!theCommands.Complete(Tcl_DStringValue(&command)))
426     return Standard_False;
427
428   // *******************************************************************
429   // Command interpreter
430   // *******************************************************************
431
432 //  Standard_Integer i = 0;
433 //  Standard_Integer j = 0;
434
435   Standard_Boolean wasspying = Draw_Spying;
436
437   OSD_Timer tictac;
438   Standard_Boolean hadchrono = Draw_Chrono;
439   if (hadchrono) tictac.Start();
440
441   if (Draw_BeforeCommand) (*Draw_BeforeCommand) ();
442
443   Standard_Integer c;
444
445   c = theCommands.RecordAndEval(Tcl_DStringValue(&command));
446
447   if (Draw_AfterCommand) (*Draw_AfterCommand)(c);
448
449   if (wasspying && Draw_Spying) {
450     if (c > 0) spystream << "# ";
451     spystream << Tcl_DStringValue(&command) << "\n";
452   }
453
454   dout.Flush();
455
456   if (*theCommands.Result())
457   {
458   #ifdef _WIN32
459     const TCollection_ExtendedString aResWide (theCommands.Result());
460     std::wcout << aResWide.ToWideString() << std::endl;
461   #else
462     std::cout << theCommands.Result() << std::endl;
463   #endif
464   }
465
466   if (Draw_Chrono && hadchrono) {
467     tictac.Stop();
468     tictac.Show();
469   }
470
471   Tcl_DStringFree(&command);
472
473   return Standard_True;
474 }
475
476 //
477 // for TCl
478 //
479
480 Standard_Integer Tcl_AppInit (Tcl_Interp *)
481 {
482   return 0;
483 }
484
485 //
486 // for debug call
487 //
488
489
490
491 Standard_Integer  Draw_Call (char *c)
492 {
493    Standard_Integer r = theCommands.Eval(c);
494    cout << theCommands.Result() << endl;
495    return r;
496 }
497
498 //=================================================================================
499 //
500 //=================================================================================
501 void Draw::Load(Draw_Interpretor& theDI, const TCollection_AsciiString& theKey,
502                 const TCollection_AsciiString& theResourceFileName,
503                 TCollection_AsciiString& theDefaultsDirectory,
504                 TCollection_AsciiString& theUserDefaultsDirectory,
505                 const Standard_Boolean Verbose ) {
506
507   static Plugin_MapOfFunctions theMapOfFunctions;
508   OSD_Function f;
509
510   if(!theMapOfFunctions.IsBound(theKey)) {
511
512     Handle(Resource_Manager) aPluginResource = new Resource_Manager(theResourceFileName.ToCString(), theDefaultsDirectory, theUserDefaultsDirectory, Verbose);
513
514     if(!aPluginResource->Find(theKey.ToCString())) {
515       Standard_SStream aMsg; aMsg << "Could not find the resource:";
516       aMsg << theKey.ToCString()<< endl;
517       cout << "could not find the resource:"<<theKey.ToCString()<< endl;
518       Draw_Failure::Raise(aMsg);
519     }
520
521     TCollection_AsciiString aPluginLibrary("");
522 #if !defined(_WIN32) || defined(__MINGW32__)
523     aPluginLibrary += "lib";
524 #endif
525     aPluginLibrary +=  aPluginResource->Value(theKey.ToCString());
526 #ifdef _WIN32
527     aPluginLibrary += ".dll";
528 #elif __APPLE__
529     aPluginLibrary += ".dylib";
530 #elif defined (HPUX) || defined(_hpux)
531     aPluginLibrary += ".sl";
532 #else
533     aPluginLibrary += ".so";
534 #endif
535     OSD_SharedLibrary aSharedLibrary(aPluginLibrary.ToCString());
536     if(!aSharedLibrary.DlOpen(OSD_RTLD_LAZY)) {
537       TCollection_AsciiString error(aSharedLibrary.DlError());
538       Standard_SStream aMsg; aMsg << "Could not open: ";
539       aMsg << aPluginResource->Value(theKey.ToCString());
540       aMsg << "; reason: ";
541       aMsg << error.ToCString();
542 #ifdef OCCT_DEBUG
543       cout << "could not open: "  << aPluginResource->Value(theKey.ToCString())<< " ; reason: "<< error.ToCString() << endl;
544 #endif
545       Draw_Failure::Raise(aMsg);
546     }
547     f = aSharedLibrary.DlSymb("PLUGINFACTORY");
548     if( f == NULL ) {
549       TCollection_AsciiString error(aSharedLibrary.DlError());
550       Standard_SStream aMsg; aMsg << "Could not find the factory in: ";
551       aMsg << aPluginResource->Value(theKey.ToCString());
552       aMsg << error.ToCString();
553       Draw_Failure::Raise(aMsg);
554     }
555     theMapOfFunctions.Bind(theKey, f);
556   }
557   else
558     f = theMapOfFunctions(theKey);
559
560 //   void (*fp) (Draw_Interpretor&, const TCollection_AsciiString&) = NULL;
561 //   fp = (void (*)(Draw_Interpretor&, const TCollection_AsciiString&)) f;
562 //   (*fp) (theDI, theKey);
563
564   void (*fp) (Draw_Interpretor&) = NULL;
565   fp = (void (*)(Draw_Interpretor&)) f;
566   (*fp) (theDI);
567
568 }