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