]> git.cworth.org Git - vogl/blob - src/voglgen/voglgen.cpp
Initial vogl checkin
[vogl] / src / voglgen / voglgen.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 // File: voglgen.cpp
27 // Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
28
29 #include "vogl_core.h"
30 #include "vogl_console.h"
31 #include "vogl_colorized_console.h"
32 #include "vogl_find_files.h"
33 #include "vogl_file_utils.h"
34 #include "vogl_command_line_params.h"
35 #include "vogl_cfile_stream.h"
36 #include "vogl_vector2d.h"
37 #include "vogl_json.h"
38 #include "vogl_vec_interval.h"
39 #include "vogl_radix_sort.h"
40 #include "vogl_regex.h"
41 #include "vogl_hash_map.h"
42 #include <set>
43
44 #include "tinyxml/tinyxml.h"
45
46 #define VOGL_NAMESPACES_HEADER
47 #define VOGL_NAMESPACES_IMPLEMENTATION
48 #include "../voglcommon/vogl_namespaces.h"
49
50 using namespace vogl;
51
52 //-------------------------------------------------------------------------------------------------------------------------------
53 // Command line options
54 //-------------------------------------------------------------------------------------------------------------------------------
55 static command_line_param_desc g_command_line_param_descs[] =
56     {
57         { "debug", 0, false, NULL },
58         { "verbose", 0, false, NULL },
59         { "find", 0, false, NULL },
60         { "func_regex", 1, false, NULL },
61         { "param_regex", 1, false, NULL },
62         { "category_regex", 1, false, NULL },
63         { "ctype_regex", 1, false, NULL },
64         { "namespace_regex", 1, false, NULL },
65         { "srcdir", 1, false, NULL },
66     };
67
68 //-----------------------------------------------------------------------------------------------------------------------
69 // Function prefixes
70 //-------------------------------------------------------------------------------------------------------------------------------
71 enum gl_lib_t
72 {
73     cGL,
74     cGLX,
75     cWGL,
76     cGLU
77 };
78
79 static const char *g_lib_api_prefixes[] =
80     {
81         "gl",
82         "glX",
83         "wgl",
84         "glu"
85     };
86
87 //-------------------------------------------------------------------------------------------------------------------------------
88 // Vendor suffixes
89 //-------------------------------------------------------------------------------------------------------------------------------
90 static const char *g_gl_vendor_suffixes[] =
91     {
92         "NV", "INTEL", "SGIS", "SGIX", "SUN", "NVX", "OES", "AMD", "ATI", "OES", "3DFX", "PGI", "INGR", "IBM"
93     };
94
95 //-------------------------------------------------------------------------------------------------------------------------------
96 // GL/GLX/WGL/etc. function specs
97 //-------------------------------------------------------------------------------------------------------------------------------
98 struct gl_function_param
99 {
100     dynamic_string m_name;
101     dynamic_string m_type;
102     dynamic_string m_ctype;
103     dynamic_string m_ctype_enum;
104     dynamic_string m_direction;
105     dynamic_string m_semantic; // array, reference, value
106     dynamic_string m_array_size;
107     bool m_retained;
108
109     gl_function_param()
110         : m_retained(false)
111     {
112     }
113
114     void clear()
115     {
116         m_name.clear();
117         m_type.clear();
118         m_ctype.clear();
119         m_ctype_enum.clear();
120         m_direction.clear();
121         m_semantic.clear();
122         m_array_size.clear();
123         m_retained = false;
124     }
125
126     void print(FILE *pFile) const
127     {
128         vogl_fprintf(pFile, "Name: \"%s\", Type: \"%s\", Direction: \"%s\", Semantic: \"%s\", ArraySize: \"%s\", Retained: %u\n", m_name.get_ptr(), m_type.get_ptr(), m_direction.get_ptr(), m_semantic.get_ptr(), m_array_size.get_ptr(), m_retained);
129     }
130 };
131
132 //-----------------------------------------------------------------------------------------------------------------------
133 // struct gl_function_def
134 //-----------------------------------------------------------------------------------------------------------------------
135 struct gl_function_def
136 {
137     dynamic_string m_name;      // func name from spec file, without the gl/glx/wgl/etc. prefix
138     dynamic_string m_full_name; // full func name, with prefix
139     vogl::vector<dynamic_string> m_param_names;
140
141     dynamic_string m_return;
142     dynamic_string m_return_ctype;
143     dynamic_string m_return_ctype_enum;
144
145     vogl::vector<gl_function_param> m_params;
146     dynamic_string m_category;
147     dynamic_string m_version;
148     dynamic_string m_profile;
149     dynamic_string m_deprecated;
150     gl_lib_t m_lib;
151     bool m_notlistable;
152
153     gl_function_def()
154     {
155         clear();
156     }
157
158     void clear()
159     {
160         m_name.clear();
161         m_param_names.clear();
162         m_return.clear();
163         m_return_ctype.clear();
164         m_return_ctype_enum.clear();
165         m_params.clear();
166         m_category.clear();
167         m_version.clear();
168         m_profile.clear();
169         m_deprecated.clear();
170         m_lib = cGL;
171         m_notlistable = false;
172     }
173
174     void print(FILE *pFile) const
175     {
176         vogl_fprintf(pFile, "Name: \"%s\", ParamNames: %u, Params: %u, Return: \"%s\", Category: \"%s\", Version: \"%s\", Profile: \"%s\", Deprecated: \"%s\", Lib: \"%s\" notlistable: %u\n",
177                     m_name.get_ptr(),
178                     m_param_names.size(),
179                     m_params.size(),
180                     m_return.get_ptr(),
181                     m_category.get_ptr(),
182                     m_version.get_ptr(),
183                     m_profile.get_ptr(),
184                     m_deprecated.get_ptr(),
185                     g_lib_api_prefixes[m_lib],
186                     m_notlistable);
187
188         if (m_params.size())
189         {
190             for (uint i = 0; i < m_params.size(); i++)
191             {
192                 vogl_fprintf(pFile, "  ");
193                 m_params[i].print(pFile);
194             }
195             vogl_fprintf(pFile, "\n");
196         }
197     }
198
199     dynamic_string get_param_proto() const
200     {
201         dynamic_string proto;
202         for (uint param_index = 0; param_index < m_params.size(); param_index++)
203         {
204             const gl_function_param &param = m_params[param_index];
205
206             proto.format_append("%s%s%s", param.m_ctype.get_ptr(), param.m_ctype.ends_with("*") ? "" : " ", param.m_name.get_ptr());
207             if (param_index != m_params.size() - 1)
208                 proto.format_append(", ");
209         }
210         return proto;
211     }
212
213     dynamic_string get_param_args() const
214     {
215         dynamic_string proto;
216         for (uint param_index = 0; param_index < m_params.size(); param_index++)
217         {
218             proto.format_append("%s", m_params[param_index].m_name.get_ptr());
219             if (param_index != m_params.size() - 1)
220                 proto.format_append(", ");
221         }
222         return proto;
223     }
224
225     const char *get_lib_name() const
226     {
227         return g_lib_api_prefixes[m_lib];
228     }
229 };
230
231 typedef vogl::vector<gl_function_def> gl_function_def_vec;
232
233 //-----------------------------------------------------------------------------------------------------------------------
234 // struct gl_string_key_comparer
235 //-----------------------------------------------------------------------------------------------------------------------
236 struct gl_string_key_comparer
237 {
238     bool operator()(const dynamic_string &lhs, const dynamic_string &rhs) const
239     {
240         return lhs.compare(rhs, true) < 0;
241     }
242 };
243
244 typedef std::map<dynamic_string, dynamic_string, gl_string_key_comparer> gl_string_map;
245 typedef std::set<dynamic_string, gl_string_key_comparer> gl_string_set;
246
247 //-----------------------------------------------------------------------------------------------------------------------
248 // class gl_function_specs
249 //-----------------------------------------------------------------------------------------------------------------------
250 class gl_function_specs
251 {
252 public:
253     gl_function_specs()
254     {
255     }
256
257     void clear()
258     {
259         m_funcs.clear();
260     }
261
262     gl_function_specs &operator+=(const gl_function_specs &other)
263     {
264         m_funcs.append(other.m_funcs);
265         return *this;
266     }
267
268     uint size() const
269     {
270         return m_funcs.size();
271     }
272
273     const gl_function_def &operator[](uint i) const
274     {
275         return m_funcs[i];
276     }
277
278     gl_function_def &operator[](uint i)
279     {
280         return m_funcs[i];
281     }
282
283     const gl_function_def_vec &get_funcs_vec() const
284     {
285         return m_funcs;
286     }
287
288     gl_function_def_vec &get_funcs_vec()
289     {
290         return m_funcs;
291     }
292
293     int find_index(const char *pName) const
294     {
295         for (uint i = 0; i < m_funcs.size(); i++)
296             if (m_funcs[i].m_name.compare(pName, true) == 0)
297                 return i;
298
299         return -1;
300     }
301
302     const gl_function_def *find(const char *pName) const
303     {
304         for (uint i = 0; i < m_funcs.size(); i++)
305             if (m_funcs[i].m_name.compare(pName, true) == 0)
306                 return &m_funcs[i];
307
308         return NULL;
309     }
310
311     bool exists(const char *pName) const
312     {
313         return find(pName) != NULL;
314     }
315
316     void dump_to_file(const char *pFilename) const
317     {
318         FILE *pFile = vogl_fopen(pFilename, "w");
319         if (pFile)
320         {
321             console::info("--- Dumping %u GL function specs to file \"%s\"\n", m_funcs.size(), pFilename);
322
323             vogl_fprintf(pFile, "Functions:\n");
324             for (uint i = 0; i < m_funcs.size(); i++)
325             {
326                 m_funcs[i].print(pFile);
327             }
328
329             vogl_fprintf(pFile, "Categories:\n");
330
331             gl_string_set categories;
332             for (uint i = 0; i < m_funcs.size(); i++)
333                 categories.insert(m_funcs[i].m_category);
334
335             for (gl_string_set::const_iterator it = categories.begin(); it != categories.end(); ++it)
336                 vogl_fprintf(pFile, "\"%s\"\n", it->get_ptr());
337
338             vogl_fclose(pFile);
339         }
340     }
341
342     bool parse_spec_file(const char *pSpec_filename, gl_lib_t default_gl_lib_type)
343     {
344         cfile_stream spec_file(pSpec_filename, cDataStreamReadable);
345         if (!spec_file.is_opened())
346         {
347             console::error("Unable to open file \"%s\"!\n", pSpec_filename);
348             return false;
349         }
350
351         dynamic_string cur_function_def;
352         vogl::vector<dynamic_string> cur_function_param_names;
353         gl_function_def *pCur_func_def = NULL;
354
355         uint max_num_params = 0;
356         uint total_functions = 0;
357
358         dynamic_string line_str;
359         while (spec_file.get_remaining())
360         {
361             if (!spec_file.read_line(line_str))
362                 break;
363
364             line_str.trim_end();
365
366             int comment_ofs = line_str.find_left('#');
367             if (comment_ofs >= 0)
368             {
369                 line_str.truncate(comment_ofs);
370                 line_str.trim_end();
371             }
372
373             if (line_str.is_empty())
374                 continue;
375
376             if (line_str.find_left(':') >= 0)
377             {
378                 cur_function_def.clear();
379                 pCur_func_def = NULL;
380                 cur_function_param_names.clear();
381
382                 continue;
383             }
384
385             //printf("%s\n", line_str.get_ptr());
386
387             int paren_start = line_str.find_left('(');
388             int paren_end = line_str.find_right(')');
389             bool is_func_def = !vogl_isspace(line_str[0]) && ((paren_start >= 0) && (paren_end >= 0) && (paren_end > paren_start));
390
391             if (is_func_def)
392             {
393                 cur_function_def.set(line_str).left(paren_start).trim();
394                 if (cur_function_def.is_empty())
395                 {
396                     console::error("Skipping unrecognized line: %s\n", line_str.get_ptr());
397                     continue;
398                 }
399                 cur_function_def = cur_function_def;
400
401                 dynamic_string param_names(line_str);
402                 param_names.mid(paren_start + 1, paren_end - paren_start - 1).trim();
403
404                 cur_function_param_names.resize(0);
405
406                 int cur_ofs = 0;
407                 while (cur_ofs < (int)param_names.get_len())
408                 {
409                     int next_comma_ofs = param_names.find_left(',', cur_ofs);
410
411                     dynamic_string cur_param_name(param_names);
412                     if (next_comma_ofs < 0)
413                     {
414                         cur_param_name.right(cur_ofs).trim();
415                         cur_ofs = param_names.get_len();
416                     }
417                     else
418                     {
419                         cur_param_name.mid(cur_ofs, next_comma_ofs - cur_ofs).trim();
420                         cur_ofs = next_comma_ofs + 1;
421                     }
422
423                     if (!cur_param_name.is_empty())
424                     {
425                         cur_function_param_names.push_back(cur_param_name);
426                     }
427                     else
428                     {
429                         console::error("Empty parameter name: %s\n", line_str.get_ptr());
430                     }
431                 }
432
433 #if 0
434                                 printf("Function: \"%s\", Params %u:\n", cur_function_def.get_ptr(), cur_function_param_names.size());
435                                 for (uint i = 0; i < cur_function_param_names.size(); i++)
436                                 {
437                                         printf("  %s\n", cur_function_param_names[i].get_ptr());
438                                 }
439                                 printf("\n");
440 #endif
441
442                 max_num_params = math::maximum(max_num_params, cur_function_param_names.size());
443                 total_functions++;
444
445                 pCur_func_def = m_funcs.enlarge(1);
446                 pCur_func_def->m_name = cur_function_def;
447                 pCur_func_def->m_param_names = cur_function_param_names;
448                 pCur_func_def->m_lib = default_gl_lib_type;
449             }
450             else if ((!cur_function_def.is_empty()) && pCur_func_def && vogl_isspace(line_str[0]))
451             {
452                 vogl::vector<dynamic_string> func_attribute_tokens;
453                 line_str.tokenize(" \t", func_attribute_tokens);
454
455                 if (func_attribute_tokens.is_empty())
456                 {
457                     console::error("Skipping unrecognized line: %s\n", line_str.get_ptr());
458                 }
459                 else
460                 {
461                     if (func_attribute_tokens[0] == "return")
462                     {
463                         if (func_attribute_tokens.size() != 2)
464                         {
465                             console::error("Expected return type on line: %s\n", line_str.get_ptr());
466                             return false;
467                         }
468                         pCur_func_def->m_return = func_attribute_tokens[1];
469                     }
470                     else if (func_attribute_tokens[0] == "param")
471                     {
472                         if ((func_attribute_tokens.size() < 5) || (func_attribute_tokens.size() > 7))
473                         {
474                             console::error("Unexpected number of param tokens on line: %s\n", line_str.get_ptr());
475                             return false;
476                         }
477
478                         if ((func_attribute_tokens[3] != "in") && (func_attribute_tokens[3] != "out"))
479                         {
480                             console::error("Unexpected param direction on line: %s\n", line_str.get_ptr());
481                             return false;
482                         }
483
484                         if (func_attribute_tokens[4].find_left("array[") == 0)
485                         {
486                             // special case for glx.spec
487                             int open_bracket = func_attribute_tokens[4].find_left('[');
488                             int close_bracket = func_attribute_tokens[4].find_left(']');
489                             if (open_bracket < close_bracket)
490                             {
491                                 func_attribute_tokens.push_back(dynamic_string(func_attribute_tokens[4]));
492                                 func_attribute_tokens.back().right(open_bracket);
493                                 func_attribute_tokens[4].truncate(open_bracket);
494                             }
495                         }
496
497                         if ((func_attribute_tokens[4] != "value") && (func_attribute_tokens[4] != "array") && (func_attribute_tokens[4] != "reference"))
498                         {
499                             console::error("Unexpected param semantic on line: %s\n", line_str.get_ptr());
500                             return false;
501                         }
502
503                         gl_function_param *pParam = pCur_func_def->m_params.enlarge(1);
504
505                         if (func_attribute_tokens.back() == "retained")
506                         {
507                             pParam->m_retained = true;
508                             func_attribute_tokens.resize(func_attribute_tokens.size() - 1);
509                         }
510
511                         //param         pname           GetTextureParameter in value
512                         //param         params          Float32 out array [COMPSIZE(pname)]
513                         pParam->m_name = func_attribute_tokens[1];
514                         pParam->m_type = func_attribute_tokens[2];
515                         pParam->m_direction = func_attribute_tokens[3];
516                         pParam->m_semantic = func_attribute_tokens[4];
517                         if (pParam->m_semantic == "array")
518                         {
519                             if ((func_attribute_tokens[5][0] != '[') || (func_attribute_tokens[5].back() != ']'))
520                             {
521                                 console::error("Unexpected array size on line: %s\n", line_str.get_ptr());
522                                 return false;
523                             }
524
525                             pParam->m_array_size = func_attribute_tokens[5];
526                             for (;;)
527                             {
528                                 int slash_ofs = pParam->m_array_size.find_left('/');
529                                 if (slash_ofs < 0)
530                                     break;
531                                 pParam->m_array_size.set_char(slash_ofs, ',');
532                             }
533                         }
534                         else if (func_attribute_tokens.size() != 5)
535                         {
536                             console::error("Unexpected number of tokens on line: %s\n", line_str.get_ptr());
537                             return false;
538                         }
539                     }
540                     else if (func_attribute_tokens[0] == "category")
541                     {
542                         pCur_func_def->m_category = func_attribute_tokens[1];
543
544                         if (pCur_func_def->m_category == "gl")
545                             pCur_func_def->m_lib = cGL;
546                         else if (pCur_func_def->m_category == "glX")
547                             pCur_func_def->m_lib = cGLX;
548                         else if (pCur_func_def->m_category == "wgl")
549                             pCur_func_def->m_lib = cWGL;
550                         else if (pCur_func_def->m_category == "glu")
551                             pCur_func_def->m_lib = cGLU;
552                         else
553                         {
554                             // lib is default_gl_lib_type
555                         }
556                     }
557                     else if (func_attribute_tokens[0] == "version")
558                     {
559                         if (func_attribute_tokens.size() != 2)
560                         {
561                             console::error("Invalid version param on line: %s\n", line_str.get_ptr());
562                             return false;
563                         }
564
565                         pCur_func_def->m_version = func_attribute_tokens[1];
566                     }
567                     else if (func_attribute_tokens[0] == "profile")
568                     {
569                         if (func_attribute_tokens.size() != 2)
570                         {
571                             console::error("Invalid profile param on line: %s\n", line_str.get_ptr());
572                             return false;
573                         }
574
575                         pCur_func_def->m_profile = func_attribute_tokens[1];
576                     }
577                     else if (func_attribute_tokens[0] == "deprecated")
578                     {
579                         if (func_attribute_tokens.size() != 2)
580                         {
581                             console::error("Invalid deprecated param on line: %s\n", line_str.get_ptr());
582                             return false;
583                         }
584
585                         pCur_func_def->m_deprecated = func_attribute_tokens[1];
586                     }
587                     else if (func_attribute_tokens[0] == "dlflags")
588                     {
589                         if (func_attribute_tokens.size() != 2)
590                         {
591                             console::error("Invalid dlflags on line: %s\n", line_str.get_ptr());
592                             return false;
593                         }
594
595                         if ((func_attribute_tokens[1] != "notlistable") && (func_attribute_tokens[1] != "handcode") && (func_attribute_tokens[1] != "prepad"))
596                         {
597                             console::error("Unrecognized dlflags on line: %s\n", line_str.get_ptr());
598                             return false;
599                         }
600
601                         pCur_func_def->m_notlistable = (func_attribute_tokens[1] == "notlistable");
602                     }
603                 }
604             }
605             else
606             {
607                 console::error("Skipping unrecognized line: %s\n", line_str.get_ptr());
608             }
609         }
610
611         for (uint i = 0; i < m_funcs.size(); i++)
612         {
613             m_funcs[i].m_full_name.format("%s%s", g_lib_api_prefixes[m_funcs[i].m_lib], m_funcs[i].m_name.get_ptr());
614         }
615
616         return true;
617     }
618
619     bool parse_gl_xml_file(const char *pFilename)
620     {
621         TiXmlDocument gl_xml;
622         if (!gl_xml.LoadFile(pFilename))
623         {
624             console::error("Failed loading %s!\n", pFilename);
625             return false;
626         }
627
628         const TiXmlElement *pRoot = gl_xml.RootElement();
629         const char *pName = pRoot->Attribute("name");
630         if ((!pName) || (strcmp(pName, "gl")))
631         {
632             console::error("Invalid root element in %s!\n", pFilename);
633             return false;
634         }
635
636         const TiXmlElement *pLibraries = pRoot->FirstChildElement("libraries");
637         const TiXmlElement *pExtensions = pRoot->FirstChildElement("extensions");
638         if ((!pLibraries) || (!pExtensions))
639         {
640             console::error("Couldn't find libraries and/or extensions elements in %s!\n", pFilename);
641             return false;
642         }
643
644         const TiXmlElement *pLibrary = pLibraries->FirstChildElement();
645         while (pLibrary)
646         {
647             const char *pName = pLibrary->Attribute("name");
648             if (pName)
649             {
650                 if (!parse_gl_xml_function_defs(pFilename, pName, pLibrary->FirstChildElement()))
651                     return false;
652             }
653
654             pLibrary = pLibrary->NextSiblingElement();
655         }
656
657         const TiXmlElement *pCur_extension = pExtensions->FirstChildElement();
658         while (pCur_extension)
659         {
660             const char *pExt_name = pCur_extension->Attribute("name");
661             if (!pExt_name)
662             {
663                 console::error("Couldn't find extension name attribute in %s!\n", pFilename);
664                 return false;
665             }
666
667             if (!parse_gl_xml_function_defs(pFilename, pExt_name, pCur_extension->FirstChildElement()))
668                 return false;
669
670             pCur_extension = pCur_extension->NextSiblingElement();
671         }
672
673         return true;
674     }
675
676 protected:
677     gl_function_def_vec m_funcs;
678
679     bool parse_gl_xml_function_defs(const char *pFilename, const char *pCategory, const TiXmlElement *pFunctions)
680     {
681         while (pFunctions)
682         {
683             if ((pFunctions->Value()) && (strcmp(pFunctions->Value(), "functions") == 0))
684             {
685                 const TiXmlElement *pFunction = pFunctions->FirstChildElement();
686                 while (pFunction)
687                 {
688                     if ((pFunction->Value()) && (strcmp(pFunction->Value(), "function") == 0))
689                     {
690                         const char *pType = pFunction->Attribute("type");
691                         const char *pName = pFunction->Attribute("name");
692                         if ((!pType) || (!pName))
693                         {
694                             console::error("Expected function name and type in file %s\n", pFilename);
695                             return false;
696                         }
697
698                         gl_function_def gl_func;
699
700                         gl_func.clear();
701                         gl_func.m_full_name = pName;
702                         gl_func.m_name = pName;
703
704                         if (gl_func.m_name.begins_with("glX", true))
705                         {
706                             gl_func.m_name.right(3);
707                             gl_func.m_lib = cGLX;
708                         }
709                         else if (gl_func.m_name.begins_with("glu", true))
710                         {
711                             gl_func.m_name.right(3);
712                             gl_func.m_lib = cGLU;
713                         }
714                         else if (gl_func.m_name.begins_with("wgl", true))
715                         {
716                             gl_func.m_name.right(3);
717                             gl_func.m_lib = cWGL;
718                         }
719                         else if (gl_func.m_name.begins_with("gl", true))
720                         {
721                             gl_func.m_name.right(2);
722                             gl_func.m_lib = cGL;
723                         }
724                         else
725                         {
726                             //console::warning("Unknown function prefix from XML, assuming \"gl\": %s\n", gl_func.m_name.get_ptr());
727                             gl_func.m_lib = cGL;
728                             gl_func.m_full_name.format("%s%s", "gl", pName);
729                         }
730
731                         gl_func.m_category = pCategory;
732                         gl_func.m_return = pType;
733
734                         const TiXmlElement *pParams = pFunction->FirstChildElement();
735                         while (pParams)
736                         {
737                             if (strcmp(pParams->Value(), "param") == 0)
738                             {
739                                 const char *pParam_type = pParams->Attribute("type");
740                                 const char *pParam_name = pParams->Attribute("name");
741                                 if ((!pParam_type) || (!pParam_name))
742                                 {
743                                     console::error("Expected parameter type and name in file %s\n", pFilename);
744                                     return false;
745                                 }
746
747                                 gl_function_param param;
748                                 param.clear();
749                                 param.m_name = pParam_name;
750                                 param.m_type = pParam_type;
751                                 gl_func.m_params.push_back(param);
752                             }
753                             pParams = pParams->NextSiblingElement();
754                         }
755
756                         if ((gl_func.m_params.size() == 1) && (gl_func.m_params[0].m_type == "") && (gl_func.m_params[0].m_name == "void"))
757                             gl_func.m_params.resize(0);
758
759                         m_funcs.push_back(gl_func);
760                     }
761
762                     pFunction = pFunction->NextSiblingElement();
763                 }
764             }
765
766             pFunctions = pFunctions->NextSiblingElement();
767         }
768
769         return true;
770     }
771 };
772
773 //-----------------------------------------------------------------------------------------------------------------------
774 // apitrace glapi.py parsing
775 //-----------------------------------------------------------------------------------------------------------------------
776 static const struct
777 {
778     const char *m_pSpec_return_type;
779     const char *m_pApitrace_return_type;
780     vogl_namespace_t m_namespace;
781 } g_apitrace_return_type_aliases[] =
782       {
783           { "void", "Void", VOGL_NAMESPACE_INVALID },
784           { "GLenum", "GLenum_error", VOGL_NAMESPACE_INVALID },
785           { "const GLubyte *", "String(Const(GLubyte))", VOGL_NAMESPACE_INVALID },
786           { "GLuint", "Handle(\"list\", GLuint, \"range\")", VOGL_NAMESPACE_LISTS },
787           { "GLint", "Alias(\"GLint\", GLenum)", VOGL_NAMESPACE_INVALID },
788           { "GLvoid*", "GLmap", VOGL_NAMESPACE_INVALID },
789           { "GLuint", "GLprogram", VOGL_NAMESPACE_PROGRAMS },
790           { "GLuint", "GLshader", VOGL_NAMESPACE_SHADERS },
791           { "GLint", "GLlocation", VOGL_NAMESPACE_LOCATIONS },
792           { "GLubyte *", "String(Const(GLubyte))", VOGL_NAMESPACE_INVALID },
793           { "GLint", "GLlocationARB", VOGL_NAMESPACE_LOCATIONS },
794           { "GLuint", "Handle(\"fragmentShaderATI\", GLuint, \"range\")", VOGL_NAMESPACE_FRAGMENT_SHADER_ATI }
795       };
796
797 const uint APITRACE_RETURN_TYPE_ALIASES_ARRAY_SIZE = sizeof(g_apitrace_return_type_aliases) / sizeof(g_apitrace_return_type_aliases[0]);
798
799 //-----------------------------------------------------------------------------------------------------------------------
800 // g_apitrace_param_type_aliases array
801 //-----------------------------------------------------------------------------------------------------------------------
802
803 static const struct
804 {
805     const char *m_pSpec_type;
806     const char *m_pApitrace_type;
807 } g_apitrace_param_type_aliases[] =
808       {
809           { "GLbitfield", "GLbitfield_access" },
810           { "GLbitfield", "GLbitfield_attrib" },
811           { "GLbitfield", "GLbitfield_barrier" },
812           { "GLbitfield", "GLbitfield_client_attrib" },
813           { "GLbitfield", "GLbitfield_shader" },
814           { "GLbitfield", "GLbitfield_sync_flush" },
815           { "GLuint", "GLpipeline" },
816           { "GLuint", "GLarray" },
817           { "GLuint", "GLarrayAPPLE" },
818           { "GLuint", "GLbuffer" },
819           { "GLuint", "GLfeedback" },
820           { "GLuint", "GLfence" },
821           { "GLuint", "GLframebuffer" },
822           { "GLuint", "GLpipeline" },
823           { "GLuint", "GLprogramARB" },
824           { "GLuint", "GLquery" },
825           { "GLuint", "GLrenderbuffer" },
826           { "GLuint", "GLsampler" },
827           { "GLuint", "GLtexture" },
828           { "GLuint", "GLarray" },
829           { "GLuint", "GLarrayAPPLE" },
830           { "GLuint", "GLbuffer" },
831           { "GLuint", "GLfeedback" },
832           { "GLuint", "GLfence" },
833           { "GLuint", "GLfragmentShaderATI" },
834           { "GLuint", "GLframebuffer" },
835           { "GLuint", "GLlist" },
836           { "GLuint", "GLpipeline" },
837           { "GLuint", "GLprogram" },
838           { "GLuint", "GLprogramARB" },
839           { "GLuint", "GLquery" },
840           { "GLuint", "GLrenderbuffer" },
841           { "GLuint", "GLsampler" },
842           { "GLuint", "GLshader" },
843           { "GLuint", "GLtexture" },
844           { "GLvoid *", "GLpointer" },
845           { "GLvoid", "GLIndexBuffer" },
846           { "GLchar *", "GLstring" },
847           { "const GLvoid *", "GLpointerConst" },
848           { "GLhalf", "GLhalfNV" },
849           { "const GLchar *", "GLstringConst" },
850           { "const GLchar *", "GLstringConstARB" },
851           { "GLchar *", "GLstringARB" },
852           { "GLchar", "GLcharARB" },
853           { "GLint", "GLlocation" },
854           { "GLint", "GLlocationARB" },
855           { "GLenum", "GLenum_int" },
856           { "GLint", "size_bgra" },
857           { "GLenum", "GLenum_mode" },
858       };
859
860 static const uint APITRACE_PARAM_TYPE_ALIASES_ARRAY_SIZE = sizeof(g_apitrace_param_type_aliases) / sizeof(g_apitrace_param_type_aliases[0]);
861
862 //-----------------------------------------------------------------------------------------------------------------------
863 // struct apitrace_gl_func_param_def
864 //-----------------------------------------------------------------------------------------------------------------------
865 struct apitrace_gl_func_param_def
866 {
867     apitrace_gl_func_param_def()
868     {
869         clear();
870     }
871
872     void clear()
873     {
874         m_name.clear();
875         m_type.clear();
876         m_gl_type.clear();
877
878         m_array_count_str.clear();
879         m_index_count_str.clear();
880         m_string_count_str.clear();
881         m_index_type_str.clear();
882
883         m_is_out = false;
884         m_is_pointer = false;
885         m_is_const = false;
886         m_is_opaque = false;
887         m_is_array = false;
888         m_is_blob = false;
889         m_is_index_buffer = false;
890         m_is_string = false;
891         m_is_opaque_ctype = false;
892     }
893
894     dynamic_string m_name;
895     dynamic_string m_type;
896     dynamic_string m_gl_type; // actual C type (but without const stuff)
897     vogl_namespace_t m_namespace;
898
899     dynamic_string m_array_count_str;
900     dynamic_string m_index_count_str;
901     dynamic_string m_string_count_str;
902     dynamic_string m_index_type_str;
903
904     bool m_is_out;
905     bool m_is_pointer;
906     bool m_is_const;
907     bool m_is_opaque;
908     bool m_is_array;
909     bool m_is_blob;
910     bool m_is_index_buffer;
911     bool m_is_string;
912     bool m_is_opaque_ctype;
913 };
914
915 typedef vogl::vector<apitrace_gl_func_param_def> apitrace_gl_func_param_def_array;
916
917 //-----------------------------------------------------------------------------------------------------------------------
918 // struct apitrace_gl_func_def
919 //-----------------------------------------------------------------------------------------------------------------------
920 struct apitrace_gl_func_def
921 {
922     apitrace_gl_func_def()
923     {
924         clear();
925     }
926
927     void clear()
928     {
929         m_name.clear();
930         m_return_type.clear();
931         m_return_gl_type.clear();
932         m_has_side_effects = false;
933         m_params.clear();
934     }
935
936     dynamic_string m_name;
937     dynamic_string m_return_type;
938     dynamic_string m_return_gl_type; // actual C type (but without const stuff)
939     vogl_namespace_t m_return_namespace;
940
941     bool m_has_side_effects;
942     apitrace_gl_func_param_def_array m_params;
943 };
944
945 typedef vogl::vector<apitrace_gl_func_def> apitrace_gl_func_def_array;
946
947 //-----------------------------------------------------------------------------------------------------------------------
948 // class apitrace_func_specs
949 //-----------------------------------------------------------------------------------------------------------------------
950
951 //#define APITRACE_FUNC_SPECS_DEBUG
952
953 class apitrace_func_specs
954 {
955 public:
956     apitrace_func_specs()
957     {
958     }
959
960     void clear()
961     {
962         m_funcs.clear();
963     }
964
965     uint size() const
966     {
967         return m_funcs.size();
968     }
969
970     const apitrace_gl_func_def &operator[](uint i) const
971     {
972         return m_funcs[i];
973     }
974
975     apitrace_gl_func_def &operator[](uint i)
976     {
977         return m_funcs[i];
978     }
979
980     const apitrace_gl_func_def_array &get_funcs_vec() const
981     {
982         return m_funcs;
983     }
984
985     apitrace_gl_func_def_array &get_funcs_vec()
986     {
987         return m_funcs;
988     }
989
990     int find_index(const char *pName) const
991     {
992         for (uint i = 0; i < m_funcs.size(); i++)
993             if (m_funcs[i].m_name.compare(pName, true) == 0)
994                 return i;
995
996         return -1;
997     }
998
999     const apitrace_gl_func_def *find(const char *pName) const
1000     {
1001         for (uint i = 0; i < m_funcs.size(); i++)
1002             if (m_funcs[i].m_name.compare(pName, true) == 0)
1003                 return &m_funcs[i];
1004
1005         return NULL;
1006     }
1007
1008     bool exists(const char *pName) const
1009     {
1010         return find(pName) != NULL;
1011     }
1012
1013     // Yes this guy is ugly, but it's simple and works on the unmodified Python source glapi.py from apitrace.
1014     // glapi.py was automatically generated, then hand edited. It contains a lot of useful type and array size info, but is still
1015     // incomplete (see glReadPixels() for example, which is missing its array size).
1016     bool parse(const char *pFilename = "apitrace_gl_param_info.txt")
1017     {
1018         clear();
1019
1020         dynamic_string_array param_info_file;
1021         if (!file_utils::read_text_file(pFilename, param_info_file, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintErrorMessages))
1022             return false;
1023
1024         dynamic_string_array unique_types;
1025         dynamic_string_array unique_array_counts;
1026
1027         for (uint line_index = 0; line_index < param_info_file.size(); line_index++)
1028         {
1029             const dynamic_string &orig_line(param_info_file[line_index]);
1030             dynamic_string line(orig_line);
1031
1032             if (line.begins_with("#"))
1033                 continue;
1034
1035             int comment_ofs = line.find_right('#');
1036             if (comment_ofs >= 0)
1037                 line.left(comment_ofs).trim();
1038
1039             if (!line.begins_with("GlFunction("))
1040                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1041
1042             line.replace("GlFunction(", "", true, NULL, 1);
1043
1044             if (line.ends_with(","))
1045                 line.shorten(1);
1046
1047             if (!line.ends_with(")"))
1048                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1049
1050             dynamic_string return_type;
1051
1052             int first_comma = line.find_left(',');
1053             if (first_comma < 0)
1054                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1055
1056             int first_paren = line.find_left('(');
1057             if ((first_paren >= 0) && (first_paren < first_comma))
1058             {
1059                 int matching_paren = find_matching_paren(line, first_paren);
1060                 if (matching_paren < 0)
1061                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1062
1063                 return_type = dynamic_string(line).left(matching_paren + 1);
1064                 line.right(matching_paren + 1).trim();
1065                 if (!line.begins_with(","))
1066                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1067
1068                 line.right(1).trim();
1069             }
1070             else
1071             {
1072                 return_type = dynamic_string(line).left(first_comma);
1073                 line.right(first_comma + 1).trim();
1074             }
1075
1076             if (!line.begins_with("\""))
1077                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1078
1079             int end_quote_ofs = line.find_left('\"', 1);
1080             if (end_quote_ofs < 0)
1081                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1082
1083             dynamic_string func_name(line);
1084             func_name.substring(1, end_quote_ofs);
1085
1086             line.right(end_quote_ofs + 1).trim();
1087             if (!line.begins_with(","))
1088                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1089             line.right(1).trim();
1090
1091             if (!line.begins_with("["))
1092                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1093
1094             int params_end = find_matching_paren(line, 0, '[', ']');
1095             if (params_end < 0)
1096                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1097
1098             dynamic_string params(line);
1099             params.substring(1, params_end);
1100
1101             line.right(params_end + 1).trim();
1102
1103             if ((!line.begins_with(",") && !line.begins_with(")")) || !line.ends_with(")"))
1104                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1105
1106             bool func_has_side_effects = true;
1107             if (line.contains("sideeffects=False"))
1108                 func_has_side_effects = false;
1109
1110             apitrace_gl_func_def func_def;
1111             func_def.m_name = func_name;
1112             func_def.m_has_side_effects = func_has_side_effects;
1113             func_def.m_return_type = return_type;
1114
1115             func_def.m_return_gl_type = return_type;
1116
1117             uint a;
1118             for (a = 0; a < APITRACE_RETURN_TYPE_ALIASES_ARRAY_SIZE; a++)
1119             {
1120                 if (func_def.m_return_gl_type == g_apitrace_return_type_aliases[a].m_pApitrace_return_type)
1121                 {
1122                     func_def.m_return_gl_type = g_apitrace_return_type_aliases[a].m_pSpec_return_type;
1123                     func_def.m_return_namespace = g_apitrace_return_type_aliases[a].m_namespace;
1124                     break;
1125                 }
1126             }
1127             if (a == APITRACE_RETURN_TYPE_ALIASES_ARRAY_SIZE)
1128             {
1129                 func_def.m_return_namespace = vogl_find_namespace_from_gl_type(func_def.m_return_gl_type.get_ptr());
1130                 if (func_def.m_return_namespace == VOGL_NAMESPACE_INVALID)
1131                 {
1132 // TODO: Here's the list of return/param types that can't be mapped right now - make exception list?
1133 #if 0
1134                                         size_bgra
1135                                         const GLboolean *
1136                                         Void
1137                                         GLvoid
1138                                         GLushort
1139                                         GLuint64EXT
1140                                         GLuint64
1141                                         GLuint
1142                                         GLubyte
1143                                         GLstringConstARB
1144                                         GLstringConst
1145                                         GLstringARB
1146                                         GLstring
1147                                         GLsizeiptrARB
1148                                         GLsizeiptr
1149                                         GLsizei
1150                                         GLshort
1151                                         GLregion
1152                                         GLpointerConst
1153                                         GLpointer
1154                                         GLintptrARB
1155                                         GLintptr
1156                                         GLint64EXT
1157                                         GLint64
1158                                         GLint
1159                                         GLhalfNV
1160                                         GLfloat
1161                                         GLenum_mode
1162                                         GLenum_int
1163                                         GLenum
1164                                         GLdouble
1165                                         GLclampf
1166                                         GLclampd
1167                                         GLcharARB
1168                                         GLchar
1169                                         GLbyte
1170                                         GLboolean
1171                                         GLbitfield_sync_flush
1172                                         GLbitfield_shader
1173                                         GLbitfield_client_attrib
1174                                         GLbitfield_barrier
1175                                         GLbitfield_attrib
1176                                         GLbitfield_access
1177                                         GLbitfield
1178                                         GLIndexBuffer
1179                                         GLDEBUGPROCARB
1180                                         GLDEBUGPROCAMD
1181                                         GLDEBUGPROC
1182 #endif
1183
1184                     //console::warning("%s: Couldn't map namespace %s\n", VOGL_METHOD_NAME, func_def.m_return_gl_type.get_ptr());
1185                 }
1186             }
1187
1188 #ifdef APITRACE_FUNC_SPECS_DEBUG
1189             printf("--- Func: %s\nReturn Type: %s, HasSideEffects: %u, Namespace: %s\n", func_name.get_ptr(), return_type.get_ptr(), func_has_side_effects, vogl_get_namespace_name(func_def.m_return_namespace));
1190 #endif
1191
1192             for (;;)
1193             {
1194                 bool is_out = false;
1195                 bool is_pointer = false;
1196                 bool is_const = false;
1197                 bool is_opaque = false;
1198                 bool is_array = false;
1199                 bool is_blob = false;
1200                 bool is_index_buffer = false;
1201                 bool is_string = false;
1202                 bool is_opaque_ctype = false;
1203                 dynamic_string array_count_str;
1204                 dynamic_string index_count_str;
1205                 dynamic_string string_count_str;
1206                 dynamic_string index_type_str;
1207
1208                 if (params.is_empty())
1209                     break;
1210
1211                 if (params.begins_with("Out("))
1212                     is_out = true;
1213                 else if (!params.begins_with("("))
1214                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1215
1216                 int first_paren = params.find_left("(");
1217                 if (first_paren < 0)
1218                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1219
1220                 int param_end_ofs = find_matching_paren(params, first_paren);
1221                 if (param_end_ofs < 0)
1222                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1223
1224                 dynamic_string cur_param;
1225                 cur_param = params;
1226                 cur_param.substring(first_paren + 1, param_end_ofs);
1227
1228                 params.right(param_end_ofs + 1).trim();
1229                 if (params.begins_with(","))
1230                     params.right(1).trim();
1231
1232                 int right_comma = cur_param.find_right(",");
1233                 if (right_comma < 0)
1234                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1235
1236                 dynamic_string param_name(cur_param);
1237                 param_name.right(right_comma + 1).trim();
1238                 cur_param.left(right_comma).trim();
1239
1240                 int paren_ofs;
1241                 while ((paren_ofs = cur_param.find_left('(')) >= 0)
1242                 {
1243                     bool get_count_string = false;
1244                     bool count_string_is_optional = false;
1245                     dynamic_string *pCount_str = &array_count_str;
1246
1247                     if (cur_param.begins_with("Out("))
1248                         is_out = true;
1249                     else if (cur_param.begins_with("Pointer("))
1250                         is_pointer = true;
1251                     else if (cur_param.begins_with("OpaquePointer("))
1252                     {
1253                         is_opaque = true;
1254                         is_pointer = true;
1255                     }
1256                     else if (cur_param.begins_with("Const("))
1257                         is_const = true;
1258                     else if (cur_param.begins_with("OpaqueBlob("))
1259                     {
1260                         is_opaque = true;
1261                         is_blob = true;
1262                         get_count_string = true;
1263                     }
1264                     else if (cur_param.begins_with("Blob("))
1265                     {
1266                         is_blob = true;
1267                         get_count_string = true;
1268                     }
1269                     else if (cur_param.begins_with("GLIndexBuffer("))
1270                     {
1271                         is_index_buffer = true;
1272                         get_count_string = true;
1273                         pCount_str = &index_count_str;
1274                     }
1275                     else if (cur_param.begins_with("OpaqueArray("))
1276                     {
1277                         is_opaque = true;
1278                         is_array = true;
1279                         get_count_string = true;
1280                     }
1281                     else if (cur_param.begins_with("Array("))
1282                     {
1283                         is_array = true;
1284                         get_count_string = true;
1285                     }
1286                     else if (cur_param.begins_with("String("))
1287                     {
1288                         is_string = true;
1289                         get_count_string = true;
1290                         count_string_is_optional = true;
1291                         pCount_str = &string_count_str;
1292                     }
1293                     else if (cur_param.begins_with("Opaque("))
1294                     {
1295                         is_opaque_ctype = true;
1296                     }
1297                     else
1298                         return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1299
1300                     int end_paren_ofs = find_matching_paren(cur_param, paren_ofs);
1301                     if (end_paren_ofs < 0)
1302                         return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1303
1304                     cur_param.substring(paren_ofs + 1, end_paren_ofs);
1305
1306                     if (get_count_string)
1307                     {
1308                         if (cur_param.ends_with("\""))
1309                         {
1310                             int start_of_count = cur_param.find_right('\"', cur_param.get_len() - 2);
1311                             if (start_of_count < 0)
1312                                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1313
1314                             if (!pCount_str->is_empty())
1315                                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1316
1317                             *pCount_str = cur_param;
1318                             pCount_str->right(start_of_count).trim();
1319
1320                             cur_param.left(start_of_count).trim();
1321                             if (!cur_param.ends_with(","))
1322                                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1323
1324                             cur_param.shorten(1).trim();
1325                         }
1326                         else
1327                         {
1328                             int comma_ofs = cur_param.find_right(',');
1329                             if ((comma_ofs < 0) && (!count_string_is_optional))
1330                                 return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1331
1332                             if (comma_ofs >= 0)
1333                             {
1334                                 if (!pCount_str->is_empty())
1335                                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1336                                 *pCount_str = cur_param;
1337                                 pCount_str->right(comma_ofs + 1).trim();
1338
1339                                 cur_param.left(comma_ofs).trim();
1340                             }
1341                         }
1342                     }
1343
1344                     if (is_index_buffer)
1345                     {
1346                         index_type_str = *pCount_str;
1347                         *pCount_str = cur_param;
1348                         cur_param.truncate(0);
1349                         if (index_type_str.contains('(') || index_type_str.contains(','))
1350                             return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1351                         break;
1352                     }
1353                 }
1354
1355                 if (is_index_buffer)
1356                     cur_param = "GLIndexBuffer";
1357
1358                 if (cur_param.is_empty())
1359                     return parse_apitrace_gl_param_info_error(param_info_file, line_index);
1360
1361                 if (unique_types.find(cur_param) < 0)
1362                     unique_types.push_back(cur_param);
1363
1364                 if (unique_array_counts.find(array_count_str) < 0)
1365                     unique_array_counts.push_back(array_count_str);
1366
1367                 apitrace_gl_func_param_def param_def;
1368                 param_def.m_name = param_name;
1369                 param_def.m_type = cur_param;
1370                 param_def.m_array_count_str = array_count_str;
1371                 param_def.m_index_count_str = index_count_str;
1372                 param_def.m_string_count_str = string_count_str;
1373                 param_def.m_index_type_str = index_type_str;
1374                 param_def.m_is_out = is_out;
1375                 param_def.m_is_pointer = is_pointer;
1376                 param_def.m_is_const = is_const;
1377                 param_def.m_is_opaque = is_opaque;
1378                 param_def.m_is_array = is_array;
1379                 param_def.m_is_blob = is_blob;
1380                 param_def.m_is_index_buffer = is_index_buffer;
1381                 param_def.m_is_string = is_string;
1382                 param_def.m_is_opaque_ctype = is_opaque_ctype;
1383
1384                 dynamic_string gl_param_type(param_def.m_type);
1385
1386                 if (param_def.m_is_opaque_ctype)
1387                     gl_param_type.unquote();
1388
1389                 param_def.m_namespace = vogl_find_namespace_from_gl_type(gl_param_type.get_ptr());
1390                 if (param_def.m_namespace == VOGL_NAMESPACE_INVALID)
1391                 {
1392                     //console::warning("%s: Couldn't map namespace %s\n", VOGL_METHOD_NAME, gl_param_type.get_ptr());
1393                 }
1394
1395                 for (uint k = 0; k < APITRACE_PARAM_TYPE_ALIASES_ARRAY_SIZE; k++)
1396                 {
1397                     if (gl_param_type == g_apitrace_param_type_aliases[k].m_pApitrace_type)
1398                     {
1399                         gl_param_type = g_apitrace_param_type_aliases[k].m_pSpec_type;
1400                         break;
1401                     }
1402                 }
1403
1404                 if ((param_def.m_is_string) || (param_def.m_is_index_buffer))
1405                     gl_param_type.append(" *");
1406
1407                 if ((param_def.m_is_array) || (param_def.m_is_blob) || (param_def.m_is_pointer))
1408                 {
1409                     gl_param_type.append(" *");
1410                 }
1411
1412                 param_def.m_gl_type = gl_param_type;
1413
1414 #ifdef APITRACE_FUNC_SPECS_DEBUG
1415                 printf("Name: %s, Type: %s, Out: %u, Pointer: %u, Const: %u, IsOpaque: %u, Array: %u, Blob: %u, IndexBuf: %u, String: %u, OpaqueCType: %u, Namespace: %s\n",
1416                        param_name.get_ptr(),
1417                        cur_param.get_ptr(),
1418                        is_out, is_pointer, is_const, is_opaque, is_array, is_blob, is_index_buffer, is_string, is_opaque_ctype, vogl_get_namespace_name(param_def.m_namespace));
1419                 if (array_count_str.get_len())
1420                     printf("   ArrayCountStr: %s\n", array_count_str.get_ptr());
1421                 if (index_count_str.get_len())
1422                     printf("   IndexCountStr: %s\n", index_count_str.get_ptr());
1423                 if (string_count_str.get_len())
1424                     printf("   StringCountStr: %s\n", string_count_str.get_ptr());
1425                 if (index_type_str.get_len())
1426                     printf("   IndexTypeStr: %s\n", index_type_str.get_ptr());
1427 #endif
1428
1429                 func_def.m_params.push_back(param_def);
1430             }
1431
1432             m_funcs.push_back(func_def);
1433
1434 #ifdef APITRACE_FUNC_SPECS_DEBUG
1435             printf("\n\n");
1436 #endif
1437         }
1438
1439 #ifdef APITRACE_FUNC_SPECS_DEBUG
1440         printf("Unique types:\n");
1441         unique_types.sort();
1442         for (uint i = 0; i < unique_types.size(); i++)
1443             printf("%s\n", unique_types[i].get_ptr());
1444
1445         printf("\n");
1446
1447         printf("Unique array counts:\n");
1448         unique_array_counts.sort();
1449         for (uint i = 0; i < unique_array_counts.size(); i++)
1450             printf("%s\n", unique_array_counts[i].get_ptr());
1451 #endif
1452
1453         return true;
1454     }
1455
1456 private:
1457     apitrace_gl_func_def_array m_funcs;
1458
1459     bool parse_apitrace_gl_param_info_error(const dynamic_string_array &param_info_file, uint line_index)
1460     {
1461         console::error("Unrecognized line: %s\n", param_info_file[line_index].get_ptr());
1462         return false;
1463     }
1464
1465     static int find_matching_paren(const dynamic_string &str, uint ofs, uint open_char = '(', uint close_char = ')')
1466     {
1467         bool in_quoted_string = false;
1468         uint param_count = 0;
1469
1470         while (ofs < str.get_len())
1471         {
1472             uint c = str[ofs];
1473
1474             if (in_quoted_string)
1475             {
1476                 if (c == '"')
1477                 {
1478                     in_quoted_string = false;
1479                 }
1480             }
1481             else if (c == '"')
1482             {
1483                 in_quoted_string = true;
1484             }
1485             else if (c == open_char)
1486                 param_count++;
1487             else if (c == close_char)
1488             {
1489                 param_count--;
1490                 if (!param_count)
1491                     return ofs;
1492             }
1493
1494             ofs++;
1495         }
1496
1497         return -1;
1498     }
1499 };
1500
1501 //-----------------------------------------------------------------------------------------------------------------------
1502 // class gl_types
1503 //-----------------------------------------------------------------------------------------------------------------------
1504 class gl_types
1505 {
1506 public:
1507     gl_types()
1508     {
1509     }
1510
1511     void clear()
1512     {
1513         m_tm.clear();
1514     }
1515
1516     const gl_string_map &get_type_map() const
1517     {
1518         return m_tm;
1519     }
1520     gl_string_map &get_type_map()
1521     {
1522         return m_tm;
1523     }
1524
1525     uint size() const
1526     {
1527         return static_cast<uint>(m_tm.size());
1528     }
1529
1530     bool is_present(const dynamic_string &type_str) const
1531     {
1532         return m_tm.find(type_str) != m_tm.end();
1533         //return false;
1534     }
1535
1536     const dynamic_string *find(const dynamic_string &type_str) const
1537     {
1538         gl_string_map::const_iterator it(m_tm.find(type_str));
1539         if (it == m_tm.end())
1540             return NULL;
1541         return &it->second;
1542     }
1543
1544     bool parse_file(const char *pFilename)
1545     {
1546         cfile_stream tm_file(pFilename, cDataStreamReadable);
1547         if (!tm_file.is_opened())
1548         {
1549             console::error("Unable to open file \"%s\"!\n", pFilename);
1550             return false;
1551         }
1552
1553         dynamic_string line_str;
1554         while (tm_file.get_remaining())
1555         {
1556             if (!tm_file.read_line(line_str))
1557                 break;
1558
1559             line_str.trim_end();
1560
1561             int comment_ofs = line_str.find_left('#');
1562             if (comment_ofs >= 0)
1563             {
1564                 line_str.truncate(comment_ofs);
1565                 line_str.trim_end();
1566             }
1567
1568             if (line_str.is_empty())
1569                 continue;
1570
1571             // AccumOp,*,*,                         GLenum,*,*
1572
1573             dynamic_string_array tokens;
1574             line_str.tokenize(",", tokens);
1575             if (tokens.size() != 6)
1576             {
1577                 console::error("Unexpected number of tokens on line: %s\n", line_str.get_ptr());
1578                 return false;
1579             }
1580
1581             for (uint i = 0; i < tokens.size(); i++)
1582                 tokens[i].trim();
1583
1584             if ((tokens[0].is_empty()) || (tokens[1] != "*") || (tokens[2] != "*") ||
1585                 (tokens[3].is_empty()) || (tokens[4] != "*") || (tokens[5] != "*"))
1586             {
1587                 console::error("Unexpected token on line: %s\n", line_str.get_ptr());
1588                 return false;
1589             }
1590
1591             if (m_tm.find(tokens[0]) != m_tm.end())
1592             {
1593                 console::error("Duplicate spec type on line: %s\n", line_str.get_ptr());
1594                 return false;
1595             }
1596
1597             m_tm.insert(std::make_pair(tokens[0], tokens[3]));
1598         }
1599
1600         return true;
1601     }
1602
1603     //-----------------------------------------------------------------------------------------------------------------------
1604
1605     void dump_to_file(const char *pFilename) const
1606     {
1607         FILE *pFile = vogl_fopen(pFilename, "w");
1608         if (pFile)
1609         {
1610             console::info("--- Dumping %u GL types to text file \"%s\"\n", static_cast<uint>(m_tm.size()), pFilename);
1611
1612             for (gl_string_map::const_iterator it = m_tm.begin(); it != m_tm.end(); ++it)
1613                 vogl_fprintf(pFile, "\"%s\" = \"%s\"\n", it->first.get_ptr(), it->second.get_ptr());
1614
1615             vogl_fclose(pFile);
1616         }
1617         else
1618         {
1619             console::error("Failed writing GL types to file \"%s\"!\n", pFilename);
1620         }
1621     }
1622
1623 protected:
1624     gl_string_map m_tm;
1625 };
1626
1627 //-----------------------------------------------------------------------------------------------------------------------
1628 // class gl_enums
1629 //-----------------------------------------------------------------------------------------------------------------------
1630 struct gl_enum_def
1631 {
1632     dynamic_string m_name;
1633     dynamic_string m_def;
1634     bool m_alias_flag;
1635     bool m_define_flag;
1636 };
1637
1638 typedef vogl::vector<gl_enum_def> gl_enum_def_vec;
1639
1640 typedef std::map<dynamic_string, gl_enum_def_vec, gl_string_key_comparer> gl_enum_def_vec_map;
1641
1642 class gl_enums
1643 {
1644 public:
1645     gl_enums()
1646     {
1647     }
1648
1649     bool parse_file(const char *pFilename)
1650     {
1651         cfile_stream enum_file(pFilename, cDataStreamReadable);
1652         if (!enum_file.is_opened())
1653         {
1654             console::error("Unable to open file \"%s\"!\n", pFilename);
1655             return false;
1656         }
1657
1658         vogl::vector<gl_enum_def_vec_map::iterator> cur_enums;
1659         bool is_define = false;
1660         bool seen_at_least_one_define = false;
1661
1662         dynamic_string line_str;
1663         while (enum_file.get_remaining())
1664         {
1665             if (!enum_file.read_line(line_str))
1666                 break;
1667
1668             line_str.trim_end();
1669
1670             int comment_ofs = line_str.find_left('#');
1671             if (comment_ofs >= 0)
1672             {
1673                 line_str.truncate(comment_ofs);
1674                 line_str.trim_end();
1675             }
1676
1677             if (line_str.is_empty())
1678                 continue;
1679
1680             int colon_ofs = line_str.find_left(':');
1681             if (colon_ofs >= 0)
1682                 line_str.left(colon_ofs + 1);
1683
1684             dynamic_string_array tokens;
1685             line_str.tokenize(", \t", tokens);
1686
1687             if ((tokens[0] == "passthru:") || (tokens[0] == "profile:") || (tokens[0].find_left("future_use:") >= 0))
1688                 continue;
1689
1690             if ((colon_ofs >= 0) && (tokens.size()) &&
1691                 ((tokens.back() == "enum:") || (tokens.back() == "define:")))
1692             {
1693                 if (seen_at_least_one_define)
1694                     cur_enums.resize(0);
1695
1696                 is_define = (tokens.back() == "define:");
1697
1698                 for (uint i = 0; i < (tokens.size() - 1); i++)
1699                 {
1700                     gl_enum_def_vec_map::iterator cur_enum(m_enums.find(tokens[i]));
1701                     if (cur_enum == m_enums.end())
1702                     {
1703                         cur_enum = m_enums.insert(std::make_pair(tokens[i], gl_enum_def_vec())).first;
1704                     }
1705
1706                     cur_enums.push_back(cur_enum);
1707                 }
1708             }
1709             else if (tokens.size())
1710             {
1711                 if (line_str.find_left('=') >= 0)
1712                 {
1713                     seen_at_least_one_define = true;
1714
1715                     if ((tokens.size() != 3) || (tokens[1] != "="))
1716                     {
1717                         console::error("Unrecognized line: %s\n", line_str.get_ptr());
1718                         return false;
1719                     }
1720
1721                     if ((tokens[0].is_empty()) || (tokens[1].is_empty()))
1722                     {
1723                         console::error("Unrecognized line: %s\n", line_str.get_ptr());
1724                         return false;
1725                     }
1726
1727                     if (!cur_enums.size())
1728                     {
1729                         console::error("Enum defined outside of enum block: %s\n", line_str.get_ptr());
1730                         return false;
1731                     }
1732
1733                     gl_enum_def def;
1734                     def.m_name = tokens[0];
1735                     def.m_def = tokens[2];
1736                     def.m_alias_flag = false;
1737                     def.m_define_flag = is_define;
1738
1739                     for (uint i = 0; i < cur_enums.size(); i++)
1740                         cur_enums[i]->second.push_back(def);
1741                 }
1742                 else if (tokens[0] == "use")
1743                 {
1744                     seen_at_least_one_define = true;
1745
1746                     if (!cur_enums.size())
1747                     {
1748                         console::error("Enum defined outside of enum block: %s\n", line_str.get_ptr());
1749                         return false;
1750                     }
1751
1752                     gl_enum_def def;
1753                     def.m_name = tokens[2];
1754                     def.m_def = tokens[1];
1755                     def.m_alias_flag = true;
1756                     def.m_define_flag = is_define;
1757
1758                     for (uint i = 0; i < cur_enums.size(); i++)
1759                         cur_enums[i]->second.push_back(def);
1760                 }
1761                 else
1762                 {
1763                     console::error("Unrecognized line: %s\n", line_str.get_ptr());
1764                     return false;
1765                 }
1766             }
1767             else
1768             {
1769                 console::error("Unrecognized line: %s\n", line_str.get_ptr());
1770                 return false;
1771             }
1772         }
1773
1774         for (gl_enum_def_vec_map::iterator enum_it = m_enums.begin(); enum_it != m_enums.end(); ++enum_it)
1775         {
1776             //printf("%s\n", enum_it->first.get_ptr());
1777             gl_enum_def_vec_map::const_iterator alias_it(m_enums.find(enum_it->first));
1778             VOGL_ASSERT(alias_it != m_enums.end());
1779         }
1780
1781         uint num_unresolved_aliases;
1782         uint pass_num = 0;
1783         do
1784         {
1785             if (++pass_num == 100)
1786             {
1787                 console::error("Typemap alias depth is too deep, or there are circular aliases\n");
1788                 return false;
1789             }
1790
1791             num_unresolved_aliases = 0;
1792
1793             for (gl_enum_def_vec_map::iterator enum_it = m_enums.begin(); enum_it != m_enums.end(); ++enum_it)
1794             {
1795                 gl_enum_def_vec &def_vec = enum_it->second;
1796                 for (uint i = 0; i < def_vec.size(); i++)
1797                 {
1798                     if (!def_vec[i].m_alias_flag)
1799                         continue;
1800
1801                     gl_enum_def_vec_map::const_iterator alias_it(m_enums.find(def_vec[i].m_def));
1802                     if (alias_it == m_enums.end())
1803                     {
1804                         console::error("Bad alias enum: %s %s\n", def_vec[i].m_def.get_ptr(), def_vec[i].m_name.get_ptr());
1805                         return false;
1806                     }
1807
1808                     const gl_enum_def_vec &alias_def_vec = alias_it->second;
1809
1810                     uint j;
1811                     for (j = 0; j < alias_def_vec.size(); j++)
1812                     {
1813                         if (alias_def_vec[j].m_name == def_vec[i].m_name)
1814                             break;
1815                     }
1816
1817                     if (j == alias_def_vec.size())
1818                     {
1819                         console::error("Bad alias enum: %s %s\n", def_vec[i].m_def.get_ptr(), def_vec[i].m_name.get_ptr());
1820                         return false;
1821                     }
1822                     if (alias_def_vec[j].m_alias_flag)
1823                     {
1824                         num_unresolved_aliases++;
1825                         continue;
1826                     }
1827
1828                     def_vec[i].m_def = alias_def_vec[j].m_def;
1829                     def_vec[i].m_alias_flag = false;
1830                 }
1831             }
1832             //printf(".");
1833         } while (num_unresolved_aliases);
1834         //printf("\n");
1835
1836         return true;
1837     }
1838
1839     void dump_to_text_file(const char *pFilename) const
1840     {
1841         FILE *pFile = vogl_fopen(pFilename, "w");
1842         if (pFile)
1843         {
1844             console::info("--- Dumping %u GL enums to file %s\n", static_cast<uint>(m_enums.size()), pFilename);
1845
1846             for (gl_enum_def_vec_map::const_iterator enum_it = m_enums.begin(); enum_it != m_enums.end(); ++enum_it)
1847             {
1848                 vogl_fprintf(pFile, "enum \"%s\"\n", enum_it->first.get_ptr());
1849                 for (uint i = 0; i < enum_it->second.size(); i++)
1850                     vogl_fprintf(pFile, "  \"%s\" = \"%s\"\n", enum_it->second[i].m_name.get_ptr(), enum_it->second[i].m_def.get_ptr());
1851             }
1852
1853             vogl_fclose(pFile);
1854         }
1855         else
1856         {
1857             console::error("Failed writing GL enums to file %s\n", pFilename);
1858         }
1859     }
1860
1861     bool dump_to_definition_macro_file(const char *pFilename, const char *pPrefix) const
1862     {
1863         gl_string_map unique_enums;
1864         for (gl_enum_def_vec_map::const_iterator enum_it = m_enums.begin(); enum_it != m_enums.end(); ++enum_it)
1865         {
1866             for (uint i = 0; i < enum_it->second.size(); i++)
1867                 unique_enums.insert(std::make_pair(enum_it->second[i].m_name, enum_it->second[i].m_def));
1868         }
1869
1870         console::info("--- Generating \"%s\":\n", pFilename);
1871
1872         FILE *pFile = vogl_fopen(pFilename, "w");
1873         if (!pFile)
1874         {
1875             console::error("%s: Failed creating file \"%s\"!\n", VOGL_METHOD_NAME, pFilename);
1876             return false;
1877         }
1878
1879         for (gl_string_map::const_iterator it = unique_enums.begin(); it != unique_enums.end(); ++it)
1880             vogl_fprintf(pFile, "#define %s_%s %s\n", pPrefix, it->first.get_ptr(), it->second.get_ptr());
1881
1882         vogl_fclose(pFile);
1883         return true;
1884     }
1885
1886     bool dump_to_description_macro_file(const char *pFilename, const char *pPrefix, const gl_types &gl_typemap, const gl_types &alt_gl_typemap) const
1887     {
1888         console::info("--- Generating \"%s\":\n", pFilename);
1889
1890         FILE *pFile = vogl_fopen(pFilename, "w");
1891         if (!pFile)
1892         {
1893             console::error("%s: Failed creating file \"%s\"!\n", VOGL_METHOD_NAME, pFilename);
1894             return false;
1895         }
1896
1897         for (gl_enum_def_vec_map::const_iterator enum_it = m_enums.begin(); enum_it != m_enums.end(); ++enum_it)
1898         {
1899             vogl_fprintf(pFile, "DEFINE_GL_ENUM_CATEGORY_BEGIN(%s)\n", enum_it->first.get_ptr());
1900
1901             for (uint i = 0; i < enum_it->second.size(); i++)
1902             {
1903                 const dynamic_string *pGLType = NULL;
1904                 pGLType = gl_typemap.find(enum_it->first.get_ptr());
1905                 if (!pGLType)
1906                     pGLType = alt_gl_typemap.find(enum_it->first.get_ptr());
1907
1908                 if (enum_it->second[i].m_define_flag)
1909                 {
1910                     vogl_fprintf(pFile, "DEFINE_GL_DEFINE_MEMBER(%s, %s, %s_%s)\n",
1911                                 pPrefix,
1912                                 enum_it->first.get_ptr(),
1913                                 pPrefix, enum_it->second[i].m_name.get_ptr());
1914                 }
1915                 else
1916                 {
1917                     vogl_fprintf(pFile, "DEFINE_GL_ENUM_MEMBER(%s, %s, \"%s\", \"%s_%s\", %s)\n",
1918                                 pPrefix,
1919                                 enum_it->first.get_ptr(),
1920                                 pGLType ? pGLType->get_ptr() : "",
1921                                 pPrefix, enum_it->second[i].m_name.get_ptr(), enum_it->second[i].m_def.get_ptr());
1922                 }
1923             }
1924
1925             vogl_fprintf(pFile, "DEFINE_GL_ENUM_CATEGORY_END(%s)\n", enum_it->first.get_ptr());
1926         }
1927
1928         vogl_fclose(pFile);
1929
1930         return true;
1931     }
1932
1933 private:
1934     gl_enum_def_vec_map m_enums;
1935 };
1936
1937 //-----------------------------------------------------------------------------------------------------------------------
1938 // class vogl_gen
1939 //-----------------------------------------------------------------------------------------------------------------------
1940 #define DEF_FUNCTION_PROTO_PARAM_STR "(a,b,c,d,e,f,g,h)"
1941
1942 class vogl_gen
1943 {
1944     apitrace_func_specs m_apitrace_gl_func_specs;
1945     gl_function_specs m_gl_xml_functions;
1946     gl_enums m_gl_enumerations;
1947     gl_enums m_glx_enumerations;
1948     gl_enums m_glx_ext_enumerations;
1949
1950     gl_function_specs m_gl_funcs;
1951     gl_function_specs m_glx_funcs;
1952     gl_function_specs m_glxext_funcs;
1953
1954     gl_function_specs m_all_gl_funcs;
1955
1956     dynamic_string_array m_unique_categories;
1957
1958     gl_string_map m_unique_ctype_enums;
1959
1960     gl_types m_gl_typemap;
1961     gl_types m_glx_typemap;
1962
1963     dynamic_string_array m_gl_so_function_exports;
1964
1965     gl_string_set m_all_gl_ctypes;
1966     gl_string_set m_all_gl_categories;
1967     gl_string_set m_all_array_sizes;
1968
1969     gl_string_map m_pointee_types;
1970
1971     dynamic_string_array m_whitelisted_funcs;
1972     dynamic_string_array m_whitelisted_displaylist_funcs;
1973     dynamic_string_array m_nullable_funcs;
1974
1975     dynamic_string_array m_simple_replay_funcs;
1976
1977     dynamic_string_array funcs_with_custom_array_size_macros;
1978     dynamic_string_array custom_return_param_array_size_macros;
1979     dynamic_string_array funcs_with_return_param_array_size_macros;
1980
1981     gl_string_set custom_array_size_macros;
1982     vogl::vector<uint> custom_array_size_macro_indices;
1983     dynamic_string_array custom_array_size_macro_names;
1984
1985     struct gl_get
1986     {
1987         gl_get()
1988             : m_min_vers(0xFFFF), m_max_vers(0)
1989         {
1990         }
1991
1992         dynamic_string m_name;
1993         uint m_min_vers;
1994         uint m_max_vers;
1995
1996         inline bool operator<(const gl_get &rhs) const
1997         {
1998             if (m_min_vers < rhs.m_min_vers)
1999                 return true;
2000             else if (m_min_vers == rhs.m_min_vers)
2001             {
2002                 if (m_max_vers < rhs.m_max_vers)
2003                     return true;
2004                 else if (m_max_vers == rhs.m_max_vers)
2005                     return m_name < rhs.m_name;
2006             }
2007             return false;
2008         }
2009     };
2010
2011     typedef vogl::hash_map<dynamic_string, gl_get> gl_get_hash_map;
2012     gl_get_hash_map m_gl_gets;
2013
2014 public:
2015     vogl_gen()
2016     {
2017     }
2018
2019     bool init()
2020     {
2021         // TODO: I'm going to move the "glspec" dir from under bin to raddebugger/glspec (or whatever)
2022         if (!file_utils::does_file_exist("gl.spec"))
2023         {
2024             if (file_utils::does_file_exist("glspec/gl.spec"))
2025             {
2026                 file_utils::change_directory("glspec");
2027                 console::warning("Changing current directory to glspec\n");
2028             }
2029             else if (file_utils::does_file_exist("../bin/glspec/gl.spec"))
2030             {
2031                 file_utils::change_directory("../bin/glspec");
2032                 console::warning("Changing current directory to ../bin/glspec\n");
2033             }
2034         }
2035
2036         if (!file_utils::does_file_exist("gl.spec"))
2037         {
2038             console::error("Can't find find gl.spec, which must be in the current directory!\n");
2039             return false;
2040         }
2041
2042         // -- Load apitrace's GL function defintions, which was auto generated then hand-edited by the apitrace team - we ONLY use this for parameter namespace info and cross referencing (verification)
2043         if (!m_apitrace_gl_func_specs.parse())
2044         {
2045             console::error("Failed parsing apitrace param info file!\n");
2046             return false;
2047         }
2048
2049         // -- Load gl.xml, auto-generated from various web pages using several Python scripts
2050         if (!m_gl_xml_functions.parse_gl_xml_file("gl.xml"))
2051             return false;
2052
2053         // -- Load the various GL/GLX/GLXEXT enum spec files
2054         m_gl_enumerations.parse_file("enum.spec");
2055         m_glx_enumerations.parse_file("glxenum.spec");
2056         m_glx_ext_enumerations.parse_file("glxenumext.spec");
2057
2058         // -- Load the various GL/GLX/GLXEXT func spec files
2059         bool success = m_gl_funcs.parse_spec_file("gl.spec", cGL);
2060         if (!success)
2061         {
2062             console::error("Failed parsing gl.spec!\n");
2063             return false;
2064         }
2065         success = m_glx_funcs.parse_spec_file("glx.spec", cGLX);
2066         if (!success)
2067         {
2068             console::error("Failed parsing glx.spec!\n");
2069             return false;
2070         }
2071
2072         success = m_glxext_funcs.parse_spec_file("glxext.spec", cGLX);
2073         if (!success)
2074         {
2075             console::error("Failed parsing glxext.spec!\n");
2076             return false;
2077         }
2078
2079         // -- Clean up the GLX func definitions
2080         for (uint i = 0; i < m_glxext_funcs.size(); i++)
2081         {
2082             int glx_index = m_glx_funcs.find_index(m_glxext_funcs[i].m_name.get_ptr());
2083             if (glx_index >= 0)
2084             {
2085                 console::warning("glxext func %s overriding glx definition\n", m_glxext_funcs[i].m_name.get_ptr());
2086                 m_glx_funcs.get_funcs_vec().erase_unordered(glx_index);
2087             }
2088
2089             int gl_index = m_gl_funcs.find_index(m_glxext_funcs[i].m_name.get_ptr());
2090             if (gl_index >= 0)
2091             {
2092                 console::warning("glxext func %s overriding definition\n", m_glxext_funcs[i].m_name.get_ptr());
2093                 m_gl_funcs.get_funcs_vec().erase_unordered(gl_index);
2094             }
2095         }
2096
2097         for (uint j = 0; j < m_glxext_funcs.size(); j++)
2098         {
2099             if (m_glxext_funcs[j].m_name.ends_with("SGIX"))
2100             {
2101                 console::message("deleting glxext func %s\n", m_glxext_funcs[j].m_name.get_ptr());
2102
2103                 m_glxext_funcs.get_funcs_vec().erase_unordered(j);
2104                 j--;
2105             }
2106         }
2107
2108         // -- Parse the various spec typemap files
2109         success = m_gl_typemap.parse_file("gl.tm");
2110         if (!success)
2111         {
2112             console::error("Failed parsing gl.tm!\n");
2113             return false;
2114         }
2115
2116         success = m_glx_typemap.parse_file("glx.tm");
2117         if (!success)
2118         {
2119             console::error("Failed parsing glx.tm!\n");
2120             return false;
2121         }
2122
2123         // -- Determine the ctypes used by all the GL/GLX functions
2124         if (!determine_ctypes("gl", m_gl_funcs, m_gl_typemap, m_glx_typemap))
2125         {
2126             console::error("Failed determined gl c types!\n");
2127             return false;
2128         }
2129
2130         if (!determine_ctypes("glX", m_glx_funcs, m_glx_typemap, m_gl_typemap))
2131         {
2132             console::error("Failed determined glX c types!\n");
2133             return false;
2134         }
2135
2136         if (!determine_ctypes("glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap))
2137         {
2138             console::error("Failed determined glX c types!\n");
2139             return false;
2140         }
2141
2142         // -- Create master list of all GL/GLX/GLXEXT functions
2143         m_all_gl_funcs = m_gl_funcs;
2144         m_all_gl_funcs += m_glx_funcs;
2145         m_all_gl_funcs += m_glxext_funcs;
2146
2147         // -- Determine the unique list of function API categories
2148         for (uint i = 0; i < m_all_gl_funcs.size(); i++)
2149         {
2150             if (m_unique_categories.find(m_all_gl_funcs[i].m_category) < 0)
2151                 m_unique_categories.push_back(m_all_gl_funcs[i].m_category);
2152         }
2153
2154         m_unique_categories.sort();
2155
2156         // -- Load the GL/GLX function export table, generated by dumping the headers of various drivers
2157         if (!load_gl_so_function_export_list("gl_glx_so_export_list.txt", m_gl_so_function_exports))
2158         {
2159             console::error("Failed parsing glx.tm!\n");
2160             return false;
2161         }
2162
2163         process_func_protos("gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_gl_so_function_exports, m_all_gl_ctypes, m_all_gl_categories, m_all_array_sizes);
2164         process_func_protos("glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_all_gl_ctypes, m_all_gl_categories, m_all_array_sizes);
2165         process_func_protos("glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_all_gl_ctypes, m_all_gl_categories, m_all_array_sizes);
2166
2167         // -- Create the m_unique_ctype_enums table
2168         for (uint i = 0; i < m_all_gl_funcs.size(); i++)
2169         {
2170             const gl_function_def &func = m_all_gl_funcs[i];
2171
2172             m_unique_ctype_enums.insert(std::make_pair(func.m_return_ctype_enum, func.m_return_ctype));
2173             for (uint p = 0; p < func.m_params.size(); p++)
2174                 m_unique_ctype_enums.insert(std::make_pair(func.m_params[p].m_ctype_enum, func.m_params[p].m_ctype));
2175         }
2176
2177 // -- Create the m_pointee_types table
2178 #if 0
2179                 printf("---\n");
2180                 for (uint i = 0; i < whitelisted_funcs.size(); i++)
2181                 {
2182                         int j = simple_replay_funcs.find(whitelisted_funcs[i]);
2183                         if (j < 0)
2184                                 printf("%s\n", whitelisted_funcs[i].get_ptr());
2185                 }
2186                 printf("---\n");
2187 #endif
2188
2189         for (gl_string_map::const_iterator it = m_unique_ctype_enums.begin(); it != m_unique_ctype_enums.end(); ++it)
2190         {
2191             dynamic_string ctype(it->first.get_ptr());
2192             if (!ctype.ends_with("_PTR"))
2193                 continue;
2194
2195             ctype.shorten(4);
2196
2197             if (ctype.ends_with("_CONST"))
2198                 ctype.shorten(6);
2199
2200             if (m_unique_ctype_enums.find(ctype) != m_unique_ctype_enums.end())
2201             {
2202                 m_pointee_types.insert(std::make_pair(it->first.get_ptr(), ctype));
2203             }
2204             else
2205             {
2206                 dynamic_string ctype_without_const(ctype);
2207                 int ofs = ctype_without_const.find_left("_CONST_");
2208                 if (ofs >= 0)
2209                 {
2210                     ctype_without_const.remove(ofs, 6);
2211                 }
2212                 if (m_unique_ctype_enums.find(ctype_without_const) != m_unique_ctype_enums.end())
2213                 {
2214                     m_pointee_types.insert(std::make_pair(it->first.get_ptr(), ctype_without_const));
2215                 }
2216                 else
2217                 {
2218                     dynamic_string ctype_without_const_definition(it->second);
2219
2220                     int ptr_ofs = ctype_without_const_definition.find_right('*');
2221                     if (ptr_ofs >= 0)
2222                         ctype_without_const_definition.remove(ptr_ofs, 1);
2223                     int const_ofs = ctype_without_const_definition.find_left("const");
2224                     if (const_ofs >= 0)
2225                         ctype_without_const_definition.remove(const_ofs, 5);
2226                     ctype_without_const_definition.trim();
2227
2228                     printf("Introducing new ctype from ptr to pointee: %s %s\n", ctype_without_const.get_ptr(), ctype_without_const_definition.get_ptr());
2229
2230                     m_unique_ctype_enums.insert(std::make_pair(ctype_without_const, ctype_without_const_definition));
2231                 }
2232                 m_pointee_types.insert(std::make_pair(it->first.get_ptr(), ctype_without_const));
2233             }
2234         }
2235
2236         // these are NOT actually pointers, they are just big enough to hold pointers (like intptr_t)
2237         //m_pointee_types.insert(std::make_pair("VOGL_GLINTPTR", "VOGL_GLINT"));
2238         //m_pointee_types.insert(std::make_pair("VOGL_GLINTPTRARB", "VOGL_GLINT"));
2239         //m_pointee_types.insert(std::make_pair("VOGL_GLSIZEIPTR", "VOGL_GLSIZEI"));
2240
2241         // -- Read the GL/GLX whitelisted and nullable funcs file
2242         //file_utils::read_text_file("gl_glx_whitelisted_funcs.txt", m_whitelisted_funcs, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintWarningMessages);
2243         if (!read_regex_function_array("gl_glx_whitelisted_funcs.txt", m_whitelisted_funcs))
2244             return false;
2245
2246         // -- Read the display list whitelist
2247         //file_utils::read_text_file("gl_glx_displaylist_whitelist.txt", m_whitelisted_displaylist_funcs, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintWarningMessages);
2248         if (!read_regex_function_array("gl_glx_displaylist_whitelist.txt", m_whitelisted_displaylist_funcs))
2249             return false;
2250
2251         //file_utils::read_text_file("gl_glx_nullable_funcs.txt", m_nullable_funcs, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintWarningMessages);
2252         if (!read_regex_function_array("gl_glx_nullable_funcs.txt", m_nullable_funcs))
2253             return false;
2254
2255         if (!read_regex_function_array("gl_glx_simple_replay_funcs.txt", m_simple_replay_funcs))
2256             return false;
2257
2258         update_whitelisted_funcs(m_gl_funcs, m_unique_ctype_enums, m_pointee_types, m_whitelisted_funcs);
2259
2260         m_whitelisted_funcs.sort();
2261
2262         process_func_defs("gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, funcs_with_custom_array_size_macros, custom_return_param_array_size_macros, funcs_with_return_param_array_size_macros);
2263         process_func_defs("glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, funcs_with_custom_array_size_macros, custom_return_param_array_size_macros, funcs_with_return_param_array_size_macros);
2264         process_func_defs("glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, funcs_with_custom_array_size_macros, custom_return_param_array_size_macros, funcs_with_return_param_array_size_macros);
2265
2266         uint cur_func_id = 0;
2267         create_array_size_macros("gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_gl_so_function_exports, custom_array_size_macros, custom_array_size_macro_indices, custom_array_size_macro_names, cur_func_id);
2268         create_array_size_macros("glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, custom_array_size_macros, custom_array_size_macro_indices, custom_array_size_macro_names, cur_func_id);
2269         create_array_size_macros("glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, custom_array_size_macros, custom_array_size_macro_indices, custom_array_size_macro_names, cur_func_id);
2270
2271         // -- Cross reference the GL spec vs. XML files, for validation
2272         if (!validate_functions(m_gl_xml_functions, m_all_gl_funcs, m_apitrace_gl_func_specs, m_gl_typemap, m_glx_typemap))
2273         {
2274             console::error("Failed validating functions!\n");
2275             return false;
2276         }
2277
2278         if (!init_gl_gets())
2279             return false;
2280
2281         return true;
2282     }
2283
2284     bool func_regex(const char *pPattern) const
2285     {
2286         regexp r;
2287         if (!r.init(pPattern))
2288         {
2289             console::error("Bad regular expression: \"%s\", reason: \"%s\"\n", pPattern, r.get_error().get_ptr());
2290             return false;
2291         }
2292
2293         uint t = 0;
2294         for (uint func_index = 0; func_index < m_all_gl_funcs.size(); func_index++)
2295         {
2296             if (r.full_match(m_all_gl_funcs[func_index].m_full_name.get_ptr()))
2297             {
2298                 const gl_function_def &func = m_all_gl_funcs[func_index];
2299
2300                 printf("%s ", func.m_return_ctype.get_ptr());
2301                 printf("%s(", func.m_full_name.get_ptr());
2302                 for (uint j = 0; j < func.m_params.size(); j++)
2303                 {
2304                     printf("%s %s", func.m_params[j].m_ctype.get_ptr(), func.m_params[j].m_name.get_ptr());
2305                     if (j != func.m_params.size() - 1)
2306                         printf(", ");
2307                 }
2308                 printf(");\n");
2309                 t++;
2310             }
2311         }
2312         printf("Found %u results\n", t);
2313
2314         return true;
2315     }
2316
2317     bool param_regex(const char *pPattern) const
2318     {
2319         regexp r;
2320         if (!r.init(pPattern))
2321         {
2322             console::error("Bad regular expression: \"%s\", reason: \"%s\"\n", pPattern, r.get_error().get_ptr());
2323             return false;
2324         }
2325
2326         uint t = 0;
2327         for (uint func_index = 0; func_index < m_all_gl_funcs.size(); func_index++)
2328         {
2329             const gl_function_def &func_def = m_all_gl_funcs[func_index];
2330
2331             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
2332             {
2333                 if (r.full_match(func_def.m_params[param_index].m_name.get_ptr()))
2334                 {
2335                     printf("%s %u %s\n", func_def.m_full_name.get_ptr(), param_index, func_def.m_params[param_index].m_name.get_ptr());
2336                     t++;
2337                 }
2338             }
2339         }
2340         printf("Found %u results\n", t);
2341
2342         return true;
2343     }
2344
2345     bool category_regex(const char *pPattern) const
2346     {
2347         regexp r;
2348         if (!r.init(pPattern))
2349         {
2350             console::error("Bad regular expression: \"%s\", reason: \"%s\"\n", pPattern, r.get_error().get_ptr());
2351             return false;
2352         }
2353
2354         uint t = 0;
2355         for (uint func_index = 0; func_index < m_all_gl_funcs.size(); func_index++)
2356         {
2357             const gl_function_def &func_def = m_all_gl_funcs[func_index];
2358
2359             if (r.full_match(func_def.m_category.get_ptr()))
2360             {
2361                 printf("%s %s\n", func_def.m_full_name.get_ptr(), func_def.m_category.get_ptr());
2362                 t++;
2363             }
2364         }
2365         printf("Found %u results\n", t);
2366
2367         return true;
2368     }
2369
2370     bool ctype_regex(const char *pPattern) const
2371     {
2372         regexp r;
2373         if (!r.init(pPattern))
2374         {
2375             console::error("Bad regular expression: \"%s\", reason: \"%s\"\n", pPattern, r.get_error().get_ptr());
2376             return false;
2377         }
2378
2379         uint t = 0;
2380         for (uint func_index = 0; func_index < m_all_gl_funcs.size(); func_index++)
2381         {
2382             const gl_function_def &func_def = m_all_gl_funcs[func_index];
2383
2384             if (r.full_match(func_def.m_return_ctype.get_ptr()))
2385             {
2386                 printf("%s return %s\n", func_def.m_full_name.get_ptr(), func_def.m_return_ctype.get_ptr());
2387                 t++;
2388             }
2389
2390             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
2391             {
2392                 if (r.full_match(func_def.m_params[param_index].m_ctype.get_ptr()))
2393                 {
2394                     printf("%s %u %s %s\n", func_def.m_full_name.get_ptr(), param_index, func_def.m_params[param_index].m_name.get_ptr(), func_def.m_params[param_index].m_ctype.get_ptr());
2395                     t++;
2396                 }
2397             }
2398         }
2399         printf("Found %u results\n", t);
2400
2401         return true;
2402     }
2403
2404     bool namespace_regex(const char *pPattern) const
2405     {
2406         regexp r;
2407         if (!r.init(pPattern))
2408         {
2409             console::error("Bad regular expression: \"%s\", reason: \"%s\"\n", pPattern, r.get_error().get_ptr());
2410             return false;
2411         }
2412
2413         uint t = 0;
2414         for (uint func_index = 0; func_index < m_apitrace_gl_func_specs.size(); func_index++)
2415         {
2416             const apitrace_gl_func_def &func_def = m_apitrace_gl_func_specs[func_index];
2417
2418             if (r.full_match(vogl_get_namespace_name(func_def.m_return_namespace)))
2419             {
2420                 printf("%s return %s\n", func_def.m_name.get_ptr(), vogl_get_namespace_name(func_def.m_return_namespace));
2421                 t++;
2422             }
2423
2424             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
2425             {
2426                 const apitrace_gl_func_param_def &param = func_def.m_params[param_index];
2427
2428                 if (r.full_match(vogl_get_namespace_name(param.m_namespace)))
2429                 {
2430                     printf("%s %u %s\n", func_def.m_name.get_ptr(), param_index, vogl_get_namespace_name(param.m_namespace));
2431                     t++;
2432                 }
2433             }
2434         }
2435         printf("Found %u results\n", t);
2436
2437         return true;
2438     }
2439
2440     bool dump_debug_files() const
2441     {
2442         m_gl_enumerations.dump_to_text_file("dbg_enums.txt");
2443         m_glx_enumerations.dump_to_text_file("dbg_glx_enums.txt");
2444         m_glx_ext_enumerations.dump_to_text_file("dbg_glx_ext_enums.txt");
2445
2446         // -- Dump the definitions for debugging
2447         m_gl_xml_functions.dump_to_file("dbg_gl_xml_funcs.txt");
2448         m_gl_funcs.dump_to_file("dbg_gl_funcs.txt");
2449         m_glx_funcs.dump_to_file("dbg_glx_funcs.txt");
2450         m_glxext_funcs.dump_to_file("dbg_glxext_funcs.txt");
2451
2452         // -- Dump the spec typemap files, for debugging
2453         m_gl_typemap.dump_to_file("dbg_gl_typemap.txt");
2454         m_glx_typemap.dump_to_file("dbg_glx_typemap.txt");
2455
2456         m_all_gl_funcs.dump_to_file("dbg_gl_all_funcs.txt");
2457
2458         FILE *pFile;
2459
2460         // Write a simple macro file line this:
2461         //GL_FUNC(OpenGL,true,GLenum,glGetError,(void),())
2462         //GL_FUNC_VOID(OpenGL,true,glActiveTexture,(GLenum a),(a))
2463         pFile = fopen_and_log("dbg_gl_glx_simple_func_macros.txt", "w");
2464         for (uint i = 0; i < m_all_gl_funcs.size(); i++)
2465         {
2466             const gl_function_def &def = m_all_gl_funcs[i];
2467             if (def.m_return == "void")
2468                 fprintf(pFile, "GL_FUNC_VOID(%s,%s,(%s),(%s))\n", def.get_lib_name(), def.m_full_name.get_ptr(), def.get_param_proto().get_ptr(), def.get_param_args().get_ptr());
2469             else
2470                 fprintf(pFile, "GL_FUNC(%s,%s,%s,(%s),(%s))\n", def.get_lib_name(), def.m_return_ctype.get_ptr(), def.m_full_name.get_ptr(), def.get_param_proto().get_ptr(), def.get_param_args().get_ptr());
2471         }
2472         fclose(pFile);
2473
2474         pFile = fopen_and_log("dbg_gl_glx_types.txt", "w");
2475         for (gl_string_set::const_iterator it = m_all_gl_ctypes.begin(); it != m_all_gl_ctypes.end(); ++it)
2476             vogl_fprintf(pFile, "%s\n", it->get_ptr());
2477         vogl_fclose(pFile);
2478
2479         pFile = fopen_and_log("dbg_gl_glx_array_sizes.txt", "w");
2480         for (gl_string_set::const_iterator it = m_all_array_sizes.begin(); it != m_all_array_sizes.end(); ++it)
2481             vogl_fprintf(pFile, "%s\n", it->get_ptr());
2482         vogl_fclose(pFile);
2483
2484         printf("\n");
2485         printf("--- Functions with custom array size macros:\n");
2486         for (uint i = 0; i < funcs_with_custom_array_size_macros.size(); i++)
2487             printf("%s\n", funcs_with_custom_array_size_macros[i].get_ptr());
2488         printf("---\n");
2489
2490         printf("--- Whitelisted functions with custom array size macros:\n");
2491         for (uint i = 0; i < funcs_with_custom_array_size_macros.size(); i++)
2492         {
2493             if (scan_dynamic_string_array_for_string(m_whitelisted_funcs, funcs_with_custom_array_size_macros[i].get_ptr(), true) < 0)
2494                 continue;
2495             printf("%s\n", funcs_with_custom_array_size_macros[i].get_ptr());
2496         }
2497         printf("---\n");
2498
2499         printf("--- All categories:\n");
2500         for (uint i = 0; i < m_unique_categories.size(); i++)
2501             printf("%s\n", m_unique_categories[i].get_ptr());
2502         printf("---\n");
2503
2504         // -- Write the final whitelist to a file for debugging
2505         file_utils::write_text_file("dbg_final_gl_glx_whitelisted_funcs.txt", m_whitelisted_funcs, true);
2506
2507         VOGL_ASSERT(m_whitelisted_funcs.is_sorted());
2508
2509         for (uint i = 0; i < m_unique_categories.size(); i++)
2510         {
2511             dynamic_string_array missing_funcs;
2512
2513             bool are_any_whitelisted = false;
2514             for (uint j = 0; j < m_all_gl_funcs.size(); j++)
2515             {
2516                 const gl_function_def &func = m_all_gl_funcs[j];
2517                 if (func.m_category != m_unique_categories[i])
2518                     continue;
2519
2520                 bool is_whitelisted = m_whitelisted_funcs.find_sorted(func.m_full_name) >= 0;
2521
2522                 if (!is_whitelisted)
2523                     missing_funcs.push_back(func.m_full_name);
2524                 else
2525                     are_any_whitelisted = true;
2526             }
2527
2528             if (missing_funcs.size())
2529             {
2530                 printf("--- Non-whitelisted funcs for %s category %s:\n", are_any_whitelisted ? "partially supported" : "unsupported", m_unique_categories[i].get_ptr());
2531                 for (uint j = 0; j < missing_funcs.size(); j++)
2532                     printf("%s\n", missing_funcs[j].get_ptr());
2533                 printf("---\n");
2534             }
2535             else
2536             {
2537                 printf("--- Full support for category: %s\n", m_unique_categories[i].get_ptr());
2538             }
2539         }
2540
2541         return true;
2542     }
2543
2544     static FILE *fopen_and_log(const char *pFilename, const char *pMode)
2545     {
2546         FILE *pFile = vogl_fopen(pFilename, pMode);
2547         if (!pFile)
2548         {
2549             console::error("Failed opening file \"%s\" for mode %s\n", pFilename, pMode);
2550             return NULL;
2551         }
2552
2553         console::info("--- Generating \"%s\":\n", pFilename);
2554         return pFile;
2555     }
2556
2557     bool generate() const
2558     {
2559         if (!m_gl_enumerations.dump_to_definition_macro_file("gl_enums.inc", "GL"))
2560             return false;
2561         if (!m_glx_enumerations.dump_to_definition_macro_file("glx_enums.inc", "GLX"))
2562             return false;
2563         if (!m_glx_ext_enumerations.dump_to_definition_macro_file("glx_ext_enums.inc", "GLX"))
2564             return false;
2565
2566         if (!m_gl_enumerations.dump_to_description_macro_file("gl_enum_desc.inc", "GL", m_gl_typemap, m_glx_typemap))
2567             return false;
2568         if (!m_glx_enumerations.dump_to_description_macro_file("glx_enum_desc.inc", "GLX", m_glx_typemap, m_gl_typemap))
2569             return false;
2570         if (!m_glx_ext_enumerations.dump_to_description_macro_file("glx_ext_desc.inc", "GLX", m_glx_typemap, m_gl_typemap))
2571             return false;
2572
2573         // -- Generate the gl_glx_protos.inc include file
2574         FILE *pFile = fopen_and_log("gl_glx_protos.inc", "w");
2575         if (!pFile)
2576         {
2577             console::error("Failed creating file gl_glx_protos.inc!\n");
2578             return false;
2579         }
2580         dump_func_proto_macros(pFile, "gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_gl_so_function_exports);
2581         dump_func_proto_macros(pFile, "glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports);
2582         dump_func_proto_macros(pFile, "glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports);
2583         vogl_fprintf(pFile, "#undef DEF_PROTO_EXPORTED\n");
2584         vogl_fprintf(pFile, "#undef DEF_PROTO_EXPORTED_VOID\n");
2585         vogl_fprintf(pFile, "#undef DEF_PROTO_INTERNAL\n");
2586         vogl_fprintf(pFile, "#undef DEF_PROTO_INTERNAL_VOID\n");
2587         vogl_fprintf(pFile, "#undef DEF_PROTO\n");
2588         vogl_fprintf(pFile, "#undef DEF_PROTO_VOID\n");
2589         vogl_fclose(pFile);
2590
2591         // -- Generate the gl_glx_ctypes.inc include file
2592         pFile = fopen_and_log("gl_glx_ctypes.inc", "w");
2593         vogl_fprintf(pFile, "DEF_TYPE(VOGL_INVALID_CTYPE, int)\n");
2594         for (gl_string_map::const_iterator it = m_unique_ctype_enums.begin(); it != m_unique_ctype_enums.end(); ++it)
2595             vogl_fprintf(pFile, "DEF_TYPE(%s, %s)\n", it->first.get_ptr(), it->second.get_ptr());
2596         vogl_fclose(pFile);
2597
2598         // -- Generate the gl_glx_ctypes_ptr_to_pointee.inc include file
2599         pFile = fopen_and_log("gl_glx_ctypes_ptr_to_pointee.inc", "w");
2600         for (gl_string_map::const_iterator it = m_pointee_types.begin(); it != m_pointee_types.end(); ++it)
2601             vogl_fprintf(pFile, "DEF_PTR_TO_POINTEE_TYPE(%s, %s)\n", it->first.get_ptr(), it->second.get_ptr());
2602         vogl_fclose(pFile);
2603
2604         // -- Generate the gl_glx_simple_replay_funcs.inc simple replay funcs file, and update the whitelist
2605         generate_simple_replay_funcs(m_all_gl_funcs, m_unique_ctype_enums, m_pointee_types, m_whitelisted_funcs);
2606
2607         // -- Generate replayer helper macros
2608         generate_replay_func_load_macros(m_all_gl_funcs, m_unique_ctype_enums, m_pointee_types, m_whitelisted_funcs);
2609
2610         // -- Generate the gl_glx_func_defs.inc include file
2611         pFile = fopen_and_log("gl_glx_func_defs.inc", "w");
2612         if (!pFile)
2613         {
2614             console::error("Failed creating file gl_glx_func_defs.inc!\n");
2615             return false;
2616         }
2617         dump_inc_file_header(pFile);
2618         dump_func_def_macros(pFile, "gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs);
2619         dump_func_def_macros(pFile, "glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs);
2620         dump_func_def_macros(pFile, "glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs);
2621         dump_function_def_undef_macros(pFile);
2622         vogl_fclose(pFile);
2623
2624         // -- Generate the gl_glx_func_return_param_array_size_macros.inc include file
2625         pFile = fopen_and_log("gl_glx_func_return_param_array_size_macros.inc", "w");
2626         if (!pFile)
2627         {
2628             console::error("Failed creating file gl_glx_func_return_param_array_size_macros.inc!\n");
2629             return false;
2630         }
2631         for (uint i = 0; i < custom_return_param_array_size_macros.size(); i++)
2632         {
2633             dynamic_string macro_name(custom_return_param_array_size_macros[i]);
2634             int n = macro_name.find_left('(');
2635             if (n >= 0)
2636                 macro_name.truncate(n);
2637
2638             int num_params = custom_return_param_array_size_macros[i].count_char(',') + 1;
2639
2640             dynamic_string params("(");
2641             for (int j = 0; j < num_params; j++)
2642             {
2643                 if (j)
2644                     params.append_char(',');
2645                 params.append_char((char)('a' + j));
2646             }
2647             params += ")";
2648
2649             vogl_fprintf(pFile, "#ifndef %s\n", macro_name.get_ptr());
2650             vogl_fprintf(pFile, "   #define %s%s -1\n", macro_name.get_ptr(), params.get_ptr());
2651             vogl_fprintf(pFile, "#endif\n");
2652         }
2653         vogl_fclose(pFile);
2654
2655         // -- Generate the gl_glx_func_descs.inc include file
2656         pFile = fopen_and_log("gl_glx_func_descs.inc", "w");
2657         dump_inc_file_header(pFile);
2658         dump_func_desc_macros(pFile, "gl", m_gl_funcs, m_gl_typemap, m_glx_typemap, m_apitrace_gl_func_specs, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, m_whitelisted_displaylist_funcs);
2659         dump_func_desc_macros(pFile, "glX", m_glx_funcs, m_glx_typemap, m_gl_typemap, m_apitrace_gl_func_specs, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, m_whitelisted_displaylist_funcs);
2660         dump_func_desc_macros(pFile, "glX", m_glxext_funcs, m_glx_typemap, m_gl_typemap, m_apitrace_gl_func_specs, m_gl_so_function_exports, m_whitelisted_funcs, m_nullable_funcs, m_whitelisted_displaylist_funcs);
2661         dump_function_def_undef_macros(pFile);
2662         vogl_fclose(pFile);
2663
2664         pFile = fopen_and_log("gl_glx_categories.inc", "w");
2665         for (gl_string_set::const_iterator it = m_all_gl_categories.begin(); it != m_all_gl_categories.end(); ++it)
2666             vogl_fprintf(pFile, "DEF_CATEGORY(%s)\n", it->get_ptr());
2667         vogl_fclose(pFile);
2668
2669         // -- Generate the gl_glx_array_size_macros.inc include file
2670         pFile = fopen_and_log("gl_glx_array_size_macros.inc", "w");
2671         for (gl_string_set::const_iterator it = custom_array_size_macros.begin(); it != custom_array_size_macros.end(); ++it)
2672         {
2673             dynamic_string macro_name(it->get_ptr());
2674             macro_name.truncate(macro_name.find_left('('));
2675             vogl_fprintf(pFile, "#ifndef %s\n", macro_name.get_ptr());
2676             vogl_fprintf(pFile, "   #define %s%s -1\n", macro_name.get_ptr(), DEF_FUNCTION_PROTO_PARAM_STR);
2677             vogl_fprintf(pFile, "#endif\n");
2678         }
2679         vogl_fclose(pFile);
2680
2681         // -- Generate the gl_glx_array_size_macros_validator.inc include file
2682         pFile = fopen_and_log("gl_glx_array_size_macros_validator.inc", "w");
2683         for (uint i = 0; i < custom_array_size_macro_indices.size(); i++)
2684         {
2685             uint j = custom_array_size_macro_indices[i];
2686             uint func_index = j >> 16;
2687             uint param_index = j & 0xFFFF;
2688             VOGL_NOTE_UNUSED(param_index);
2689
2690             const dynamic_string &macro_name = custom_array_size_macro_names[i];
2691
2692             vogl_fprintf(pFile, "#ifndef DEF_FUNCTION_CUSTOM_HANDLER_%s%s\n", g_lib_api_prefixes[m_all_gl_funcs[func_index].m_lib], m_all_gl_funcs[func_index].m_name.get_ptr());
2693             vogl_fprintf(pFile, "   #ifdef %s\n", macro_name.get_ptr());
2694             vogl_fprintf(pFile, "      VALIDATE_ARRAY_SIZE_MACRO_DEFINED(%s, 0x%08X)\n", macro_name.get_ptr(), custom_array_size_macro_indices[i]);
2695             vogl_fprintf(pFile, "   #else\n");
2696             vogl_fprintf(pFile, "      VALIDATE_ARRAY_SIZE_MACRO_NOT_DEFINED(%s, 0x%08X)\n", macro_name.get_ptr(), custom_array_size_macro_indices[i]);
2697             vogl_fprintf(pFile, "   #endif\n");
2698             vogl_fprintf(pFile, "#endif\n");
2699         }
2700         vogl_fclose(pFile);
2701
2702         // -- Generate the gl_glx_custom_return_param_array_size_macro_validator.inc include file
2703         pFile = fopen_and_log("gl_glx_custom_return_param_array_size_macro_validator.inc", "w");
2704         for (uint i = 0; i < custom_return_param_array_size_macros.size(); i++)
2705         {
2706             dynamic_string macro_name(custom_return_param_array_size_macros[i]);
2707             int n = macro_name.find_left('(');
2708             if (n >= 0)
2709                 macro_name.truncate(n);
2710
2711             vogl_fprintf(pFile, "#ifdef %s\n", macro_name.get_ptr());
2712             vogl_fprintf(pFile, "   CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_DEFINED(%s, %s)\n", macro_name.get_ptr(), funcs_with_return_param_array_size_macros[i].get_ptr());
2713             vogl_fprintf(pFile, "#else\n");
2714             vogl_fprintf(pFile, "   CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_NOT_DEFINED(%s, %s)\n", macro_name.get_ptr(), funcs_with_return_param_array_size_macros[i].get_ptr());
2715             vogl_fprintf(pFile, "#endif\n");
2716         }
2717         vogl_fclose(pFile);
2718
2719         // -- Generate the gl_glx_custom_func_handler_validator.inc include file
2720         pFile = fopen_and_log("gl_glx_custom_func_handler_validator.inc", "w");
2721         for (uint i = 0; i < m_all_gl_funcs.size(); i++)
2722         {
2723             vogl_fprintf(pFile, "#ifdef DEF_FUNCTION_CUSTOM_HANDLER_%s%s\n", g_lib_api_prefixes[m_all_gl_funcs[i].m_lib], m_all_gl_funcs[i].m_name.get_ptr());
2724             vogl_fprintf(pFile, "   CUSTOM_FUNC_HANDLER_DEFINED(%u)\n", i);
2725             vogl_fprintf(pFile, "#else\n");
2726             vogl_fprintf(pFile, "   CUSTOM_FUNC_HANDLER_NOT_DEFINED(%u)\n", i);
2727             vogl_fprintf(pFile, "#endif\n");
2728         }
2729         vogl_fclose(pFile);
2730
2731         // -- Generate the gl_glx_array_size_macro_func_param_indices.inc include file
2732         pFile = fopen_and_log("gl_glx_array_size_macro_func_param_indices.inc", "w");
2733         for (uint i = 0; i < custom_array_size_macro_indices.size(); i++)
2734         {
2735             if (i)
2736                 vogl_fprintf(pFile, ",");
2737             vogl_fprintf(pFile, "0x%08X", custom_array_size_macro_indices[i]);
2738             if ((i & 31) == 31)
2739                 vogl_fprintf(pFile, "\n");
2740         }
2741         vogl_fprintf(pFile, "\n");
2742         vogl_fclose(pFile);
2743
2744         if (!generate_gl_gets_inc_file())
2745             return false;
2746
2747         if (!generate_libvogltrace_export_script())
2748             return false;
2749
2750         return true;
2751     }
2752
2753 private:
2754     //-----------------------------------------------------------------------------------------------------------------------
2755     // init_gl_gets
2756     //-----------------------------------------------------------------------------------------------------------------------
2757     bool init_gl_gets()
2758     {
2759         static const struct gl_get_files
2760         {
2761             const char *m_pFilename;
2762             uint m_vers;
2763         } s_gl_get_files[] =
2764               {
2765                   { "gl10_gets.txt", 0x10 },
2766                   { "gl15_gets.txt", 0x15 },
2767                   { "gl21_gets.txt", 0x21 },
2768                   { "gl33_gets.txt", 0x33 },
2769                   { "gl40_gets.txt", 0x40 },
2770                   { "gl41_gets.txt", 0x41 },
2771                   { "gl42_gets.txt", 0x42 },
2772                   { "gl43_gets.txt", 0x43 }
2773               };
2774
2775         for (uint file_iter = 0; file_iter < sizeof(s_gl_get_files) / sizeof(s_gl_get_files[0]); file_iter++)
2776         {
2777             const char *pFilename = s_gl_get_files[file_iter].m_pFilename;
2778
2779             //         typedef vogl::hash_map<dynamic_string, gl_get> gl_get_hash_map;
2780             //         gl_get_hash_map m_gl_gets;
2781
2782             dynamic_string_array get_names;
2783
2784             if (!file_utils::read_text_file(pFilename, get_names, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintErrorMessages))
2785                 return false;
2786
2787             for (uint i = 0; i < get_names.size(); i++)
2788             {
2789                 if ((get_names[i].toupper().compare(get_names[i], true) != 0) || (get_names[i].contains(' ')))
2790                 {
2791                     console::error("In file %s, enum name is invalid: \"%s\"\n", pFilename, get_names[i].get_ptr());
2792                     return false;
2793                 }
2794
2795                 gl_get_hash_map::insert_result ins_res(m_gl_gets.insert(get_names[i], gl_get()));
2796                 gl_get &gl_get_obj = ins_res.first->second;
2797                 gl_get_obj.m_name = get_names[i];
2798                 gl_get_obj.m_min_vers = vogl::math::minimum(gl_get_obj.m_min_vers, s_gl_get_files[file_iter].m_vers);
2799                 gl_get_obj.m_max_vers = vogl::math::maximum(gl_get_obj.m_max_vers, s_gl_get_files[file_iter].m_vers);
2800             }
2801         }
2802
2803         //for (gl_get_hash_map::const_iterator it = m_gl_gets.begin(); it != m_gl_gets.end(); ++it)
2804         //   printf("%s 0x%04X 0x%04X\n", it->first.get_ptr(), it->second.m_min_vers, it->second.m_max_vers);
2805
2806         return true;
2807     }
2808
2809     bool generate_libvogltrace_export_script() const
2810     {
2811 #if 0
2812                 // We're writing an anonymous version map on purpose, otherwise bad shit happens in some apps!
2813                 {
2814 global:
2815                         OpenDebugManager;
2816                         OpenDebugSession;
2817 local:
2818                         *;
2819                 };
2820 #endif
2821
2822         const char *pFilename = "libvogltrace_linker_script.txt";
2823         cfile_stream export_script(pFilename, cDataStreamWritable);
2824
2825         console::info("--- Generating \"%s\":\n", pFilename);
2826
2827         export_script.puts("{\n");
2828         export_script.puts("  global:\n");
2829
2830         for (uint i = 0; i < m_gl_so_function_exports.size(); i++)
2831             export_script.printf("    %s;\n", m_gl_so_function_exports[i].get_ptr());
2832
2833         dynamic_string_array nongenerated_exports;
2834         file_utils::read_text_file("gl_glx_nongenerated_so_export_list.txt", nongenerated_exports, file_utils::cRTFPrintWarningMessages);
2835
2836         for (uint i = 0; i < nongenerated_exports.size(); i++)
2837             export_script.printf("    %s;\n", nongenerated_exports[i].get_ptr());
2838
2839         export_script.puts("  local:\n");
2840         export_script.puts("    *;\n");
2841         export_script.puts("};\n");
2842
2843         return true;
2844     }
2845
2846     //-----------------------------------------------------------------------------------------------------------------------
2847     // generate_gl_gets_inc_file
2848     //-----------------------------------------------------------------------------------------------------------------------
2849     bool generate_gl_gets_inc_file() const
2850     {
2851         // Note: I used this to generate our first gl_gets.inc file, which then had to be hand edited.
2852         const char *pFilename = "gl_gets_approx.inc";
2853         cfile_stream gl_gets_inc(pFilename, cDataStreamWritable);
2854
2855         if (!gl_gets_inc.is_opened())
2856         {
2857             console::error("Failed creating file %s!\n", pFilename);
2858             return false;
2859         }
2860
2861         console::info("--- Generating \"%s\":\n", pFilename);
2862
2863         vogl::vector<gl_get> sorted_gets;
2864         for (gl_get_hash_map::const_iterator it = m_gl_gets.begin(); it != m_gl_gets.end(); ++it)
2865             sorted_gets.push_back(it->second);
2866         sorted_gets.sort();
2867
2868         int prev_min_vers = -1;
2869         int prev_max_vers = -1;
2870         for (uint i = 0; i < sorted_gets.size(); i++)
2871         {
2872             if ((prev_min_vers != static_cast<int>(sorted_gets[i].m_min_vers)) || (prev_max_vers != static_cast<int>(sorted_gets[i].m_max_vers)))
2873             {
2874                 gl_gets_inc.printf("// Start of version %u.%u - %u.%u\n", sorted_gets[i].m_min_vers >> 4, sorted_gets[i].m_min_vers & 0xF, sorted_gets[i].m_max_vers >> 4, sorted_gets[i].m_max_vers & 0xF);
2875                 prev_min_vers = sorted_gets[i].m_min_vers;
2876                 prev_max_vers = sorted_gets[i].m_max_vers;
2877             }
2878             gl_gets_inc.printf("DEFINE_GL_GET(%s, 0x%04X, 0x%04X)\n", sorted_gets[i].m_name.get_ptr(), sorted_gets[i].m_min_vers, sorted_gets[i].m_max_vers);
2879         }
2880
2881         return true;
2882     }
2883
2884     //-----------------------------------------------------------------------------------------------------------------------
2885     // ensure_gl_exports_are_defined
2886     //-----------------------------------------------------------------------------------------------------------------------
2887     bool ensure_gl_exports_are_defined(gl_function_specs &gl_funcs, const gl_function_specs &glx_funcs, const gl_function_specs &glxext_funcs)
2888     {
2889         cfile_stream list_file("gl_glx_so_export_list.txt", cDataStreamReadable);
2890         if (!list_file.is_opened())
2891             return false;
2892
2893         dynamic_string line_str;
2894         while (list_file.get_remaining())
2895         {
2896             if (!list_file.read_line(line_str))
2897                 break;
2898
2899             line_str.trim();
2900             if (line_str.is_empty())
2901                 continue;
2902
2903             dynamic_string func;
2904             const gl_function_specs *pSpecs = NULL;
2905             if (line_str.find_left("glX") == 0)
2906             {
2907                 func.set(line_str).right(3);
2908                 pSpecs = &glx_funcs;
2909             }
2910             else if (line_str.find_left("gl") == 0)
2911             {
2912                 func.set(line_str).right(2);
2913                 pSpecs = &gl_funcs;
2914             }
2915
2916             if (!pSpecs)
2917             {
2918                 console::warning("Unrecognized SO export: %s\n", line_str.get_ptr());
2919                 continue;
2920             }
2921
2922             const gl_function_def *pFunc = pSpecs->find(func.get_ptr());
2923             if ((!pFunc) && (pSpecs == &glx_funcs))
2924             {
2925                 pSpecs = &glxext_funcs;
2926                 pFunc = pSpecs->find(func.get_ptr());
2927             }
2928
2929             if (!pFunc)
2930             {
2931                 if (func.ends_with("OES", true) || func.ends_with("x", true) || func.ends_with("NV", true) || func.ends_with("NVX") ||
2932                     func.ends_with("SGI") || func.ends_with("EXT") || func.ends_with("X") || func.ends_with("xv") || func.ends_with("Autodesk") ||
2933                     func.ends_with("WIN"))
2934                 {
2935                     //console::warning("Skipping missing SO export: %s\n", line_str.get_ptr());
2936                     continue;
2937                 }
2938
2939                 console::warning("Can't find SO export in spec files: %s\n", line_str.get_ptr());
2940                 continue;
2941             }
2942
2943             //printf("Found %s\n", pFunc->m_name.get_ptr());
2944         }
2945
2946         return true;
2947     }
2948
2949     //-----------------------------------------------------------------------------------------------------------------------
2950     // load_gl_so_function_export_list
2951     //-----------------------------------------------------------------------------------------------------------------------
2952     bool load_gl_so_function_export_list(const char *pFilename, dynamic_string_array &gl_so_function_exports)
2953     {
2954         cfile_stream list_file(pFilename, cDataStreamReadable);
2955         if (!list_file.is_opened())
2956             return false;
2957
2958         dynamic_string line_str;
2959         while (list_file.get_remaining())
2960         {
2961             if (!list_file.read_line(line_str))
2962                 break;
2963
2964             line_str.trim();
2965             if (line_str.is_empty())
2966                 continue;
2967
2968             gl_so_function_exports.push_back(line_str);
2969         }
2970
2971         gl_so_function_exports.sort();
2972
2973         return true;
2974     }
2975
2976     //-----------------------------------------------------------------------------------------------------------------------
2977     // translate_ctype_to_ctype_enum
2978     //-----------------------------------------------------------------------------------------------------------------------
2979     dynamic_string translate_ctype_to_ctype_enum(dynamic_string ctype)
2980     {
2981         ctype.trim().toupper().replace("_", "");
2982
2983         uint num_found;
2984         do
2985         {
2986             ctype.replace(" *", "*", true, &num_found);
2987         } while (num_found);
2988
2989         do
2990         {
2991             ctype.replace("  ", " ", true, &num_found);
2992         } while (num_found);
2993
2994         ctype.replace(" ", "_");
2995         ctype.replace("*", "_PTR");
2996
2997         return "VOGL_" + ctype;
2998     }
2999
3000     //-----------------------------------------------------------------------------------------------------------------------
3001     // determine_ctypes
3002     //-----------------------------------------------------------------------------------------------------------------------
3003     bool determine_ctypes(const char *pFunc_prefix, gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap)
3004     {
3005         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3006         {
3007             gl_function_def &func = gl_funcs[func_index];
3008
3009             dynamic_string full_func_name(cVarArg, "%s%s", pFunc_prefix, func.m_name.get_ptr());
3010
3011             if (func.m_return == "void")
3012                 func.m_return_ctype = "void";
3013             else
3014             {
3015                 const dynamic_string *pCType = typemap.find(func.m_return);
3016                 if (!pCType)
3017                     pCType = alt_typemap.find(func.m_return);
3018                 if (!pCType)
3019                 {
3020                     console::warning("Unable to map spec type %s\n", func.m_return.get_ptr());
3021                     return false;
3022                 }
3023
3024                 func.m_return_ctype = *pCType;
3025             }
3026             func.m_return_ctype_enum = translate_ctype_to_ctype_enum(func.m_return_ctype);
3027
3028             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3029             {
3030                 gl_function_param &param = func.m_params[param_index];
3031
3032                 const dynamic_string *pCType = typemap.find(param.m_type);
3033                 if (!pCType)
3034                     pCType = alt_typemap.find(param.m_type);
3035                 if (!pCType)
3036                 {
3037                     console::warning("Unable to map spec type %s\n", param.m_type.get_ptr());
3038                     return false;
3039                 }
3040
3041                 dynamic_string type_prefix;
3042
3043                 dynamic_string type_suffix("");
3044                 if ((param.m_semantic == "array") || (param.m_semantic == "reference"))
3045                 {
3046                     type_suffix = " *";
3047
3048                     if (param.m_direction == "in")
3049                     {
3050                         if (!pCType->ends_with("const"))
3051                             type_prefix = "const ";
3052                     }
3053                 }
3054
3055                 dynamic_string full_ctype(cVarArg, "%s%s%s", type_prefix.get_ptr(), pCType->get_ptr(), type_suffix.get_ptr());
3056
3057                 param.m_ctype = full_ctype;
3058                 param.m_ctype_enum = translate_ctype_to_ctype_enum(full_ctype);
3059             }
3060         }
3061
3062         return true;
3063     }
3064
3065     //-----------------------------------------------------------------------------------------------------------------------
3066     // get_func_proto_macro
3067     //-----------------------------------------------------------------------------------------------------------------------
3068     dynamic_string get_func_proto_macro(const char *pFunc_prefix, const gl_function_def &func, const dynamic_string_array &sorted_gl_so_function_exports) const
3069     {
3070         dynamic_string proto;
3071
3072         dynamic_string full_func_name(cVarArg, "%s%s", pFunc_prefix, func.m_name.get_ptr());
3073
3074         dynamic_string exported_param((func.m_return == "void") ? "DEF_PROTO_INTERNAL_VOID" : "DEF_PROTO_INTERNAL");
3075         int export_index = sorted_gl_so_function_exports.find_sorted(full_func_name);
3076         if (export_index >= 0)
3077             exported_param = (func.m_return == "void") ? "DEF_PROTO_EXPORTED_VOID" : "DEF_PROTO_EXPORTED";
3078
3079         dynamic_string category(func.m_category.get_len() ? func.m_category.get_ptr() : "UNDEFINED");
3080
3081         proto.format_append("( %s, %s, %s, %s, %u, ", exported_param.get_ptr(), category.get_ptr(), func.m_return_ctype.get_ptr(), func.m_return_ctype_enum.get_ptr(), func.m_params.size());
3082
3083         proto.format_append("%s, ", full_func_name.get_ptr());
3084
3085         proto.format_append("(");
3086         for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3087         {
3088             const gl_function_param &param = func.m_params[param_index];
3089
3090             proto.format_append("%s%s%s", param.m_ctype.get_ptr(), param.m_ctype.ends_with("*") ? "" : " ", param.m_name.get_ptr());
3091             if (param_index != func.m_params.size() - 1)
3092                 proto.format_append(", ");
3093         }
3094
3095         proto.format_append("), ");
3096
3097         proto.format_append("(");
3098         for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3099         {
3100             proto.format_append("%s", func.m_params[param_index].m_name.get_ptr());
3101             if (param_index != func.m_params.size() - 1)
3102                 proto.format_append(", ");
3103         }
3104
3105         proto.format_append(") )");
3106
3107         return proto;
3108     }
3109
3110     //-----------------------------------------------------------------------------------------------------------------------
3111     // process_func_protos
3112     //-----------------------------------------------------------------------------------------------------------------------
3113     bool process_func_protos(
3114         const char *pFunc_prefix, const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const dynamic_string_array &sorted_gl_so_function_exports,
3115         gl_string_set &all_gl_ctypes, gl_string_set &all_gl_categories, gl_string_set &array_sizes)
3116     {
3117         VOGL_NOTE_UNUSED(pFunc_prefix);
3118         VOGL_NOTE_UNUSED(typemap);
3119         VOGL_NOTE_UNUSED(alt_typemap);
3120         VOGL_NOTE_UNUSED(sorted_gl_so_function_exports);
3121
3122         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3123         {
3124             const gl_function_def &func = gl_funcs[func_index];
3125
3126             all_gl_categories.insert(func.m_category);
3127             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3128             {
3129                 const gl_function_param &param = func.m_params[param_index];
3130
3131                 all_gl_ctypes.insert(param.m_ctype);
3132                 array_sizes.insert(param.m_array_size);
3133             }
3134         }
3135
3136         return true;
3137     }
3138
3139     //-----------------------------------------------------------------------------------------------------------------------
3140     // dump_func_proto_macros
3141     //-----------------------------------------------------------------------------------------------------------------------
3142     bool dump_func_proto_macros(FILE *pFile, const char *pFunc_prefix, const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const dynamic_string_array &sorted_gl_so_function_exports) const
3143     {
3144         VOGL_NOTE_UNUSED(typemap);
3145         VOGL_NOTE_UNUSED(alt_typemap);
3146
3147         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3148         {
3149             const gl_function_def &func = gl_funcs[func_index];
3150
3151             dynamic_string func_proto(get_func_proto_macro(pFunc_prefix, func, sorted_gl_so_function_exports));
3152
3153             vogl_fprintf(pFile, "%s%s\n", (func.m_return_ctype == "void") ? "DEF_PROTO_VOID" : "DEF_PROTO", func_proto.get_ptr());
3154         }
3155
3156         return true;
3157     }
3158
3159     //-----------------------------------------------------------------------------------------------------------------------
3160     // func_param_translate_array_size
3161     //-----------------------------------------------------------------------------------------------------------------------
3162     dynamic_string func_param_translate_array_size(const char *pFunc_prefix, const gl_function_def &func, const gl_function_param &param, const dynamic_string &func_proto, bool *pCustom_macro_flag = NULL) const
3163     {
3164         if (pCustom_macro_flag)
3165             *pCustom_macro_flag = false;
3166
3167         if (param.m_array_size.begins_with("[") && param.m_array_size.ends_with("]"))
3168         {
3169             dynamic_string array_size_param(param.m_array_size);
3170             array_size_param.mid(1, array_size_param.get_len() - 2);
3171
3172             for (uint i = 0; i < func.m_params.size(); i++)
3173                 if ((func.m_params[i].m_name == array_size_param) ||
3174                     ((func.m_params[i].m_name + "*1") == array_size_param) ||
3175                     ((func.m_params[i].m_name + "*2") == array_size_param) ||
3176                     ((func.m_params[i].m_name + "*3") == array_size_param) ||
3177                     ((func.m_params[i].m_name + "*4") == array_size_param) ||
3178                     ((func.m_params[i].m_name + "*5") == array_size_param) ||
3179                     ((func.m_params[i].m_name + "*6") == array_size_param) ||
3180                     ((func.m_params[i].m_name + "*7") == array_size_param) ||
3181                     ((func.m_params[i].m_name + "*8") == array_size_param) ||
3182                     ((func.m_params[i].m_name + "*9") == array_size_param) ||
3183                     ((func.m_params[i].m_name + "*10") == array_size_param) ||
3184                     ((func.m_params[i].m_name + "*11") == array_size_param) ||
3185                     ((func.m_params[i].m_name + "*12") == array_size_param) ||
3186                     ((func.m_params[i].m_name + "*13") == array_size_param) ||
3187                     ((func.m_params[i].m_name + "*14") == array_size_param) ||
3188                     ((func.m_params[i].m_name + "*15") == array_size_param) ||
3189                     ((func.m_params[i].m_name + "*16") == array_size_param))
3190                 {
3191                     if (func.m_params[i].m_semantic == "value")
3192                         return array_size_param;
3193                     //else if (func.m_params[i].m_semantic == "reference")
3194                     //   return dynamic_string(cVarArg, "%s ? *%s : -2", array_size_param.get_ptr(), array_size_param.get_ptr());
3195                     //else if ((func.m_params[i].m_semantic == "array") && (func.m_params[i].m_array_size == "[1]"))
3196                     //   return dynamic_string(cVarArg, "%s ? *%s : -2", array_size_param.get_ptr(), array_size_param.get_ptr());
3197                 }
3198
3199             if (array_size_param == "0" || array_size_param == "1" || array_size_param == "2" ||
3200                 array_size_param == "3" || array_size_param == "4" || array_size_param == "5" ||
3201                 array_size_param == "6" || array_size_param == "7" || array_size_param == "8" ||
3202                 array_size_param == "9" || array_size_param == "12" || array_size_param == "16")
3203             {
3204                 return array_size_param;
3205             }
3206
3207             if (array_size_param.begins_with("COMPSIZE(") && array_size_param.ends_with(")"))
3208             {
3209                 dynamic_string comp_size_param(array_size_param);
3210                 comp_size_param.mid(9, comp_size_param.get_len() - 10);
3211
3212                 // each of these are assumed to be a GL enum
3213                 if ((comp_size_param == "pname") || (comp_size_param == "attribute") ||
3214                     (comp_size_param == "id") ||  //(comp_size_param == "buffer") ||
3215                     (comp_size_param == "map") || //(comp_size_param == "name") ||
3216                     (comp_size_param == "path") || (comp_size_param == "query") ||
3217                     (comp_size_param == "target") || (comp_size_param == "type") ||
3218                     (comp_size_param == "value"))
3219                     return dynamic_string(cVarArg, "DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM(%s)", comp_size_param.get_ptr());
3220
3221                 // these might be wrong
3222                 for (uint i = 0; i < func.m_params.size(); i++)
3223                     if (((func.m_params[i].m_name + "*2") == comp_size_param) ||
3224                         ((func.m_params[i].m_name + "*3") == comp_size_param) ||
3225                         ((func.m_params[i].m_name + "*4") == comp_size_param))
3226                     {
3227                         return dynamic_string(cVarArg, "DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM(%s)", comp_size_param.get_ptr());
3228                     }
3229             }
3230         }
3231
3232         if (pCustom_macro_flag)
3233             *pCustom_macro_flag = true;
3234
3235         dynamic_string custom_array_size(cVarArg, "DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_%s%s_%s%s", pFunc_prefix, func.m_name.get_ptr(), param.m_name.get_ptr(), func_proto.get_ptr());
3236         return custom_array_size;
3237     }
3238
3239     //-----------------------------------------------------------------------------------------------------------------------
3240     // create_array_size_macros
3241     // TODO: use funcs_with_custom_array_size_macros[] vs. scanning for DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_
3242     //-----------------------------------------------------------------------------------------------------------------------
3243     void create_array_size_macros(const char *pFunc_prefix, const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const dynamic_string_array &sorted_gl_so_function_exports,
3244                                   gl_string_set &custom_array_size_macros, vogl::vector<uint> &custom_array_size_macro_indices, dynamic_string_array &custom_array_size_macro_names, uint &cur_func_id) const
3245     {
3246         VOGL_NOTE_UNUSED(typemap);
3247         VOGL_NOTE_UNUSED(alt_typemap);
3248
3249         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3250         {
3251             const gl_function_def &func = gl_funcs[func_index];
3252
3253             dynamic_string func_proto(get_func_proto_macro(pFunc_prefix, func, sorted_gl_so_function_exports));
3254
3255             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3256             {
3257                 const gl_function_param &param = func.m_params[param_index];
3258
3259                 if (param.m_semantic == "array")
3260                 {
3261                     dynamic_string array_size_macro(func_param_translate_array_size(pFunc_prefix, func, param, func_proto));
3262                     if (array_size_macro.begins_with("DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_"))
3263                     {
3264                         custom_array_size_macros.insert(array_size_macro);
3265
3266                         // oh god this is ugly
3267                         dynamic_string macro_name(array_size_macro);
3268                         int n = macro_name.find_left('(');
3269                         if (n >= 0)
3270                             macro_name.truncate(n);
3271
3272                         custom_array_size_macro_indices.push_back((cur_func_id << 16) | param_index);
3273                         custom_array_size_macro_names.push_back(macro_name);
3274                     }
3275                 }
3276             }
3277
3278             cur_func_id++;
3279         }
3280     }
3281
3282     //-----------------------------------------------------------------------------------------------------------------------
3283     // process_func_defs
3284     //-----------------------------------------------------------------------------------------------------------------------
3285     bool process_func_defs(const char *pFunc_prefix, const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const dynamic_string_array &sorted_gl_so_function_exports,
3286                            const dynamic_string_array &whitelisted_funcs,
3287                            const dynamic_string_array &nullable_funcs,
3288                            dynamic_string_array &funcs_with_custom_array_size_macros,
3289                            dynamic_string_array &custom_return_param_array_size_macros,
3290                            dynamic_string_array &funcs_with_return_param_array_size_macros)
3291     {
3292         VOGL_NOTE_UNUSED(typemap);
3293         VOGL_NOTE_UNUSED(alt_typemap);
3294         VOGL_NOTE_UNUSED(nullable_funcs);
3295
3296         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3297         {
3298             const gl_function_def &func = gl_funcs[func_index];
3299
3300             dynamic_string full_func_name(func.m_full_name); //cVarArg, "%s%s", pFunc_prefix, func.m_name.get_ptr());
3301
3302             bool is_in_whitelist = false;
3303             VOGL_NOTE_UNUSED(is_in_whitelist);
3304             for (uint i = 0; i < whitelisted_funcs.size(); i++)
3305             {
3306                 if (whitelisted_funcs[i] == full_func_name)
3307                 {
3308                     is_in_whitelist = true;
3309                     break;
3310                 }
3311             }
3312
3313             dynamic_string func_proto(get_func_proto_macro(pFunc_prefix, func, sorted_gl_so_function_exports));
3314
3315             // TODO: This (func_has_custom_array_size_macros) is dead code
3316             bool func_has_custom_array_size_macros = false;
3317
3318             dynamic_string func_params;
3319
3320             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3321             {
3322                 const gl_function_param &param = func.m_params[param_index];
3323
3324                 func_params.append(param.m_name);
3325                 if (param_index != (func.m_params.size() - 1))
3326                     func_params.append(", ");
3327             }
3328
3329             if (func.m_return != "void")
3330             {
3331                 dynamic_string return_param_compute_array_size_macro_name(cVarArg, "DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_%s(%s)", full_func_name.get_ptr(), func_params.get_ptr());
3332
3333                 custom_return_param_array_size_macros.push_back(return_param_compute_array_size_macro_name);
3334                 funcs_with_return_param_array_size_macros.push_back(full_func_name);
3335             }
3336
3337             if (func_has_custom_array_size_macros)
3338             {
3339                 funcs_with_custom_array_size_macros.push_back(full_func_name);
3340             }
3341         }
3342
3343         return true;
3344     }
3345
3346     //-----------------------------------------------------------------------------------------------------------------------
3347     // dump_func_def_macros
3348     //-----------------------------------------------------------------------------------------------------------------------
3349     bool dump_func_def_macros(FILE *pFile, const char *pFunc_prefix, const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const dynamic_string_array &sorted_gl_so_function_exports,
3350                               const dynamic_string_array &whitelisted_funcs,
3351                               const dynamic_string_array &nullable_funcs) const
3352     {
3353         VOGL_NOTE_UNUSED(typemap);
3354         VOGL_NOTE_UNUSED(alt_typemap);
3355         VOGL_NOTE_UNUSED(nullable_funcs);
3356
3357         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3358         {
3359             const gl_function_def &func = gl_funcs[func_index];
3360
3361             dynamic_string full_func_name(cVarArg, "%s%s", pFunc_prefix, func.m_name.get_ptr());
3362
3363             bool is_in_whitelist = false;
3364             VOGL_NOTE_UNUSED(is_in_whitelist);
3365             for (uint i = 0; i < whitelisted_funcs.size(); i++)
3366             {
3367                 if (whitelisted_funcs[i] == full_func_name)
3368                 {
3369                     is_in_whitelist = true;
3370                     break;
3371                 }
3372             }
3373
3374             dynamic_string func_proto(get_func_proto_macro(pFunc_prefix, func, sorted_gl_so_function_exports));
3375
3376             vogl_fprintf(pFile, "// %s Category: %s Vers: \"%s\" Deprecated: \"%s\" Profile: \"%s\"\n", full_func_name.get_ptr(), func.m_category.get_ptr(), func.m_version.get_ptr(), func.m_deprecated.get_ptr(), func.m_profile.get_ptr());
3377
3378             vogl_fprintf(pFile, "#ifdef DEF_FUNCTION_CUSTOM_HANDLER_%s\n", full_func_name.get_ptr());
3379
3380             vogl_fprintf(pFile, "   DEF_FUNCTION_CUSTOM_HANDLER_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3381             vogl_fprintf(pFile, "   #undef DEF_FUNCTION_CUSTOM_HANDLER_%s\n", full_func_name.get_ptr());
3382
3383             vogl_fprintf(pFile, "#else\n");
3384
3385             vogl_fprintf(pFile, "   DEF_FUNCTION_BEGIN%s%s\n", func.m_return == "void" ? "_VOID" : "", func_proto.get_ptr());
3386
3387             vogl_fprintf(pFile, "   #ifdef DEF_FUNCTION_CUSTOM_FUNC_PROLOG_%s\n", full_func_name.get_ptr());
3388             vogl_fprintf(pFile, "      DEF_FUNCTION_CUSTOM_FUNC_PROLOG_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3389             vogl_fprintf(pFile, "      #undef DEF_FUNCTION_CUSTOM_FUNC_PROLOG_%s\n", full_func_name.get_ptr());
3390             vogl_fprintf(pFile, "   #endif\n");
3391
3392             vogl_fprintf(pFile, "   DEF_FUNCTION_INIT%s%s\n", func.m_return == "void" ? "_VOID" : "", func_proto.get_ptr());
3393
3394             bool func_has_custom_array_size_macros = false;
3395
3396             dynamic_string func_params;
3397
3398             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3399             {
3400                 const gl_function_param &param = func.m_params[param_index];
3401
3402                 func_params.append(param.m_name);
3403                 if (param_index != (func.m_params.size() - 1))
3404                     func_params.append(", ");
3405
3406                 if (param.m_direction != "in")
3407                     continue;
3408
3409                 if (param.m_semantic == "value")
3410                 {
3411                     vogl_fprintf(pFile, "   DEF_FUNCTION_INPUT_VALUE_PARAM( %u, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3412                 }
3413                 else if (param.m_semantic == "array")
3414                 {
3415                     vogl_fprintf(pFile, "   // %s ArraySize=%s\n", param.m_name.get_ptr(), param.m_array_size.get_ptr());
3416                     vogl_fprintf(pFile, "   DEF_FUNCTION_INPUT_ARRAY_PARAM( %u, %s, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr(), func_param_translate_array_size(pFunc_prefix, func, param, func_proto, &func_has_custom_array_size_macros).get_ptr());
3417                 }
3418                 else if (param.m_semantic == "reference")
3419                 {
3420                     vogl_fprintf(pFile, "   DEF_FUNCTION_INPUT_REFERENCE_PARAM( %u, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3421                 }
3422             }
3423
3424             vogl_fprintf(pFile, "   #ifdef DEF_FUNCTION_CUSTOM_GL_CALLER_%s\n", full_func_name.get_ptr());
3425             vogl_fprintf(pFile, "      DEF_FUNCTION_CUSTOM_GL_CALLER_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3426             vogl_fprintf(pFile, "      #undef DEF_FUNCTION_CUSTOM_GL_CALLER_%s\n", full_func_name.get_ptr());
3427
3428             vogl_fprintf(pFile, "   #else\n");
3429
3430             vogl_fprintf(pFile, "      #ifdef DEF_FUNCTION_CUSTOM_GL_PROLOG_%s\n", full_func_name.get_ptr());
3431             vogl_fprintf(pFile, "         DEF_FUNCTION_CUSTOM_GL_PROLOG_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3432             vogl_fprintf(pFile, "         #undef DEF_FUNCTION_CUSTOM_GL_PROLOG_%s\n", full_func_name.get_ptr());
3433             vogl_fprintf(pFile, "      #endif\n");
3434
3435             vogl_fprintf(pFile, "      DEF_FUNCTION_CALL_GL%s%s\n", func.m_return == "void" ? "_VOID" : "", func_proto.get_ptr());
3436
3437             vogl_fprintf(pFile, "      #ifdef DEF_FUNCTION_CUSTOM_GL_EPILOG_%s\n", full_func_name.get_ptr());
3438             vogl_fprintf(pFile, "         DEF_FUNCTION_CUSTOM_GL_EPILOG_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3439             vogl_fprintf(pFile, "         #undef DEF_FUNCTION_CUSTOM_GL_EPILOG_%s\n", full_func_name.get_ptr());
3440             vogl_fprintf(pFile, "      #endif\n");
3441
3442             vogl_fprintf(pFile, "   #endif\n");
3443
3444             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3445             {
3446                 const gl_function_param &param = func.m_params[param_index];
3447                 if (param.m_direction != "out")
3448                     continue;
3449
3450                 if (param.m_semantic == "value")
3451                 {
3452                     vogl_fprintf(pFile, "   DEF_FUNCTION_OUTPUT_VALUE_PARAM( %u, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3453                 }
3454                 else if (param.m_semantic == "array")
3455                 {
3456                     vogl_fprintf(pFile, "   // %s ArraySize=%s\n", param.m_name.get_ptr(), param.m_array_size.get_ptr());
3457                     vogl_fprintf(pFile, "   DEF_FUNCTION_OUTPUT_ARRAY_PARAM( %u, %s, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr(), func_param_translate_array_size(pFunc_prefix, func, param, func_proto, &func_has_custom_array_size_macros).get_ptr());
3458                 }
3459                 else if (param.m_semantic == "reference")
3460                 {
3461                     vogl_fprintf(pFile, "   DEF_FUNCTION_OUTPUT_REFERENCE_PARAM( %u, %s, %s, %s, %s )\n", param_index, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3462                 }
3463             }
3464
3465             vogl_fprintf(pFile, "   #ifdef DEF_FUNCTION_CUSTOM_FUNC_EPILOG_%s\n", full_func_name.get_ptr());
3466             vogl_fprintf(pFile, "      DEF_FUNCTION_CUSTOM_FUNC_EPILOG_%s%s\n", full_func_name.get_ptr(), func_proto.get_ptr());
3467             vogl_fprintf(pFile, "      #undef DEF_FUNCTION_CUSTOM_FUNC_EPILOG_%s\n", full_func_name.get_ptr());
3468             vogl_fprintf(pFile, "   #endif\n");
3469
3470             if (func.m_return != "void")
3471             {
3472                 //vogl_fprintf(pFile, "   DEF_FUNCTION_RETURN_PARAM( %s, %s, %s, )\n", func.m_return.get_ptr(), func.m_return_ctype.get_ptr(), func.m_return_ctype_enum.get_ptr());
3473                 dynamic_string return_param_compute_array_size_macro_name(cVarArg, "DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_%s(%s)", full_func_name.get_ptr(), func_params.get_ptr());
3474
3475                 vogl_fprintf(pFile, "   DEF_FUNCTION_RETURN_PARAM( %s, %s, %s, %s )\n", func.m_return.get_ptr(), func.m_return_ctype.get_ptr(), func.m_return_ctype_enum.get_ptr(), return_param_compute_array_size_macro_name.get_ptr());
3476             }
3477
3478             vogl_fprintf(pFile, "   DEF_FUNCTION_END%s%s\n", func.m_return == "void" ? "_VOID" : "", func_proto.get_ptr());
3479
3480             vogl_fprintf(pFile, "#endif\n");
3481             vogl_fprintf(pFile, "\n");
3482         }
3483
3484         return true;
3485     }
3486
3487     //-----------------------------------------------------------------------------------------------------------------------
3488     // dump_func_desc_macros
3489     //-----------------------------------------------------------------------------------------------------------------------
3490     bool dump_func_desc_macros(
3491         FILE *pFile, const char *pFunc_prefix,
3492         const gl_function_specs &gl_funcs, const gl_types &typemap, const gl_types &alt_typemap, const apitrace_func_specs &apitrace_gl_func_specs,
3493         const dynamic_string_array &sorted_gl_so_function_exports, const dynamic_string_array &whitelisted_funcs, const dynamic_string_array &nullable_funcs, const dynamic_string_array &whitelisted_displaylists_funcs) const
3494     {
3495         VOGL_NOTE_UNUSED(typemap);
3496         VOGL_NOTE_UNUSED(alt_typemap);
3497
3498         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3499         {
3500             const gl_function_def &func = gl_funcs[func_index];
3501
3502             dynamic_string full_func_name(cVarArg, "%s%s", pFunc_prefix, func.m_name.get_ptr());
3503             VOGL_ASSERT(full_func_name.compare(func.m_full_name, true) == 0);
3504
3505             const apitrace_gl_func_def *pApitrace_func_def = apitrace_gl_func_specs.find(full_func_name.get_ptr());
3506
3507             bool is_in_whitelist = whitelisted_funcs.find(full_func_name) != cInvalidIndex;
3508             bool is_nullable = nullable_funcs.find(full_func_name) != cInvalidIndex;
3509
3510             bool is_whitelisted_for_displaylists = false;
3511             for (uint i = 0; i < whitelisted_displaylists_funcs.size(); i++)
3512             {
3513                 if (regexp_full_match(func.m_full_name.get_ptr(), whitelisted_displaylists_funcs[i].get_ptr()))
3514                 {
3515                     is_whitelisted_for_displaylists = true;
3516                     break;
3517                 }
3518             }
3519
3520             if (is_whitelisted_for_displaylists)
3521             {
3522                 if (func.m_notlistable)
3523                 {
3524                     console::error("%s: Func's %s m_notlistable and is_whitelisted_for_displaylists flags are not compatible!\n", VOGL_METHOD_NAME, full_func_name.get_ptr());
3525                 }
3526             }
3527
3528             dynamic_string func_proto(get_func_proto_macro(pFunc_prefix, func, sorted_gl_so_function_exports));
3529
3530             vogl_fprintf(pFile, "// %s Category: %s Vers: \"%s\" Deprecated: \"%s\" Profile: \"%s\"\n", full_func_name.get_ptr(), func.m_category.get_ptr(), func.m_version.get_ptr(), func.m_deprecated.get_ptr(), func.m_profile.get_ptr());
3531
3532             vogl_fprintf(pFile, "DEF_FUNCTION_BEGIN%s\n", func_proto.get_ptr());
3533
3534             vogl_namespace_t return_namespace = VOGL_NAMESPACE_UNKNOWN;
3535             if (pApitrace_func_def)
3536                 return_namespace = pApitrace_func_def->m_return_namespace;
3537
3538             vogl_fprintf(pFile, "   DEF_FUNCTION_INFO( %i, %s, \"%s\", \"%s\", \"%s\", \"%s\", %s, %s, %s, %s )\n", (int)return_namespace, func.m_return.get_ptr(), func.m_category.get_ptr(), func.m_version.get_ptr(),
3539                         func.m_profile.get_ptr(), func.m_deprecated.get_ptr(), is_in_whitelist ? "true" : "false", is_nullable ? "true" : "false", is_whitelisted_for_displaylists ? "true" : "false", !func.m_notlistable ? "true" : "false");
3540
3541             if (func.m_params.size())
3542             {
3543                 vogl_fprintf(pFile, "   DEF_FUNCTION_BEGIN_PARAMS\n");
3544                 for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3545                 {
3546                     const gl_function_param &param = func.m_params[param_index];
3547
3548                     vogl_namespace_t param_namespace = VOGL_NAMESPACE_UNKNOWN;
3549                     if (pApitrace_func_def)
3550                     {
3551                         VOGL_ASSERT(param_index < pApitrace_func_def->m_params.size());
3552                         if (param_index < pApitrace_func_def->m_params.size())
3553                             param_namespace = pApitrace_func_def->m_params[param_index].m_namespace;
3554                     }
3555
3556                     dynamic_string dir(param.m_direction);
3557                     dir.toupper();
3558
3559                     if (param.m_semantic == "value")
3560                     {
3561                         vogl_fprintf(pFile, "   DEF_FUNCTION_%s_VALUE_PARAM( %i, %s, %s, %s, %s )\n", dir.get_ptr(), (int)param_namespace, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3562                     }
3563                     else if (param.m_semantic == "array")
3564                     {
3565                         vogl_fprintf(pFile, "   // %s ArraySize=%s\n", param.m_name.get_ptr(), param.m_array_size.get_ptr());
3566                         vogl_fprintf(pFile, "   DEF_FUNCTION_%s_ARRAY_PARAM( %i, %s, %s, %s, %s, %s )\n", dir.get_ptr(), (int)param_namespace, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr(), func_param_translate_array_size(pFunc_prefix, func, param, func_proto).get_ptr());
3567                     }
3568                     else if (param.m_semantic == "reference")
3569                     {
3570                         vogl_fprintf(pFile, "   DEF_FUNCTION_%s_REFERENCE_PARAM( %i, %s, %s, %s, %s )\n", dir.get_ptr(), (int)param_namespace, param.m_type.get_ptr(), param.m_ctype.get_ptr(), param.m_ctype_enum.get_ptr(), param.m_name.get_ptr());
3571                     }
3572                 }
3573                 vogl_fprintf(pFile, "   DEF_FUNCTION_END_PARAMS\n");
3574             }
3575
3576             vogl_fprintf(pFile, "   DEF_FUNCTION_RETURN( %s, %s, %s )\n", func.m_return.get_ptr(), func.m_return_ctype.get_ptr(), func.m_return_ctype_enum.get_ptr());
3577
3578             vogl_fprintf(pFile, "DEF_FUNCTION_END%s\n", func_proto.get_ptr());
3579
3580             vogl_fprintf(pFile, "\n");
3581         }
3582
3583         return true;
3584     }
3585
3586     //-----------------------------------------------------------------------------------------------------------------------
3587     // dump_inc_file_header
3588     //-----------------------------------------------------------------------------------------------------------------------
3589     void dump_inc_file_header(FILE *pFile) const
3590     {
3591         vogl_fprintf(pFile, "// Auto-generated by voglgen. Don't hand modify!\n\n");
3592     }
3593
3594     //-----------------------------------------------------------------------------------------------------------------------
3595     // dump_function_def_undef_macros
3596     //-----------------------------------------------------------------------------------------------------------------------
3597     void dump_function_def_undef_macros(FILE *pFile) const
3598     {
3599         vogl_fprintf(pFile, "#undef DEF_PROTO_EXPORTED\n");
3600         vogl_fprintf(pFile, "#undef DEF_PROTO_EXPORTED_VOID\n");
3601         vogl_fprintf(pFile, "#undef DEF_PROTO_INTERNAL\n");
3602         vogl_fprintf(pFile, "#undef DEF_PROTO_INTERNAL_VOID\n");
3603         vogl_fprintf(pFile, "#undef DEF_FUNCTION_BEGIN_PARAMS\n");
3604         vogl_fprintf(pFile, "#undef DEF_FUNCTION_REFERENCE_PARAM\n");
3605         vogl_fprintf(pFile, "#undef DEF_FUNCTION_IN_VALUE_PARAM\n");
3606         vogl_fprintf(pFile, "#undef DEF_FUNCTION_IN_ARRAY_PARAM\n");
3607         vogl_fprintf(pFile, "#undef DEF_FUNCTION_IN_REFERENCE_PARAM\n");
3608         vogl_fprintf(pFile, "#undef DEF_FUNCTION_OUT_REFERENCE_PARAM\n");
3609         vogl_fprintf(pFile, "#undef DEF_FUNCTION_OUT_ARRAY_PARAM\n");
3610         vogl_fprintf(pFile, "#undef DEF_FUNCTION_END_PARAMS\n");
3611         vogl_fprintf(pFile, "#undef DEF_FUNCTION_BEGIN\n");
3612         vogl_fprintf(pFile, "#undef DEF_FUNCTION_BEGIN_VOID\n");
3613         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INIT\n");
3614         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INIT_VOID\n");
3615         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INPUT_VALUE_PARAM\n");
3616         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INPUT_REFERENCE_PARAM\n");
3617         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INPUT_ARRAY_PARAM\n");
3618         vogl_fprintf(pFile, "#undef DEF_FUNCTION_OUTPUT_REFERENCE_PARAM\n");
3619         vogl_fprintf(pFile, "#undef DEF_FUNCTION_OUTPUT_ARRAY_PARAM\n");
3620         vogl_fprintf(pFile, "#undef DEF_FUNCTION_CALL_GL\n");
3621         vogl_fprintf(pFile, "#undef DEF_FUNCTION_CALL_GL_VOID\n");
3622         vogl_fprintf(pFile, "#undef DEF_FUNCTION_END\n");
3623         vogl_fprintf(pFile, "#undef DEF_FUNCTION_END_VOID\n");
3624         vogl_fprintf(pFile, "#undef DEF_FUNCTION_RETURN_PARAM\n");
3625         vogl_fprintf(pFile, "#undef DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM\n");
3626         vogl_fprintf(pFile, "#undef DEF_FUNCTION_INFO\n");
3627     }
3628
3629     struct gl_type_alias_t
3630     {
3631         const char *m_pName;
3632         const char *m_pAlias;
3633     };
3634
3635     //-----------------------------------------------------------------------------------------------------------------------
3636     // purify_gl_type
3637     //-----------------------------------------------------------------------------------------------------------------------
3638     static dynamic_string_array purify_gl_type(dynamic_string str)
3639     {
3640         static const gl_type_alias_t g_gl_type_comparison_exception_table[] =
3641             {
3642                 { "__GLXextFuncPtr", "void *" },
3643                 { "GLfunction", "void *" },
3644                 { "GLuint*", "unsigned int *" },
3645                 { "GLuint *", "unsigned int *" },
3646                 { "GLuint", "unsigned int" },
3647                 { "Bool", "bool" },
3648                 { "GLboolean", "bool" },
3649                 { "GLvoid", "void" },
3650                 { "int64_t", "int64_t" },
3651                 { "GLint64", "int64_t" },
3652                 { "GLvoid*", "void*" },
3653                 { "handleARB", "GLhandleARB" },
3654                 { "GLint", "int" },
3655                 { "const GLubyte *", "const char *" },
3656                 { "GLubyte *", "char *" },
3657                 { "GLubyte*", "char *" },
3658                 { "GLchar*", "char *" },
3659                 { "GLchar* const", "char *" },
3660                 { "const char *", "char *" },
3661                 { "GLchar", "char" },
3662                 { "void function()", "void *" },
3663                 { "int32_t", "int" },
3664                 { "GLclampf", "float" },
3665                 { "GLfloat", "float" },
3666                 { "GLclampd", "double" },
3667                 { "GLdouble", "double" },
3668                 { "GLsizei", "int" },
3669                 { "int32_t *", "int *" },
3670                 { "int64_t *", "int64_t *" },
3671                 { "GLint64*", "int64_t *" },
3672                 { "GLint32*", "int *" },
3673                 { "GLint32 *", "int *" },
3674                 { "const GLuint*", "const unsigned int *" },
3675                 { "const GLuint *", "const unsigned int *" },
3676                 { "GLuint32*", "unsigned int *" },
3677                 { "GLuint32 *", "unsigned int *" },
3678                 { "GLulong*", "unsigned long *" },
3679                 { "GLint*", "int *" },
3680                 { "GLint *", "int *" },
3681                 { "const GLint *", "const int *" },
3682                 { "const GLvoid *", "const void *" },
3683                 { "const GLvoid*", "const void *" },
3684                 { "GLvoid *", "void *" },
3685                 { "GLvoid*", "void *" },
3686                 { "GLchar *", "char *" },
3687                 { "GLchar*", "char *" },
3688                 { "const GLchar *", "const char *" },
3689                 { "const GLchar*", "const char *" },
3690                 { "GLcharARB *", "char *" },
3691                 { "GLcharARB*", "char *" },
3692                 { "const GLcharARB *", "const char *" },
3693                 { "const GLcharARB*", "const char *" },
3694                 { "uint *", "unsigned int *" },
3695                 { "ulong", "unsigned long" },
3696                 { "ulong *", "unsigned long *" },
3697                 { "GLuint64", "unsigned int64_t" },
3698                 { "GLuint64*", "unsigned int64_t *" },
3699                 { "const GLuint64*", "const unsigned int64_t *" },
3700                 { "GLuint64EXT", "unsigned int64_t" },
3701                 { "const GLuint64EXT *", "const unsigned int64_t *" },
3702                 { "GLuint64EXT *", "unsigned int64_t *" },
3703                 { "GLint64", "int64_t" },
3704                 { "GLint64*", "int64_t *" },
3705                 { "const GLint64*", "const int64_t *" },
3706                 { "GLint64EXT", "int64_t" },
3707                 { "const GLint64EXT *", "const int64_t *" },
3708                 { "GLint64EXT *", "int64_t *" },
3709                 { "GLintptr", "int *" },
3710                 { "GLintptrARB", "int *" },
3711                 { "GLenum", "int" }, // Mapping GLenum->int is pushing it, but there are some extensions that don't agree on whether the param is GLenum or int.
3712                 { "GLhalfNV", "GLhalf" },
3713                 { "const GLhalfNV *", "const GLhalf *" },
3714                 { "GLchar* const *", "char * const *" },
3715                 { "GLchar **", "char **" },
3716                 { "const GLfloat *", "const float *" },
3717                 { "const GLdouble *", "const double *" },
3718                 { "GLfloat *", "float *" },
3719                 { "const GLfloat *", "const float *" },
3720                 { "GLfloat*", "float *" },
3721                 { "const GLfloat *", "const float *" },
3722                 { "const GLfloat*", "const float *" },
3723                 { "GLclampf *", "float *" },
3724                 { "const GLclampf *", "const float *" },
3725                 { "GLclampf*", "float *" },
3726                 { "GLdouble *", "double *" },
3727                 { "GLdouble*", "double *" },
3728                 { "GLclampd *", "double *" },
3729                 { "GLclampd*", "double *" },
3730                 { "GLsizeiptrARB", "GLsizeiptr" },
3731                 { "handleARB*", "GLhandleARB *" },
3732                 { "const GLcharARB* *", "const char **" },
3733                 { "GLchar * *", "const char **" },
3734                 { "GLchar**", "const char **" },
3735                 { "const GLchar* *", "const char **" },
3736                 { "GLoint", "unsigned int" }, // Bad in scraped XML
3737                 { "const GLchar * *", "const char **" },
3738                 { "cl_context", "struct _cl_context *" }, // Correct in spec, bad in scraped XML.
3739                 { "cl_event", "struct _cl_event *" },     // Correct in spec, bad in scraped XML.
3740             };
3741
3742         // See if the ctype can be aliased to a simpler, hopefully equivalent ctype.
3743         for (uint i = 0; i < VOGL_ARRAY_SIZE(g_gl_type_comparison_exception_table); i++)
3744         {
3745             if (str == g_gl_type_comparison_exception_table[i].m_pName)
3746             {
3747                 str = g_gl_type_comparison_exception_table[i].m_pAlias;
3748                 break;
3749             }
3750         }
3751
3752         // Tokenize type string
3753         dynamic_string_array tokens;
3754         str.tokenize(" \t", tokens, true);
3755
3756         // Kill all const crap, nobody seems to agree on it so screw it.
3757         for (int i = 0; i < static_cast<int>(tokens.size()); i++)
3758         {
3759             if (tokens[i] == "const")
3760             {
3761                 tokens.erase(i);
3762                 i--;
3763             }
3764         }
3765
3766         // Seperate out trailing "*" chars into multiple tokens.
3767         dynamic_string ptr_str("*");
3768
3769         for (int i = 0; i < static_cast<int>(tokens.size()); i++)
3770         {
3771             for (;;)
3772             {
3773                 if (tokens[i].get_len() == 1)
3774                     break;
3775
3776                 int pointer_ofs = tokens[i].find_right('*');
3777                 if (pointer_ofs < 0)
3778                     break;
3779
3780                 tokens[i].truncate(pointer_ofs);
3781                 tokens.insert(i + 1, ptr_str);
3782             }
3783         }
3784
3785         return tokens;
3786     }
3787
3788     //-----------------------------------------------------------------------------------------------------------------------
3789     // validate_functions
3790     //-----------------------------------------------------------------------------------------------------------------------
3791     bool validate_functions(const gl_function_specs &gl_xml_funcs, const gl_function_specs &gl_funcs, const apitrace_func_specs &apitrace_gl_funcs,
3792                             const gl_types &primary_typemap, const gl_types &alt_typemap) const
3793     {
3794         dynamic_string_array missing_funcs;
3795
3796         uint total_skipped = 0;
3797         uint total_validated = 0;
3798         uint total_failures = 0;
3799         uint total_not_found = 0;
3800
3801         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
3802         {
3803             const gl_function_def &func = gl_funcs[func_index];
3804
3805             // Let's skip these guys, they are either bad in the XML and not worth fixing up the individual params in code, or they are totally uninteresting (SUN, OES),
3806             // or they have been manually validated to be correct in the .spec files.
3807             if ((func.m_name == "Uniform2ui") || (func.m_name == "Uniform3ui") || (func.m_name == "Uniform4ui") ||
3808                 (func.m_name == "ProgramUniform2ui") || (func.m_name == "ProgramUniform3ui") || (func.m_name == "ProgramUniform4ui") ||
3809                 (func.m_name == "ReplacementCodePointerSUN") || (func.m_name == "ClearDepthfOES") || (func.m_name == "QueryMatrixxOES") ||
3810                 (func.m_name == "QueryMatrixxOES") || (func.m_name == "SendPbufferToVideoNV") || (func.m_name == "ReleaseVideoImageNV") ||
3811                 (func.m_name == "BindVideoImageNV") || (func.m_name == "GetTransparentIndexSUN") ||
3812                 (func.m_name == "GetIntegerui64i_vNV"))
3813             {
3814                 total_skipped++;
3815                 continue;
3816             }
3817
3818             const gl_types *pPrimary_typemap = &primary_typemap;
3819             const gl_types *pAlt_typemap = &alt_typemap;
3820             if ((func.m_lib == cGLX) || (func.m_lib == cWGL))
3821                 std::swap(pPrimary_typemap, pAlt_typemap);
3822
3823             dynamic_string return_type;
3824             if (func.m_return == "void")
3825             {
3826                 return_type = "void";
3827             }
3828             else
3829             {
3830                 const dynamic_string *pCType = pPrimary_typemap->find(func.m_return);
3831                 if (!pCType)
3832                     pCType = pAlt_typemap->find(func.m_return);
3833                 if (!pCType)
3834                 {
3835                     console::warning("Unable to map spec type %s\n", func.m_return.get_ptr());
3836                     return false;
3837                 }
3838
3839                 return_type = *pCType;
3840             }
3841
3842             dynamic_string_array func_param_ctypes;
3843
3844             for (uint param_index = 0; param_index < func.m_params.size(); param_index++)
3845             {
3846                 const gl_function_param &param = func.m_params[param_index];
3847
3848                 const dynamic_string *pCType = pPrimary_typemap->find(param.m_type);
3849                 if (!pCType)
3850                     pCType = pAlt_typemap->find(param.m_type);
3851                 if (!pCType)
3852                 {
3853                     console::warning("Unable to map spec type %s\n", param.m_type.get_ptr());
3854                     return false;
3855                 }
3856
3857                 dynamic_string type_prefix;
3858
3859                 dynamic_string type_suffix("");
3860                 if ((param.m_semantic == "array") || (param.m_semantic == "reference"))
3861                 {
3862                     type_suffix = " *";
3863
3864                     if (param.m_direction == "in")
3865                     {
3866                         if (!pCType->ends_with("const"))
3867                             type_prefix = "const ";
3868                     }
3869                 }
3870
3871                 dynamic_string full_ctype(cVarArg, "%s%s%s", type_prefix.get_ptr(), pCType->get_ptr(), type_suffix.get_ptr());
3872
3873                 func_param_ctypes.push_back(full_ctype);
3874             }
3875
3876             const apitrace_gl_func_def *pApitrace_func_def = apitrace_gl_funcs.find(func.m_full_name.get_ptr());
3877             if (pApitrace_func_def)
3878             {
3879                 if (pApitrace_func_def->m_return_gl_type != return_type)
3880                 {
3881                     console::warning("Function %s return type mismatch vs. apitrace specs: spec: %s, apitrace: %s\n", func.m_full_name.get_ptr(), return_type.get_ptr(), pApitrace_func_def->m_return_gl_type.get_ptr());
3882                     total_failures++;
3883                 }
3884
3885                 if (pApitrace_func_def->m_params.size() != func_param_ctypes.size())
3886                 {
3887                     console::warning("Function %s has a different number of params vs. apitrace specs: spec: %u, apitrace: %u\n", func.m_full_name.get_ptr(), func_param_ctypes.size(), pApitrace_func_def->m_params.size());
3888                     total_failures++;
3889                 }
3890                 else
3891                 {
3892                     for (uint i = 0; i < func_param_ctypes.size(); i++)
3893                     {
3894                         const apitrace_gl_func_param_def &param_def = pApitrace_func_def->m_params[i];
3895
3896                         dynamic_string apitrace_param_type(param_def.m_gl_type);
3897
3898                         dynamic_string_array purified_spec_ctype(purify_gl_type(func_param_ctypes[i]));
3899                         dynamic_string_array purified_apitrace_ctype(purify_gl_type(apitrace_param_type));
3900
3901                         bool type_mismatch = purified_spec_ctype.size() != purified_apitrace_ctype.size();
3902                         if (!type_mismatch)
3903                         {
3904                             for (uint j = 0; j < purified_spec_ctype.size(); j++)
3905                             {
3906                                 if (purified_spec_ctype[j] != purified_apitrace_ctype[j])
3907                                 {
3908                                     type_mismatch = true;
3909                                     break;
3910                                 }
3911                             }
3912                         }
3913
3914                         if (type_mismatch)
3915                         {
3916                             console::warning("Function %s param %u, spec vs. apitrace type difference: spec: %s apitrace: %s\n", func.m_full_name.get_ptr(), i, func_param_ctypes[i].get_ptr(), apitrace_param_type.get_ptr());
3917                             total_failures++;
3918
3919                             //printf("   { \"%s\", \"%s\" },\n", func_param_ctypes[i].get_ptr(), apitrace_param_type.get_ptr());
3920                         }
3921                     }
3922                 }
3923             }
3924             else
3925             {
3926                 //printf("Func not found in apitrace specs: %s\n", func.m_full_name.get_ptr());
3927             }
3928
3929             uint gl_xml_func_index;
3930             for (gl_xml_func_index = 0; gl_xml_func_index < gl_xml_funcs.size(); gl_xml_func_index++)
3931             {
3932                 if (gl_xml_funcs[gl_xml_func_index].m_lib != func.m_lib)
3933                     continue;
3934
3935                 dynamic_string gl_xml_func_name(gl_xml_funcs[gl_xml_func_index].m_name);
3936
3937                 if (gl_xml_func_name == func.m_name)
3938                     break;
3939             }
3940
3941             if (gl_xml_func_index == gl_xml_funcs.size())
3942             {
3943                 dynamic_string suffix;
3944                 if (func.m_name.ends_with("ARB", true) || func.m_name.ends_with("EXT", true))
3945                     suffix.set(func.m_name).right(func.m_name.get_len() - 3);
3946                 else if (func.m_name.ends_with("NV", true))
3947                     suffix.set(func.m_name).right(func.m_name.get_len() - 2);
3948
3949                 if (suffix.get_len())
3950                 {
3951                     for (gl_xml_func_index = 0; gl_xml_func_index < gl_xml_funcs.size(); gl_xml_func_index++)
3952                     {
3953                         if (gl_xml_funcs[gl_xml_func_index].m_lib != func.m_lib)
3954                             continue;
3955
3956                         dynamic_string gl_xml_func_name(gl_xml_funcs[gl_xml_func_index].m_name);
3957                         gl_xml_func_name += suffix;
3958
3959                         if (gl_xml_func_name == func.m_name)
3960                             break;
3961                     }
3962                 }
3963
3964                 if (gl_xml_func_index == gl_xml_funcs.size())
3965                 {
3966                     missing_funcs.push_back(func.m_name);
3967                     total_not_found++;
3968                     continue;
3969                 }
3970             }
3971
3972             const gl_function_def &xml_func = gl_xml_funcs[gl_xml_func_index];
3973             if (xml_func.m_params.size() != func.m_params.size())
3974             {
3975                 console::error("Function %s param number mismatch\n", func.m_name.get_ptr());
3976                 total_failures++;
3977                 continue;
3978             }
3979
3980             dynamic_string_array purified_func_return(purify_gl_type(return_type));
3981
3982             dynamic_string xml_func_return(xml_func.m_return);
3983
3984             // XML exceptions (they where incorrect on the web, GLsync here makes no sense)
3985             if ((func.m_name == "FramebufferRenderbuffer") || (func.m_name == "FlushMappedBufferRange"))
3986             {
3987                 xml_func_return = "void";
3988             }
3989
3990             dynamic_string_array purified_xml_func_return(purify_gl_type(xml_func_return));
3991
3992             if (purified_func_return.size() != purified_xml_func_return.size())
3993             {
3994                 console::warning("Function %s return type mismatch: \"%s\" != \"%s\"\n", func.m_name.get_ptr(), return_type.get_ptr(), xml_func_return.get_ptr());
3995                 total_failures++;
3996             }
3997             else
3998             {
3999                 for (uint i = 0; i < purified_func_return.size(); i++)
4000                 {
4001                     if (purified_func_return[i] != purified_xml_func_return[i])
4002                     {
4003                         console::warning("Function %s return type mismatch: \"%s\" != \"%s\", param \"%s\" != \"%s\"\n", func.m_name.get_ptr(), return_type.get_ptr(), xml_func_return.get_ptr(), purified_func_return[i].get_ptr(), purified_xml_func_return[i].get_ptr());
4004                         total_failures++;
4005                     }
4006                 }
4007             }
4008
4009             uint param_index;
4010             for (param_index = 0; param_index < func.m_params.size(); param_index++)
4011             {
4012                 dynamic_string param_type(func_param_ctypes[param_index]);
4013                 dynamic_string xml_param_type(xml_func.m_params[param_index].m_type);
4014
4015                 // manual XML exceptions (incorrect on the web)
4016                 if ((param_index == 4) && (func.m_name == "GetTransformFeedbackVarying"))
4017                 {
4018                     xml_param_type = "GLsizei *";
4019                 }
4020                 if ((param_index == 3) && (func.m_name == "GetActiveUniformBlockiv"))
4021                 {
4022                     xml_param_type = "GLint *";
4023                 }
4024                 if ((param_index == 1) && (func.m_name == "CreateContextAttribsARB"))
4025                 {
4026                     xml_param_type = "GLXFBConfig";
4027                 }
4028                 if ((param_index == 3) && (func.m_name == "ProgramNamedParameter4fvNV"))
4029                 {
4030                     xml_param_type = "GLfloat *";
4031                 }
4032                 if ((param_index == 3) && (func.m_name == "ProgramNamedParameter4dvNV"))
4033                 {
4034                     xml_param_type = "GLdouble *";
4035                 }
4036
4037                 dynamic_string_array purified_param_type(purify_gl_type(param_type));
4038                 dynamic_string_array purified_xml_param_type(purify_gl_type(xml_param_type));
4039
4040                 if (purified_param_type.size() != purified_xml_param_type.size())
4041                 {
4042                     console::warning("Function %s param type mismatch: \"%s\" != \"%s\"\n", func.m_name.get_ptr(), param_type.get_ptr(), xml_param_type.get_ptr());
4043                     total_failures++;
4044                 }
4045                 else
4046                 {
4047                     for (uint j = 0; j < purified_param_type.size(); j++)
4048                     {
4049                         if (purified_param_type[j] != purified_xml_param_type[j])
4050                         {
4051                             console::warning("Function %s param type mismatch: \"%s\" != \"%s\", param \"%s\" != \"%s\"\n", func.m_name.get_ptr(),
4052                                              param_type.get_ptr(),
4053                                              xml_param_type.get_ptr(),
4054                                              purified_param_type[j].get_ptr(),
4055                                              purified_xml_param_type[j].get_ptr());
4056                             total_failures++;
4057                         }
4058                     }
4059                 }
4060             }
4061
4062             total_validated++;
4063         }
4064
4065         printf("\n");
4066         printf("Results of spec vs. XML function validation:\n");
4067         printf("Total passed: %u\n", total_validated);
4068         printf("Total failures: %u\n", total_failures);
4069         printf("Total skipped: %u\n", total_skipped);
4070         printf("Total functions present in spec but missing in XML: %u\n", total_not_found);
4071
4072         if (g_command_line_params.get_value_as_bool("verbose"))
4073         {
4074             printf("\nMissing function list:\n");
4075             for (uint i = 0; i < missing_funcs.size(); i++)
4076                 printf("%s\n", missing_funcs[i].get_ptr());
4077
4078             printf("\nMissing function list excluding OES and vendor suffixes:\n");
4079             for (uint i = 0; i < missing_funcs.size(); i++)
4080             {
4081                 const dynamic_string &func = missing_funcs[i];
4082
4083                 uint j;
4084                 for (j = 0; j < VOGL_ARRAY_SIZE(g_gl_vendor_suffixes); j++)
4085                     if (func.ends_with(g_gl_vendor_suffixes[j], true))
4086                         break;
4087
4088                 if (j < VOGL_ARRAY_SIZE(g_gl_vendor_suffixes))
4089                     continue;
4090
4091                 printf("%s\n", func.get_ptr());
4092             }
4093         }
4094
4095         return true;
4096     }
4097
4098     //-----------------------------------------------------------------------------------------------------------------------
4099     // update_whitelisted_funcs
4100     //-----------------------------------------------------------------------------------------------------------------------
4101     bool update_whitelisted_funcs(const gl_function_specs &gl_funcs, const gl_string_map &unique_ctype_enums, const gl_string_map &pointee_types, dynamic_string_array &whitelisted_funcs)
4102     {
4103         VOGL_NOTE_UNUSED(unique_ctype_enums);
4104         VOGL_NOTE_UNUSED(pointee_types);
4105
4106         dynamic_string_array new_whitelisted_funcs(whitelisted_funcs);
4107
4108         vogl::vector<bool> used_flags(m_simple_replay_funcs.size());
4109
4110         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
4111         {
4112             const gl_function_def &func_def = gl_funcs[func_index];
4113             dynamic_string full_func_name(func_def.m_full_name); //cVarArg, "%s%s", g_lib_api_prefixes[gl_funcs[func_index].m_lib], gl_funcs[func_index].m_name.get_ptr());
4114
4115             uint i;
4116             for (i = 0; i < m_simple_replay_funcs.size(); i++)
4117             {
4118                 if (m_simple_replay_funcs[i].ends_with("*"))
4119                 {
4120                     dynamic_string prefix(m_simple_replay_funcs[i]);
4121                     prefix.left(prefix.get_len() - 1);
4122                     if (full_func_name.begins_with(prefix.get_ptr()))
4123                         break;
4124                 }
4125                 else
4126                 {
4127                     if (full_func_name == m_simple_replay_funcs[i])
4128                         break;
4129                 }
4130             }
4131
4132             if (i == m_simple_replay_funcs.size())
4133                 continue;
4134
4135             VOGL_ASSERT(!used_flags[i]);
4136             used_flags[i] = true;
4137
4138             if (whitelisted_funcs.find(full_func_name) < 0)
4139             {
4140                 console::printf("Adding simple GL replay func %s to func whitelist\n", full_func_name.get_ptr());
4141                 whitelisted_funcs.push_back(full_func_name);
4142             }
4143             else
4144             {
4145                 console::warning("Simple GL replay func %s was already in the func whitelist\n", full_func_name.get_ptr());
4146             }
4147         }
4148
4149         for (uint i = 0; i < m_simple_replay_funcs.size(); i++)
4150         {
4151             if (!used_flags[i])
4152                 console::warning("Simple replay func %s was not found/used\n", m_simple_replay_funcs[i].get_ptr());
4153         }
4154
4155         return true;
4156     }
4157
4158     //-----------------------------------------------------------------------------------------------------------------------
4159     // generate_simple_replay_funcs
4160     //-----------------------------------------------------------------------------------------------------------------------
4161     bool generate_simple_replay_funcs(const gl_function_specs &gl_funcs, const gl_string_map &unique_ctype_enums, const gl_string_map &pointee_types, const dynamic_string_array &whitelisted_funcs) const
4162     {
4163         dynamic_string_array new_whitelisted_funcs(whitelisted_funcs);
4164
4165         console::info("--- Generating \"gl_glx_simple_replay_funcs.inc\":\n");
4166
4167         FILE *pFile = vogl_fopen("gl_glx_simple_replay_funcs.inc", "w");
4168         if (!pFile)
4169         {
4170             console::error("Failed creating file gl_glx_simple_replay_funcs.inc\n");
4171             return false;
4172         }
4173
4174         dump_inc_file_header(pFile);
4175
4176         vogl::vector<bool> used_flags(m_simple_replay_funcs.size());
4177
4178         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
4179         {
4180             const gl_function_def &func_def = gl_funcs[func_index];
4181             dynamic_string full_func_name(func_def.m_full_name); //cVarArg, "%s%s", g_lib_api_prefixes[gl_funcs[func_index].m_lib], gl_funcs[func_index].m_name.get_ptr());
4182
4183             uint i;
4184             for (i = 0; i < m_simple_replay_funcs.size(); i++)
4185             {
4186                 if (m_simple_replay_funcs[i].ends_with("*"))
4187                 {
4188                     dynamic_string prefix(m_simple_replay_funcs[i]);
4189                     prefix.left(prefix.get_len() - 1);
4190                     if (full_func_name.begins_with(prefix.get_ptr()))
4191                         break;
4192                 }
4193                 else
4194                 {
4195                     if (full_func_name == m_simple_replay_funcs[i])
4196                         break;
4197                 }
4198             }
4199
4200             if (i == m_simple_replay_funcs.size())
4201                 continue;
4202
4203             VOGL_ASSERT(!used_flags[i]);
4204             used_flags[i] = true;
4205
4206             vogl_fprintf(pFile, "VOGL_SIMPLE_REPLAY_FUNC_BEGIN(%s, func_def.m_params.size())\n", full_func_name.get_ptr());
4207
4208             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
4209             {
4210                 const bool last_param = (param_index == (func_def.m_params.size() - 1));
4211
4212                 if (func_def.m_params[param_index].m_ctype_enum.ends_with("_PTR"))
4213                 {
4214                     gl_string_map::const_iterator it = pointee_types.find(func_def.m_params[param_index].m_ctype_enum);
4215                     if (it == pointee_types.end())
4216                     {
4217                         console::error("Failed finding pointee ctype for ctype %s\n", func_def.m_params[param_index].m_ctype.get_ptr());
4218                         vogl_fclose(pFile);
4219                         return false;
4220                     }
4221
4222                     it = unique_ctype_enums.find(it->second);
4223                     if (it == unique_ctype_enums.end())
4224                     {
4225                         console::error("Failed finding pointee ctype for ctype %s\n", func_def.m_params[param_index].m_ctype.get_ptr());
4226                         vogl_fclose(pFile);
4227                         return false;
4228                     }
4229
4230                     vogl_fprintf(pFile, "   VOGL_SIMPLE_REPLAY_FUNC_PARAM_CLIENT_MEMORY(%s, %u)\n", it->second.get_ptr(), param_index);
4231                 }
4232                 else
4233                 {
4234                     // TODO: Add expected size of buffer check
4235                     vogl_fprintf(pFile, "   VOGL_SIMPLE_REPLAY_FUNC_PARAM_VALUE(%s, %u)\n", func_def.m_params[param_index].m_ctype.get_ptr(), param_index);
4236                 }
4237
4238                 if (!last_param)
4239                     vogl_fprintf(pFile, "   VOGL_SIMPLE_REPLAY_FUNC_PARAM_SEPERATOR\n");
4240             }
4241
4242             vogl_fprintf(pFile, "VOGL_SIMPLE_REPLAY_FUNC_END(%s)\n\n", full_func_name.get_ptr());
4243         }
4244
4245         vogl_fclose(pFile);
4246
4247         return true;
4248     }
4249
4250     //-----------------------------------------------------------------------------------------------------------------------
4251     // generate_replay_func_load_macros
4252     //-----------------------------------------------------------------------------------------------------------------------
4253     bool generate_replay_func_load_macros(const gl_function_specs &gl_funcs, const gl_string_map &unique_ctype_enums, const gl_string_map &pointee_types, const dynamic_string_array &whitelisted_funcs) const
4254     {
4255         VOGL_NOTE_UNUSED(unique_ctype_enums);
4256         VOGL_NOTE_UNUSED(pointee_types);
4257
4258         dynamic_string_array new_whitelisted_funcs(whitelisted_funcs);
4259
4260         console::info("--- Generating \"gl_glx_replay_helper_macros.inc\":\n");
4261
4262         FILE *pFile = vogl_fopen("gl_glx_replay_helper_macros.inc", "w");
4263         if (!pFile)
4264         {
4265             console::error("Failed creating file gl_glx_replay_helper_macros\n");
4266             return false;
4267         }
4268
4269         dump_inc_file_header(pFile);
4270
4271         for (uint func_index = 0; func_index < gl_funcs.size(); func_index++)
4272         {
4273             const gl_function_def &func_def = gl_funcs[func_index];
4274             dynamic_string full_func_name(func_def.m_full_name); //cVarArg, "%s%s", g_lib_api_prefixes[gl_funcs[func_index].m_lib], gl_funcs[func_index].m_name.get_ptr());
4275
4276             vogl_fprintf(pFile, "#define VOGL_REPLAY_LOAD_PARAMS_HELPER_%s %c\n", full_func_name.get_ptr(), func_def.m_params.size() ? '\\' : ' ');
4277
4278             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
4279             {
4280                 const bool last_param = (param_index == (func_def.m_params.size() - 1));
4281
4282                 if (func_def.m_params[param_index].m_ctype_enum.ends_with("_PTR"))
4283                 {
4284 #if 0
4285                                         gl_string_map::const_iterator it = pointee_types.find(func_def.m_params[param_index].m_ctype_enum);
4286                                         if (it == pointee_types.end())
4287                                         {
4288                                                 console::error("Failed finding pointee ctype for ctype %s\n", func_def.m_params[param_index].m_ctype.get_ptr());
4289                                                 vogl_fclose(pFile);
4290                                                 return false;
4291                                         }
4292
4293                                         it = unique_ctype_enums.find(it->second);
4294                                         if (it == unique_ctype_enums.end())
4295                                         {
4296                                                 console::error("Failed finding pointee ctype for ctype %s\n", func_def.m_params[param_index].m_ctype.get_ptr());
4297                                                 vogl_fclose(pFile);
4298                                                 return false;
4299                                         }
4300 #endif
4301
4302                     dynamic_string const_str;
4303                     if (!func_def.m_params[param_index].m_ctype.begins_with("const "))
4304                         const_str = "const ";
4305
4306                     vogl_fprintf(pFile, "   %s%s pTrace_%s = reinterpret_cast<%s%s>(trace_packet.get_param_client_memory_ptr(%u));", const_str.get_ptr(), func_def.m_params[param_index].m_ctype.get_ptr(), func_def.m_params[param_index].m_name.get_ptr(), const_str.get_ptr(), func_def.m_params[param_index].m_ctype.get_ptr(), param_index);
4307                 }
4308                 else
4309                 {
4310                     vogl_fprintf(pFile, "   %s %s = trace_packet.get_param_value<%s>(%u);", func_def.m_params[param_index].m_ctype.get_ptr(), func_def.m_params[param_index].m_name.get_ptr(), func_def.m_params[param_index].m_ctype.get_ptr(), param_index);
4311                 }
4312
4313                 if (!last_param)
4314                     vogl_fprintf(pFile, " \\\n");
4315                 else
4316                     vogl_fprintf(pFile, "\n");
4317             }
4318
4319             vogl_fprintf(pFile, "\n");
4320
4321             vogl_fprintf(pFile, "#define VOGL_REPLAY_CALL_GL_HELPER_%s GL_ENTRYPOINT(%s)(", full_func_name.get_ptr(), full_func_name.get_ptr());
4322
4323             for (uint param_index = 0; param_index < func_def.m_params.size(); param_index++)
4324             {
4325                 const bool last_param = (param_index == (func_def.m_params.size() - 1));
4326
4327                 if (func_def.m_params[param_index].m_ctype_enum.ends_with("_PTR"))
4328                 {
4329                     if (func_def.m_params[param_index].m_ctype_enum.begins_with("VOGL_CONST_"))
4330                         vogl_fprintf(pFile, "pTrace_%s", func_def.m_params[param_index].m_name.get_ptr());
4331                     else
4332                         vogl_fprintf(pFile, "pReplay_%s", func_def.m_params[param_index].m_name.get_ptr());
4333                 }
4334                 else
4335                 {
4336                     vogl_fprintf(pFile, "%s", func_def.m_params[param_index].m_name.get_ptr());
4337                 }
4338
4339                 if (!last_param)
4340                     vogl_fprintf(pFile, ", ");
4341             }
4342
4343             vogl_fprintf(pFile, ")\n\n");
4344         }
4345
4346         vogl_fclose(pFile);
4347
4348         return true;
4349     }
4350
4351     //-----------------------------------------------------------------------------------------------------------------------
4352     // read_regex_function_array
4353     //-----------------------------------------------------------------------------------------------------------------------
4354     bool read_regex_function_array(const char *pFilename, dynamic_string_array &funcs)
4355     {
4356         dynamic_string_array regex_func_patterns;
4357
4358         if (!file_utils::read_text_file(pFilename, regex_func_patterns, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintErrorMessages))
4359             return false;
4360
4361         regex_func_patterns.unique(dynamic_string_equal_to_case_sensitive());
4362
4363         vogl::vector<bool> used_flags(regex_func_patterns.size());
4364
4365         for (uint i = 0; i < m_all_gl_funcs.size(); i++)
4366         {
4367             uint j;
4368             for (j = 0; j < regex_func_patterns.size(); j++)
4369                 if (regexp_full_match(m_all_gl_funcs[i].m_full_name.get_ptr(), regex_func_patterns[j].get_ptr()))
4370                     break;
4371
4372             if (j < regex_func_patterns.size())
4373             {
4374                 funcs.push_back(m_all_gl_funcs[i].m_full_name);
4375                 used_flags[j] = true;
4376             }
4377         }
4378
4379         for (uint i = 0; i < used_flags.size(); i++)
4380             if (!used_flags[i])
4381                 console::warning("%s: Regex pattern \"%s\" from file \"%s\" did not match any function names!\n", VOGL_METHOD_NAME, regex_func_patterns[i].get_ptr(), pFilename);
4382
4383         return true;
4384     }
4385 };
4386
4387 //----------------------------------------------------------------------------------------------------------------------
4388 // init_command_line_params
4389 //----------------------------------------------------------------------------------------------------------------------
4390 static bool init_command_line_params(int argc, char *argv[])
4391 {
4392     command_line_params::parse_config parse_cfg;
4393     parse_cfg.m_single_minus_params = true;
4394     parse_cfg.m_double_minus_params = true;
4395
4396     if (!g_command_line_params.parse(get_command_line_params(argc, argv), VOGL_ARRAY_SIZE(g_command_line_param_descs), g_command_line_param_descs, parse_cfg))
4397     {
4398         console::error("%s: Failed parsing command line parameters!\n", VOGL_FUNCTION_NAME);
4399         return false;
4400     }
4401
4402     return true;
4403 }
4404
4405 //-----------------------------------------------------------------------------------------------------------------------
4406 // check_for_option
4407 //-----------------------------------------------------------------------------------------------------------------------
4408 static bool check_for_option(int argc, char *argv[], const char *pOption)
4409 {
4410     for (int i = 1; i < argc; i++)
4411     {
4412         if ((argv[i][0] == '/') || (argv[i][0] == '-'))
4413         {
4414             if (vogl_stricmp(&argv[i][1], pOption) == 0)
4415                 return true;
4416         }
4417     }
4418     return false;
4419 }
4420
4421 //-----------------------------------------------------------------------------------------------------------------------
4422 // print_title
4423 //-----------------------------------------------------------------------------------------------------------------------
4424 static void print_title()
4425 {
4426     console::printf("voglgen");
4427     console::printf(" %s Built %s, %s", vogl_is_x64() ? "x64" : "x86", __DATE__, __TIME__);
4428 #ifdef VOGL_BUILD_DEBUG
4429     console::printf(" DEBUG build");
4430 #endif
4431     console::printf("\n");
4432     console::printf("Debugger present: %u\n", vogl_is_debugger_present());
4433 }
4434
4435 //-------------------------------------------------------------------------------------------------------------------------------
4436 // main_internal
4437 //-------------------------------------------------------------------------------------------------------------------------------
4438 static int main_internal(int argc, char *argv[])
4439 {
4440     VOGL_NOTE_UNUSED(argc);
4441     VOGL_NOTE_UNUSED(argv);
4442     char cwd[1024];
4443
4444     cwd[0] = 0;
4445     colorized_console::init();
4446     colorized_console::set_exception_callback();
4447
4448     if (check_for_option(argc, argv, "quiet"))
4449         console::disable_output();
4450
4451     print_title();
4452
4453     bool status = false;
4454     if (init_command_line_params(argc, argv))
4455     {
4456         dynamic_string srcdir;
4457
4458         if (g_command_line_params.get_value_as_string(srcdir, "srcdir"))
4459         {
4460             printf("srcdir: '%s'\n", srcdir.get_ptr());
4461             chdir(srcdir.get_ptr());
4462         }
4463         // If we can't find this text file, try the vogl/glspec dir.
4464         if (access("apitrace_gl_param_info.txt", F_OK) != 0)
4465         {
4466             if (access("../../vogl/glspec/apitrace_gl_param_info.txt", F_OK) == 0)
4467                 chdir("../../vogl/glspec");
4468         }
4469         getcwd(cwd, sizeof(cwd));
4470         printf("Current working directory: %s\n\n", cwd);
4471
4472         vogl_gen generator;
4473
4474         console::printf("---------------- Begin Generator Init\n");
4475         status = generator.init();
4476         console::printf("---------------- End Generator Init\n");
4477
4478         if (status)
4479         {
4480             dynamic_string regex_pattern;
4481             if (g_command_line_params.get_value_as_string(regex_pattern, "func_regex"))
4482                 generator.func_regex(regex_pattern.get_ptr());
4483             else if (g_command_line_params.get_value_as_string(regex_pattern, "param_regex"))
4484                 generator.param_regex(regex_pattern.get_ptr());
4485             else if (g_command_line_params.get_value_as_string(regex_pattern, "category_regex"))
4486                 generator.category_regex(regex_pattern.get_ptr());
4487             else if (g_command_line_params.get_value_as_string(regex_pattern, "namespace_regex"))
4488                 generator.namespace_regex(regex_pattern.get_ptr());
4489             else if (g_command_line_params.get_value_as_string(regex_pattern, "ctype_regex"))
4490                 generator.ctype_regex(regex_pattern.get_ptr());
4491             else
4492             {
4493                 console::printf("---------------- Begin Generate\n");
4494                 status = generator.generate();
4495                 console::printf("---------------- End Generate\n");
4496
4497                 if (status && g_command_line_params.get_value_as_bool("debug"))
4498                 {
4499                     console::printf("---------------- Begin Debug Dump\n");
4500                     generator.dump_debug_files();
4501                     console::printf("---------------- End Debug Dump\n");
4502                 }
4503             }
4504         }
4505     }
4506
4507     if (!status)
4508         console::error("voglgen FAILED!\n");
4509     else
4510         console::printf("voglgen succeeded\n  (to %s)\n", cwd);
4511
4512     int exit_status = status ? EXIT_SUCCESS : EXIT_FAILURE;
4513
4514     console::printf("%u warning(s), %u error(s)\n", console::get_total_messages(cWarningConsoleMessage), console::get_total_messages(cErrorConsoleMessage));
4515
4516     console::printf("Exit status: %i\n", exit_status);
4517
4518     colorized_console::deinit();
4519
4520     vogl_print_heap_stats();
4521
4522     return status ? EXIT_SUCCESS : EXIT_FAILURE;
4523 }
4524
4525 //-----------------------------------------------------------------------------------------------------------------------
4526 // pause_and_wait
4527 //-----------------------------------------------------------------------------------------------------------------------
4528 static void pause_and_wait(void)
4529 {
4530     console::enable_output();
4531
4532     console::message("\nPress a key to continue.\n");
4533
4534     for (;;)
4535     {
4536         if (vogl_getch() != -1)
4537             break;
4538     }
4539 }
4540
4541 //-----------------------------------------------------------------------------------------------------------------------
4542 // main
4543 //-----------------------------------------------------------------------------------------------------------------------
4544 int main(int argc, char *argv[])
4545 {
4546     int status = EXIT_FAILURE;
4547
4548     if (vogl_is_debugger_present())
4549     {
4550         status = main_internal(argc, argv);
4551     }
4552     else
4553     {
4554 #ifdef _MSC_VER
4555         __try
4556         {
4557             status = main_internal(argc, argv);
4558         }
4559         __except(EXCEPTION_EXECUTE_HANDLER)
4560         {
4561             console::error("Uncached exception! voglgen command line tool failed!\n");
4562         }
4563 #else
4564         status = main_internal(argc, argv);
4565 #endif
4566     }
4567
4568     if (check_for_option(argc, argv, "pause"))
4569     {
4570         if ((status == EXIT_FAILURE) || (console::get_total_messages(cErrorConsoleMessage)))
4571             pause_and_wait();
4572     }
4573
4574     return status;
4575 }