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