1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    ParseOGLExt.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /* A program that will read in OpenGL extension header files and output VTK
16  * code that handles extensions in a more platform-independent manner.
17  */
18 
19 
20 /*
21  * Copyright 2003 Sandia Corporation.
22  * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
23  * license for use of this work by or on behalf of the
24  * U.S. Government. Redistribution and use in source and binary forms, with
25  * or without modification, are permitted provided that this Notice and any
26  * statement of authorship are reproduced on all copies.
27  */
28 
29 #include "vtkSystemIncludes.h"
30 
31 #include "Tokenizer.h"
32 
33 #include <list>
34 #include <set>
35 #include <map>
36 
37 #include <string.h>
38 #include <ctype.h>
39 
40 // #define this if you want debug output as the parser does its work
41 
42 // #define DEBUG_PARSE
43 
44 static std::set< std::pair< std::string, std::string > > ConstantsAlreadyWritten;
45 
ToUpper(std::string s)46 static std::string ToUpper(std::string s)
47 {
48   std::string u;
49 
50   for (std::string::size_type i = 0; i < s.length(); i++)
51     {
52     u.append(1, static_cast<char>(toupper(s[i])));
53     }
54 
55   return u;
56 }
57 
58 class Extension {
59 public:
GetName() const60   std::string GetName() const { return this->name; }
61   enum {GL, WGL, GLX} type;
62 
Extension()63   Extension() {}
64   Extension(char *line);
65   static bool isExtension(char *line);
66 
WriteSupportWrapperBegin(ostream & out,int itype)67   static inline void WriteSupportWrapperBegin(ostream &out, int itype) {
68     switch (itype)
69       {
70       case WGL:
71         out << "#ifdef WIN32" << endl;
72         break;
73       case GLX:
74        out << "#ifdef VTK_USE_X" << endl;
75         break;
76       case GL:
77         break;
78       }
79   }
WriteSupportWrapperBegin(ostream & out) const80   inline void WriteSupportWrapperBegin(ostream &out) const {
81     WriteSupportWrapperBegin(out, this->type);
82   }
WriteSupportWrapperEnd(ostream & out,int itype)83   static inline void WriteSupportWrapperEnd(ostream &out, int itype) {
84     if ((itype == WGL) || (itype == GLX))
85       {
86       out << "#endif" << endl;
87       }
88   }
WriteSupportWrapperEnd(ostream & out) const89   inline void WriteSupportWrapperEnd(ostream &out) const {
90     WriteSupportWrapperEnd(out, this->type);
91   }
92 
TypeToCapString(int t)93   static inline const char *TypeToCapString(int t) {
94     switch (t)
95       {
96       case GL: return "GL";
97       case GLX: return "GLX";
98       case WGL: return "WGL";
99       }
100     return NULL;
101   }
TypeToString(int t)102   static inline const char *TypeToString(int t) {
103     switch (t)
104       {
105       case GL: return "gl";
106       case GLX: return "glX";
107       case WGL: return "wgl";
108       }
109     return NULL;
110   }
111 
operator <(const Extension & obj) const112   bool operator<(const Extension &obj) const { return this->name < obj.name; }
113 
114 protected:
115   std::string name;
116 };
117 
Extension(char * line)118 Extension::Extension(char *line)
119 {
120   Tokenizer t(line);
121 
122   t.GetNextToken();
123 
124   this->name = t.GetNextToken();
125 
126   Tokenizer nameTokens(this->name, "_");
127   std::string header = nameTokens.GetNextToken();
128   if (header == "WGL")
129     {
130     this->type = WGL;
131     }
132   else if (header == "GLX")
133     {
134     this->type = GLX;
135     }
136   else
137     {
138     this->type = GL;
139     }
140 }
141 
isExtension(char * line)142 bool Extension::isExtension(char *line)
143 {
144   Tokenizer t(line);
145 
146   if (t.GetNextToken() != "#ifndef") return false;
147 
148   Tokenizer nameTokens(t.GetNextToken(), "_");
149   std::string header = nameTokens.GetNextToken();
150   if ((header == "GL") || (header == "WGL") || (header == "GLX"))
151     {
152     return true;
153     }
154 
155   return false;
156 }
157 
158 static Extension currentExtension;
159 
160 class Constant {
161 public:
GetName() const162   std::string GetName() const  { return this->name; }
163   std::string GetValue() const;
164 
165   Constant(char *line);
166   static bool isConstant(char *line);
167 
operator <(const Constant & obj) const168   bool operator<(const Constant &obj) const { return this->name < obj.name; }
169 
170 protected:
171   std::string name;
172   std::string value;
173 };
174 
175 static std::map<std::string, std::string> EncounteredConstants;
176 
Constant(char * line)177 Constant::Constant(char *line)
178 {
179   // Assumes isConstant is true.
180   Tokenizer t(line);
181 
182   t.GetNextToken();
183 
184   this->name = t.GetNextToken();
185   std::string fullname = this->name;
186   if (currentExtension.type == Extension::GL)
187     {
188     // Skip the "GL_"
189     this->name = this->name.substr(3);
190     }
191   else
192     {
193     // Skip the "GLX_" or "WGL_"
194     this->name = this->name.substr(4);
195     }
196   // Make sure name does not start with a numeric.
197   if ((this->name[0] >= '0') && (this->name[0] <= '9'))
198     {
199     this->name = '_' + this->name;
200     }
201 
202   this->value = t.GetNextToken();
203 
204   // Now record this as found.
205   EncounteredConstants[fullname] = this->value;
206 }
207 
GetValue() const208 std::string Constant::GetValue() const
209 {
210   // Sometimes, one constant points to another.  Handle this properly.
211   std::map<std::string, std::string>::iterator found
212     = EncounteredConstants.find(this->value);
213   if (found != EncounteredConstants.end())
214     {
215     return found->second;
216     }
217   return this->value;
218 }
219 
isConstant(char * line)220 bool Constant::isConstant(char *line)
221 {
222   Tokenizer t(line);
223 
224   if (t.GetNextToken() != "#define")
225     {
226     return false;
227     }
228 
229   std::string n = t.GetNextToken();
230   if (   (   (currentExtension.type == Extension::GL)
231           && (strncmp(n.c_str(), "GL_", 3) == 0) )
232       || (   (currentExtension.type == Extension::WGL)
233           && (strncmp(n.c_str(), "WGL_", 4) == 0) )
234       || (   (currentExtension.type == Extension::GLX)
235           && (strncmp(n.c_str(), "GLX_", 4) == 0) ) )
236     {
237     return true;
238     }
239   return false;
240 }
241 
242 class Typedef {
243 public:
244   std::string definition;
245 
246   Typedef(char *line);
247   static bool isTypedef(char *line);
248 
operator <(const Typedef & obj) const249   bool operator<(const Typedef &obj) const { return this->definition < obj.definition; }
250 };
251 
Typedef(char * line)252 Typedef::Typedef(char *line)
253 {
254   // Assumes isTypedef is true.
255   this->definition = line;
256 }
257 
isTypedef(char * line)258 bool Typedef::isTypedef(char *line)
259 {
260   Tokenizer t(line);
261 
262   // Hack for some SGI stuff that declares a multiline struct.
263   if (   (t.GetNextToken() == "typedef")
264       && ((t.GetNextToken() != "struct") || (t.GetNextToken() != "{")) )
265     {
266     return true;
267     }
268 
269   // Hack for how some WIN32 things are declared.
270   if (strncmp(line, "DECLARE_HANDLE(", 15) == 0)
271     {
272     return true;
273     }
274 
275   return false;
276 }
277 
278 class Function {
279 public:
GetReturnType() const280   std::string GetReturnType() const { return this->returnType; }
GetEntry() const281   std::string GetEntry() const { return this->entry; }
GetName() const282   std::string GetName() const { return this->name; }
GetArguments() const283   std::string GetArguments() const { return this->arguments; }
GetExtensionType() const284   int GetExtensionType() const { return this->extensionType; }
285 
286   Function(char *line);
287   static bool isFunction(char *line);
288   const char *GetProcType();
289 
operator <(const Function & obj) const290   bool operator<(const Function &obj) const { return this->name < obj.name; }
291 
292 protected:
293   std::string returnType;
294   std::string entry;
295   std::string name;
296   std::string arguments;
297   int extensionType;
298 };
299 
Function(char * line)300 Function::Function(char *line) : extensionType(currentExtension.type)
301 {
302   // Assumes isFunction returns true.
303 
304   Tokenizer t(line, " \n\t(");
305 
306   t.GetNextToken();
307   std::string token = t.GetNextToken();
308   this->returnType = "";
309   while ((token == "const") || (token == "unsigned"))
310     {
311     this->returnType += token + " ";
312     token = t.GetNextToken();
313     }
314   this->returnType += token;
315 
316   token = t.GetNextToken();
317   if (token == "*")
318     {
319     this->returnType += " *";
320     token = t.GetNextToken();
321     }
322   else if (token[0] == '*')
323     {
324     this->returnType += " *";
325     token = token.substr(1);
326     }
327 
328 #ifdef DEBUG_PARSE
329   cerr << "Function return type: " << this->returnType << endl;
330 #endif
331 
332   if (currentExtension.type == Extension::GL)
333     {
334     this->entry = "APIENTRY";
335     token = t.GetNextToken();
336     }
337   else if (currentExtension.type == Extension::WGL)
338     {
339     this->entry = "WINAPI";
340     token = t.GetNextToken();
341     }
342   else
343     {
344     this->entry = "";
345     }
346 
347 #ifdef DEBUG_PARSE
348   cerr << "Function entry: " << this->entry << endl;
349 #endif
350 
351   if (currentExtension.type == Extension::GL)
352     {
353     // Strip off "gl"
354     this->name = token.substr(2);
355     }
356   else
357     {
358     // Strip off "glX" or "wgl"
359     this->name = token.substr(3);
360     }
361 
362 #ifdef DEBUG_PARSE
363   cerr << "Function name: " << this->name << endl;
364 #endif
365 
366   this->arguments = t.GetRemainingString();
367 
368 #ifdef DEBUG_PARSE
369   cerr << "Function arguments: " << this->arguments << endl;
370 #endif
371 }
372 
isFunction(char * line)373 bool Function::isFunction(char *line)
374 {
375   Tokenizer t(line);
376 
377   std::string modifier = t.GetNextToken();
378   std::string sreturnType = t.GetNextToken();
379   if (sreturnType == "const")
380     {
381     // We don't really need the return type, just to skip over const.
382     sreturnType += " ";
383     sreturnType += t.GetNextToken();
384     }
385 
386   std::string sentry = t.GetNextToken();
387   if (sentry == "*")
388     {
389     sreturnType += " *";
390     sentry = t.GetNextToken();
391     }
392   else if (sentry.size() && sentry[0] == '*')
393     {
394     sreturnType += " *";
395     sentry = sentry.substr(1);
396     }
397 
398   return (   (   (currentExtension.type == Extension::GL)
399               && (modifier == "GLAPI") && (sentry == "APIENTRY") )
400           || (   (currentExtension.type == Extension::GL)
401               && (modifier == "extern") && (sentry == "APIENTRY") )
402           || (   (currentExtension.type == Extension::WGL)
403               && (modifier == "extern") && (sentry == "WINAPI") )
404           || (   (currentExtension.type == Extension::GLX)
405               && (modifier == "extern") ) );
406 }
407 
GetProcType()408 const char *Function::GetProcType()
409 {
410   static std::string proctype;
411 
412   proctype = "PFN";
413   proctype += Extension::TypeToCapString(this->extensionType);
414   proctype += ToUpper(this->name);
415   proctype += "PROC";
416 
417   return proctype.c_str();
418 }
419 
420 static std::list<Extension> extensions;
421 static std::set<Extension> extensionset;
422 static std::map<Extension, std::list<Constant> > consts;
423 static std::map<Extension, std::list<Typedef> > types;
424 static std::map<Extension, std::list<Function> > functs;
425 
ParseLine(char * line)426 static void ParseLine(char *line)
427 {
428   static bool inExtension = false;
429   static int ifLevel = 0;
430 
431   Tokenizer tokens(line);
432   std::string firstToken = tokens.GetNextToken();
433 
434   if (Extension::isExtension(line))
435     {
436     currentExtension = Extension(line);
437 #ifdef DEBUG_PARSE
438     cerr << "Recognized extension: " << line << endl;
439 #endif
440 
441     // There are some exceptions to the extensions we support.  This is
442     // because someone has placed some funky nonstandard stuff in the
443     // header files.
444     if (   (currentExtension.GetName() == "GLX_SGIX_video_source")
445         || (currentExtension.GetName() == "GLX_SGIX_dmbuffer")
446         || (currentExtension.GetName() == "GLX_SGIX_hyperpipe") )
447       {
448       inExtension = false;
449       return;
450       }
451 
452   // Only add extension to list if it is not already in it.
453     if (extensionset.find(currentExtension) == extensionset.end())
454       {
455       if (currentExtension.GetName() == "GLX_ARB_get_proc_address")
456         {
457         // Special case where GLX_VERSION_1_4 depends on a typedef in
458         // GLX_ARB_get_proc_address, so we have to move the latter up.
459         extensions.push_front(currentExtension);
460         }
461       else
462         {
463         extensions.push_back(currentExtension);
464         }
465       extensionset.insert(currentExtension);
466       }
467     inExtension = true;
468     ifLevel = 0;
469     }
470  else if (inExtension)
471     {
472     if (strncmp(firstToken.c_str(), "#if", 3) == 0)
473       {
474       ifLevel++;
475       }
476     else if (firstToken == "#endif")
477       {
478       if (ifLevel == 0)
479         {
480         inExtension = false;
481         }
482       else
483         {
484         ifLevel--;
485         }
486       }
487     else if (   Constant::isConstant(line)
488              && (strncmp(currentExtension.GetName().c_str(), (line+8),
489                          currentExtension.GetName().length()) != 0) )
490       {
491 #ifdef DEBUG_PARSE
492       cerr << "Recognized constant: " << line << endl;
493 #endif
494       consts[currentExtension].push_back(line);
495       }
496     else if (Function::isFunction(line))
497       {
498 #ifdef DEBUG_PARSE
499       cerr << "Recognized function: " << line << endl;
500 #endif
501       functs[currentExtension].push_back(line);
502       }
503     else if (Typedef::isTypedef(line))
504       {
505 #ifdef DEBUG_PARSE
506       cerr << "Recognized typedef: " << line << endl;
507 #endif
508       types[currentExtension].push_back(line);
509       }
510     }
511   else
512     {
513 #ifdef DEBUG_PARSE
514     cerr << "Unrecognized line: " << line << endl;
515 #endif
516     }
517 }
518 
WriteHeader(ostream & file,const char * generator,char ** srcs,int num_srcs)519 static void WriteHeader(ostream &file, const char *generator,
520                         char **srcs, int num_srcs)
521 {
522   file << "// -*- c++ -*-" << endl << endl;
523   file << "//DO NOT EDIT!" << endl;
524   file << "//This file was created with " << generator << endl
525        << "//from";
526   for (int i = 0; i < num_srcs; i++)
527     {
528     file << " " << srcs[i];
529     }
530   file << endl << endl;
531   file << "/*" << endl
532        << " * Copyright 2003 Sandia Corporation." << endl
533        << " * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive" << endl
534        << " * license for use of this work by or on behalf of the" << endl
535        << " * U.S. Government. Redistribution and use in source and binary forms, with" << endl
536        << " * or without modification, are permitted provided that this Notice and any" << endl
537        << " * statement of authorship are reproduced on all copies." << endl
538        << " */" << endl << endl;
539 }
540 
WriteClassDeclarationGuts(ostream & hfile,int type)541 static void WriteClassDeclarationGuts(ostream &hfile, int type)
542 {
543   for (std::list<Extension>::iterator iextension = extensions.begin();
544        iextension != extensions.end(); iextension++)
545     {
546     if (iextension->type != type) continue;
547     hfile << endl << "  //Definitions for " << iextension->GetName().c_str() << endl;
548     std::map<Extension, std::list<Constant> >::iterator cExts
549       = consts.find(*iextension);
550     if (cExts != consts.end())
551       {
552       for (std::list<Constant>::iterator iconst = cExts->second.begin();
553            iconst != cExts->second.end(); iconst++)
554         {
555         // New versions of the NVIDIA OpenGL headers for Linux can
556         // #define the same constant with the same value in multiple
557         // sections.  This utility will happily parse those and write
558         // out duplicate enums in different enum classes, which
559         // confuses the C++ preprocessor terribly.  Don't write out a
560         // definition for an enum with a name/value pair that's
561         // already been used.
562         if (ConstantsAlreadyWritten.find(std::make_pair(iconst->GetName(),
563                                                            iconst->GetValue()))
564              == ConstantsAlreadyWritten.end())
565           {
566           if(strcmp(iconst->GetName().c_str(),"TIMEOUT_IGNORED")==0)
567             {
568             // BCC/VS6/VS70 cannot digest this C99 macro
569             hfile << "#if !defined(__BORLANDC__) && (!defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER>=1310))" << endl;
570             }
571 
572 
573           hfile << "  const GLenum " << iconst->GetName().c_str()
574                 << " = static_cast<GLenum>(" << iconst->GetValue().c_str() << ");" << endl;
575 
576           ConstantsAlreadyWritten.insert(std::make_pair(iconst->GetName(),
577                                                            iconst->GetValue()));
578           if(strcmp(iconst->GetName().c_str(),"TIMEOUT_IGNORED")==0)
579             {
580             // really special case for non C99 compilers like BCC
581             hfile << "#endif /* only for C99 compilers */" << endl;
582             }
583           }
584         else
585           {
586           hfile << "  /* skipping duplicate " << iconst->GetName().c_str()
587                 << " = " << iconst->GetValue().c_str() << " */" << endl;
588           }
589         }
590       }
591     std::map<Extension, std::list<Typedef> >::iterator tExts
592       = types.find(*iextension);
593     if (tExts != types.end())
594       {
595       for (std::list<Typedef>::iterator itype = tExts->second.begin();
596            itype != tExts->second.end(); itype++)
597         {
598         hfile << "  " << itype->definition.c_str() << endl;
599         }
600       }
601     std::map<Extension, std::list<Function> >::iterator fExts
602       = functs.find(*iextension);
603     if (fExts != functs.end())
604       {
605       for (std::list<Function>::iterator ifunc = fExts->second.begin();
606            ifunc != fExts->second.end(); ifunc++)
607         {
608         hfile << "  extern VTKRENDERINGOPENGL_EXPORT " << ifunc->GetProcType()
609               << " " << ifunc->GetName().c_str() << ";" << endl;
610         }
611       }
612     }
613 }
614 
WriteFunctionPointerDeclarations(ostream & cxxfile,int type)615 static void WriteFunctionPointerDeclarations(ostream &cxxfile, int type)
616 {
617   Extension::WriteSupportWrapperBegin(cxxfile, type);
618   for (std::map<Extension, std::list<Function> >::iterator fExts
619          = functs.begin();
620        fExts != functs.end(); fExts++)
621     {
622     if (fExts->first.type != type) continue;
623     cxxfile << "//Functions for " << fExts->first.GetName().c_str() << endl;
624     for (std::list<Function>::iterator ifunc = fExts->second.begin();
625          ifunc != fExts->second.end(); ifunc++)
626       {
627       cxxfile << "vtk" << Extension::TypeToString(type) << "::"
628               << ifunc->GetProcType()
629               << " vtk" << Extension::TypeToString(type) << "::"
630               << ifunc->GetName().c_str() << " = NULL;" << endl;
631       }
632     }
633   Extension::WriteSupportWrapperEnd(cxxfile, type);
634   cxxfile << endl;
635 }
636 
WriteCode(ostream & hfile,ostream & cxxfile)637 static void WriteCode(ostream &hfile, ostream &cxxfile)
638 {
639   // Write data for header file ---------------------------------
640   hfile << "#ifndef vtkgl_h" << endl
641         << "#define vtkgl_h" << endl << endl;
642   hfile << "#include \"vtkRenderingOpenGLConfigure.h\"" << endl;
643   hfile << "#include \"vtkSystemIncludes.h\"" << endl;
644   hfile << "#include \"vtkWindows.h\"" << endl;
645   hfile << "#include \"vtkOpenGL.h\"" << endl;
646   hfile << "#include <stddef.h>" << endl << endl;
647   hfile << "#ifdef VTK_USE_X" << endl
648         << "/* To prevent glx.h to include glxext.h from the OS */" << endl
649         << "#define GLX_GLXEXT_LEGACY" << endl
650         << "#include <GL/glx.h>" << endl
651         << "#endif" << endl << endl;
652   hfile << "class vtkOpenGLExtensionManager;" << endl << endl;
653   hfile << "#ifndef APIENTRY" << endl
654         << "#define APIENTRY" << endl
655         << "#define VTKGL_APIENTRY_DEFINED" << endl
656         << "#endif" << endl << endl;
657   hfile << "#ifndef APIENTRYP" << endl
658         << "#define APIENTRYP APIENTRY *" << endl
659         << "#define VTKGL_APIENTRYP_DEFINED" << endl
660         << "#endif" << endl << endl;
661 
662   hfile << "/* Undefine all constants to avoid name conflicts.  They should be defined  */" << endl
663         << "/* with GL_, GLX_, or WGL_ preprended to them anyway, but sometimes you run */" << endl
664         << "/* into a header file that gets it wrong.                                   */" << endl;
665   for (std::map<Extension, std::list<Constant> >::iterator constlist
666          = consts.begin();
667        constlist != consts.end(); constlist++)
668     {
669     for (std::list<Constant>::iterator c = (*constlist).second.begin();
670          c != (*constlist).second.end(); c++)
671       {
672       hfile << "#ifdef " << (*c).GetName().c_str() << endl;
673       hfile << "#undef " << (*c).GetName().c_str() << endl;
674       hfile << "#endif" << endl;
675       }
676     }
677 
678   Extension::WriteSupportWrapperBegin(hfile, Extension::GL);
679   hfile << endl << "namespace vtkgl {" << endl;
680   // Add necessary type declarations.
681   hfile << "  //Define int32_t, int64_t, and uint64_t." << endl;
682   hfile << "  typedef vtkTypeInt32 int32_t;" << endl;
683   hfile << "  typedef vtkTypeInt64 int64_t;" << endl;
684   hfile << "  typedef vtkTypeUInt64 uint64_t;" << endl;
685   // OpenGL 3.2 typedefs
686   hfile << "  typedef int64_t GLint64;" << endl;
687   hfile << "  typedef uint64_t GLuint64;" << endl;
688   hfile << "  typedef struct __GLsync *GLsync;" << endl;
689 
690   ConstantsAlreadyWritten.clear();
691   WriteClassDeclarationGuts(hfile, Extension::GL);
692   hfile << endl << "  // Method to load functions for a particular extension.";
693   hfile << endl << "  extern int VTKRENDERINGOPENGL_EXPORT LoadExtension(const char *name, "
694         << "vtkOpenGLExtensionManager *manager);" << endl;
695   hfile << endl << "  // Strings containing special version extensions.";
696   hfile << endl << "  extern VTKRENDERINGOPENGL_EXPORT const char *GLVersionExtensionsString();" << endl;
697   hfile << endl << "  const char *GLXVersionExtensionsString();" << endl;
698   hfile << "}" << endl;
699   Extension::WriteSupportWrapperEnd(hfile, Extension::GL);
700 
701   Extension::WriteSupportWrapperBegin(hfile, Extension::GLX);
702   hfile << "namespace vtkglX {" << endl;
703   // glxext.h is not written very well.  Add some typedefs that may not
704   // be defined.
705   hfile << "  //Miscellaneous definitions." << endl;
706   hfile << "  typedef XID GLXContextID;" << endl;
707   hfile << "  typedef XID GLXPbuffer;" << endl;
708   hfile << "  typedef XID GLXWindow;" << endl;
709   hfile << "  typedef XID GLXFBConfigID;" << endl;
710   hfile << "  typedef struct __GLXFBConfigRec *GLXFBConfig;" << endl;
711   hfile << "  typedef vtkTypeInt32 int32_t;" << endl;
712   hfile << "  typedef vtkTypeInt64 int64_t;" << endl;
713   ConstantsAlreadyWritten.clear();
714   WriteClassDeclarationGuts(hfile, Extension::GLX);
715   hfile << "}" << endl;
716   Extension::WriteSupportWrapperEnd(hfile, Extension::GLX);
717 
718   Extension::WriteSupportWrapperBegin(hfile, Extension::WGL);
719   hfile << "namespace vtkwgl {" << endl;
720   ConstantsAlreadyWritten.clear();
721   WriteClassDeclarationGuts(hfile, Extension::WGL);
722   hfile << "}" << endl;
723   Extension::WriteSupportWrapperEnd(hfile, Extension::WGL);
724 
725   hfile << endl
726         << "#ifdef VTKGL_APIENTRY_DEFINED" << endl
727         << "#undef APIENTRY" << endl
728         << "#endif" << endl << endl;
729   hfile << "#ifdef VTKGL_APIENTRYP_DEFINED" << endl
730         << "#undef APIENTRYP" << endl
731         << "#endif" << endl << endl;
732   hfile << "#endif //_vtkgl_h" << endl;
733 
734   // Write data for C++ file --------------------------------------------
735   cxxfile << "#include \"vtkgl.h\"" << endl;
736   cxxfile << "#include \"vtkOpenGLExtensionManager.h\"" << endl << endl;
737 
738   // Write function pointer declarations.
739   WriteFunctionPointerDeclarations(cxxfile, Extension::GL);
740   WriteFunctionPointerDeclarations(cxxfile, Extension::GLX);
741   WriteFunctionPointerDeclarations(cxxfile, Extension::WGL);
742 
743   std::list<Extension>::iterator iextension;
744 
745   // Write function to load function pointers.
746   cxxfile << "int vtkgl::LoadExtension(const char *name, vtkOpenGLExtensionManager *manager)" << endl
747           << "{" << endl;
748   for (iextension = extensions.begin();
749        iextension != extensions.end(); iextension++)
750     {
751     iextension->WriteSupportWrapperBegin(cxxfile);
752     cxxfile << "  if (strcmp(name, \"" << iextension->GetName().c_str()
753             << "\") == 0)" << endl
754             << "    {" << endl;
755     std::string vtkglclass = "vtk";
756     vtkglclass += Extension::TypeToString(iextension->type);
757     std::list<Function>::iterator ifunct;
758     for (ifunct = functs[*iextension].begin();
759          ifunct != functs[*iextension].end(); ifunct++)
760       {
761       cxxfile << "    " << vtkglclass.c_str() << "::"
762               << ifunct->GetName().c_str() << " = reinterpret_cast<" << vtkglclass.c_str() << "::"
763               << ifunct->GetProcType()
764               << ">(manager->GetProcAddress(\""
765               << Extension::TypeToString(iextension->type)
766               << ifunct->GetName().c_str() << "\"));" << endl;
767       }
768     cxxfile << "    return 1";
769     for (ifunct = functs[*iextension].begin();
770          ifunct != functs[*iextension].end(); ifunct++)
771       {
772       cxxfile << " && (" << vtkglclass.c_str() << "::" << ifunct->GetName().c_str()
773               << " != NULL)";
774       }
775     cxxfile << ";" << endl;
776     cxxfile << "    }" << endl;
777     iextension->WriteSupportWrapperEnd(cxxfile);
778     }
779   cxxfile << "  vtkGenericWarningMacro(<< \"Nothing known about extension \" << name" << endl
780           << "                         << \".  vtkgl may need to be updated.\");" << endl;
781   cxxfile << "  return 0;" << endl
782           << "}" << endl;
783 
784   // Write functions to report special version extension strings.
785   cxxfile << endl << "const char *vtkgl::GLVersionExtensionsString()" << endl
786           << "{" << endl
787           << "  return \"";
788   for (iextension = extensions.begin();
789        iextension != extensions.end(); iextension++)
790     {
791     if (strncmp("GL_VERSION_", iextension->GetName().c_str(), 11) == 0)
792       {
793       cxxfile << iextension->GetName().c_str() << " ";
794       }
795     }
796   cxxfile << "\";" << endl
797           << "}" << endl;
798 
799   cxxfile << endl << "const char *vtkgl::GLXVersionExtensionsString()" << endl
800           << "{" << endl
801           << "  return \"";
802   for (iextension = extensions.begin();
803        iextension != extensions.end(); iextension++)
804     {
805     if (strncmp("GLX_VERSION_", iextension->GetName().c_str(), 12) == 0)
806       {
807       cxxfile << iextension->GetName().c_str() << " ";
808       }
809     }
810   cxxfile << "\";" << endl
811           << "}" << endl;
812 }
813 
main(int argc,char ** argv)814 int main(int argc, char **argv)
815 {
816   if (argc < 3)
817     {
818     cerr << "USAGE: " << argv[0] << "<output dir> <header files>" << endl;
819     return 1;
820     }
821 
822   std::string outputDir = argv[1];
823 
824   for (int i = 2; i < argc; i++)
825     {
826 #ifdef DEBUG_PARSE
827     cerr << "*** Parsing declarations from file " << argv[i] << endl;
828 #endif
829     ifstream file(argv[i]);
830     if (!file)
831       {
832       cerr << "Could not open " << argv[i] << endl;
833       return 2;
834       }
835 
836     while (!file.eof())
837       {
838       static char buf[4096];    // What are the odds of needing more?
839       file.getline(buf, 4096);
840       ParseLine(buf);
841       }
842     file.close();
843     }
844 
845   ofstream hfile((outputDir + "/vtkgl.h").c_str());
846   WriteHeader(hfile, argv[0], argv+1, argc-1);
847   ofstream cxxfile((outputDir + "/vtkgl.cxx").c_str());
848   WriteHeader(cxxfile, argv[0], argv+1, argc-1);
849 
850   WriteCode(hfile, cxxfile);
851 
852   hfile.close();
853   cxxfile.close();
854 
855   return 0;
856 }
857