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