d3d10: Add support for parsing sample masks to parse_fx10_object().
[wine] / dlls / opengl32 / make_opengl
1 #!/usr/bin/perl -w
2 use strict;
3
4 # This script is called thus :
5 #
6 #   make_opengl [opengl_version]
7 #
8 #     - It needs the gl.spec and gl.tm files in the current directory.
9 #       These files are hosted in the OpenGL extension registry at
10 #       opengl.org:
11 #
12 #       http://www.opengl.org/registry/api/gl.spec
13 #       http://www.opengl.org/registry/api/gl.tm
14 #
15 #       If they are not found in the current directory the script will
16 #       attempt to download them from there.
17 #
18 #     - opengl_version is the OpenGL version emulated by the library
19 #       (can be 1.0 to 1.5). The default is 1.1.
20 #
21 # This script generates the three following files :
22 #
23 #     - opengl32.spec : the spec file giving all the exported functions
24 #       of the OpenGL32.DLL library. These functions are the one an
25 #       application can directly link to (and are all the functions
26 #       defined in the OpenGL core for the version defined by
27 #       'opengl_version').
28 #
29 #     - opengl_norm.c : this file contains the thunks for all OpenGL
30 #       functions that are defined in 'opengl32.spec'. The corresponding
31 #       functions NEED to be defined in Linux's libGL or the library
32 #       won't be able to be linked in.
33 #
34 #     - opengl_ext.c : in this file are stored thunks for ALL possible
35 #       OpenGL extensions (at least, all the extensions that are defined
36 #       in the OpenGL extension registry). Contrary to 'opengl_norm.c',
37 #       you do not need to have these extensions in your libGL to have
38 #       OpenGL work (as they are resolved at run-time using
39 #       glXGetProcAddressARB).
40 #
41 #     - include/wine/wgl_driver.h: definitions for the tables of OpenGL functions.
42 #
43 #
44 # Copyright 2000 Lionel Ulmer
45 # Copyright 2012 Alexandre Julliard
46 #
47 # This library is free software; you can redistribute it and/or
48 # modify it under the terms of the GNU Lesser General Public
49 # License as published by the Free Software Foundation; either
50 # version 2.1 of the License, or (at your option) any later version.
51 #
52 # This library is distributed in the hope that it will be useful,
53 # but WITHOUT ANY WARRANTY; without even the implied warranty of
54 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
55 # Lesser General Public License for more details.
56 #
57 # You should have received a copy of the GNU Lesser General Public
58 # License along with this library; if not, write to the Free Software
59 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
60 #
61
62 #
63 # Files to generate
64 #
65 my $spec_file = "opengl32.spec";
66 my $norm_file = "opengl_norm.c";
67 my $ext_file  = "opengl_ext.c";
68
69 # Set to 0 for removing the ENTER / LEAVE GL calls
70 my $gen_thread_safe = 0;
71 # Prefix used for the local variables
72 my $ext_prefix = "func_";
73 # If set to 1, generate TRACEs for each OpenGL function
74 my $gen_traces = 1;
75
76 #
77 # List of categories to put in the 'opengl_norm.c' file
78 #
79 my %cat_1_0 = ( "display-list" => 1,
80              "drawing" => 1,
81              "drawing-control" => 1,
82              "feedback" => 1,
83              "framebuf" => 1,
84              "misc" => 1,
85              "modeling" => 1,
86              "pixel-op" => 1,
87              "pixel-rw" => 1,
88              "state-req" => 1,
89              "xform" => 1,
90              "VERSION_1_0" => 1,
91              "VERSION_1_0_DEPRECATED" => 1 );
92 my %cat_1_1 = ( %cat_1_0,
93              "VERSION_1_1" => 1,
94              "VERSION_1_1_DEPRECATED" => 1 );
95 my %cat_1_2 = ( %cat_1_1,
96              "VERSION_1_2" => 1,
97              "VERSION_1_2_DEPRECATED" => 1 );
98 my %cat_1_3 = ( %cat_1_2,
99              "VERSION_1_3" => 1,
100              "VERSION_1_3_DEPRECATED" => 1 );
101 my %cat_1_4 = ( %cat_1_3,
102              "VERSION_1_4" => 1,
103              "VERSION_1_4_DEPRECATED" => 1 );
104 my %cat_1_5 = ( %cat_1_4,
105              "VERSION_1_5" => 1,
106              "VERSION_1_5_DEPRECATED" => 1 );
107
108 my %norm_categories = ();
109
110 #
111 # This hash table gives the conversion between OpenGL types and what
112 # is used by the TRACE printfs
113 #
114 my %debug_conv =
115     ("GLbitfield" => "%d",
116      "GLboolean" => "%d",
117      "GLbyte" => "%d",
118      "GLclampd" => "%f",
119      "GLclampf" => "%f",
120      "GLdouble" => "%f",
121      "GLenum" => "%d",
122      "GLfloat" => "%f",
123      "GLint" => "%d",
124      "GLshort" => "%d",
125      "GLsizei" => "%d",
126      "GLstring" => "%s",
127      "GLubyte" => "%d",
128      "GLuint" => "%d",
129      "GLushort" => "%d",
130      "GLhalfNV" => "%d",
131      "GLintptrARB" => "%ld",
132      "GLsizeiptrARB" => "%ld",
133      "GLintptr" => "%ld",
134      "GLsizeiptr" => "%ld",
135      "GLhandleARB" => "%d",
136      "GLcharARB" => "%c",
137      "GLvoid" => "(void)",
138      "_GLfuncptr" => "%p",
139      "GLDEBUGPROCARB" => "%p",
140      "GLDEBUGPROCAMD" => "%p",
141      "GLvdpauSurfaceNV" => "%ld",
142      "INT64" => "%s,wine_dbgstr_longlong(%s)",
143      "UINT64" => "%s,wine_dbgstr_longlong(%s)"
144     );
145
146 #
147 # This hash table gives the conversion between OpenGL types and what
148 # is used in the .spec file
149 #
150 my %arg_conv =
151     ("GLbitfield" => [ "long", 4 ],
152      "GLboolean" => [ "long", 4 ],
153      "GLbyte" => [ "long", 4 ],
154      "GLclampd" => [ "double", 8 ],
155      "GLclampf" => [ "float", 4 ],
156      "GLdouble" => [ "double", 8 ],
157      "GLenum" => [ "long", 4 ],
158      "GLfloat" => [ "float", 4 ],
159      "GLint" => [ "long", 4 ],
160      "GLshort" => [ "long", 4 ],
161      "GLsizei" => [ "long", 4 ],
162      "GLstring" => [ "str", 4 ],
163      "GLubyte" => [ "long", 4 ],
164      "GLuint" => [ "long", 4 ],
165      "GLushort" => [ "long", 4 ],
166      "GLhalfNV" => [ "long", 4 ],
167      "GLintptrARB" => [ "long", 4 ],
168      "GLsizeiptrARB" => [ "long", 4 ],
169      "GLhandleARB" => [ "long", 4 ],
170      "GLcharARB" => [ "long", 4 ],
171      "GLintptr" => [ "long", 4 ],
172      "GLsizeiptr" => [ "long", 4 ],
173      "_GLfuncptr" => [ "ptr", 4 ]);
174
175 #
176 # Used to convert some types
177 #
178 sub ConvertType($)
179 {
180     my ($type) = @_;
181
182     my %hash = ( "GLstring" => "const GLubyte *",
183               "GLintptrARB" => "INT_PTR",
184               "GLsizeiptrARB" => "INT_PTR",
185               "GLintptr" => "INT_PTR",
186               "GLsizeiptr" => "INT_PTR",
187               "GLhandleARB" => "unsigned int",
188               "GLcharARB" => "char",
189               "GLchar" => "char",
190               "GLhalfNV" => "unsigned short",
191               "GLvdpauSurfaceNV" => "INT_PTR",
192               "struct _cl_context" => "void",
193               "struct _cl_event" => "void",
194               "GLDEBUGPROCARB" => "void *",
195               "GLDEBUGPROCAMD" => "void *" );
196
197     foreach my $org (reverse sort keys %hash) {
198         if ($type =~ /$org/) {
199             my ($before, $after) = ($type =~ /^(.*)$org(.*)$/);
200             return "$before$hash{$org}$after";
201         }
202     }
203     return $type;
204 }
205
206 #
207 # Used to convert some variable names
208 #
209 sub ConvertVarName($)
210 {
211     my ($type) = @_;
212
213     my %hash = ( "near" => "nearParam",
214                  "far"  => "farParam" );
215
216     foreach my $org (keys %hash) {
217         if ($type =~ /$org/) {
218             my ($before, $after) = ($type =~ /^(.*)$org(.*)$/);
219             return "$before$hash{$org}$after";
220         }
221     }
222     return $type;
223 }
224
225 #
226 # This functions generates the thunk for a given function.
227 #
228 sub GenerateThunk($$$)
229 {
230     my ($func_ref, $comment, $prefix) = @_;
231     my $ret = "";
232     my $call_arg = "";
233     my $trace_call_arg = "";
234     my $trace_arg = "";
235
236     return "" if $func_ref->[0] eq "glDebugEntry";
237     return "" if $func_ref->[0] eq "glGetString";
238
239     # If for opengl_norm.c, generate a nice heading otherwise Patrik won't be happy :-)
240     # Patrik says: Well I would be even happier if a (OPENGL32.@) was added as well. Done. :-)
241     if ($comment eq 1) {
242         $ret = "$ret/***********************************************************************\n";
243         $ret = "$ret *              $func_ref->[0] (OPENGL32.\@)\n";
244         $ret = "$ret */\n";
245     }
246     $ret = $ret . ConvertType($func_ref->[1]) . " WINAPI wine_$func_ref->[0]( ";
247     for (my $i = 0; $i < @{$func_ref->[2]}; $i++) {
248         ## Quick debug code :-)
249         ## print $func_ref->[2]->[$i]->[1] . "\n";
250         my $type = $func_ref->[2]->[$i]->[0];
251         my $name = ConvertVarName($func_ref->[2]->[$i]->[1]);
252         $ret .= ConvertType($type) . " $name";
253         $call_arg .= $name;
254         if ($type =~ /\*/) {
255             $trace_arg .= "%p";
256             $trace_call_arg .= $name;
257         } elsif (defined $debug_conv{$type}) {
258             if ($debug_conv{$type} =~ /(.*),(.*)/)
259             {
260                 $trace_arg .= $1;
261                 $trace_call_arg .= sprintf $2, $name;
262             }
263             else
264             {
265                 $trace_arg .= $debug_conv{$type};
266                 $trace_call_arg .= $name;
267             }
268         }
269         else { printf "Unknown type %s\n", $type; }
270         if ($i+1 < @{$func_ref->[2]}) {
271             $ret .= ", ";
272             $call_arg .= ", ";
273             $trace_call_arg .= ", ";
274             $trace_arg .= ", ";
275         } else {
276             $ret .= " ";
277             $call_arg .= " ";
278             $trace_call_arg .= " ";
279         }
280     }
281     $ret .= 'void ' if (!@{$func_ref->[2]});
282     $ret .= ") {\n";
283     $ret .= "  const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;\n";
284     if ($func_ref->[1] ne "void" && $gen_thread_safe) {
285         $ret = "$ret  " . ConvertType($func_ref->[1]) . " ret_value;\n";
286     }
287     if ($gen_traces) {
288         $ret = "$ret  TRACE(\"($trace_arg)\\n\"";
289         if ($trace_arg ne "") {
290             $ret .= ", $trace_call_arg";
291         }
292         $ret = "$ret);\n";
293     }
294     if ($gen_thread_safe) {
295         $ret .= "  ENTER_GL();\n";
296         $ret .= "  ";
297         if ($func_ref->[1] ne "void") {
298             $ret .= "ret_value = ";
299         }
300         $ret .= "funcs->$prefix.p_$func_ref->[0]( $call_arg);\n";
301         $ret .= "  LEAVE_GL();\n";
302         if ($func_ref->[1] ne "void") {
303             $ret .= "  return ret_value;\n"
304         }
305     }
306     else {
307         $ret .= "  ";
308         if ($func_ref->[1] ne "void") {
309             $ret .= "return ";
310         }
311         $ret .= "funcs->$prefix.p_$func_ref->[0]( $call_arg);\n";
312     }
313     $ret = "$ret}\n";
314
315     # Return this string....
316     return $ret;
317 }
318
319 sub generate_null_func($)
320 {
321     my ($func_ref) = @_;
322     my $ret;
323
324     return "" if $func_ref->[0] eq "glDebugEntry";
325
326     $ret = "static " . ConvertType($func_ref->[1]) . " null_$func_ref->[0]( ";
327     for (my $i = 0; $i < @{$func_ref->[2]}; $i++) {
328         my $type = $func_ref->[2]->[$i]->[0];
329         my $name = ConvertVarName($func_ref->[2]->[$i]->[1]);
330         $ret .= ConvertType($type) . " $name";
331         $ret .= "," if ($i+1 < @{$func_ref->[2]});
332         $ret .= " ";
333     }
334     $ret .= 'void ' if (!@{$func_ref->[2]});
335     $ret .= ") {";
336     if ($func_ref->[0] eq "glGetError")
337     {
338         $ret .= " return GL_INVALID_OPERATION;";
339     }
340     elsif ($func_ref->[1] ne "void")
341     {
342         $ret .= " return 0;";
343     }
344     $ret .= " }\n";
345     return $ret;
346 }
347
348 sub get_func_proto($)
349 {
350     my $func = shift;
351     my $ret = sprintf "%-10s", ConvertType($func->[1]);
352     $ret .= " (WINE_GLAPI *p_$func->[0])(";
353     for (my $i = 0; $i < @{$func->[2]}; $i++)
354     {
355         $ret .= ConvertType($func->[2]->[$i]->[0]);
356         $ret .= "," if ($i+1 < @{$func->[2]});
357     }
358     $ret .= "void" unless @{$func->[2]};
359     $ret .= ")";
360     return $ret;
361 }
362
363 #
364 # Extract and checks the number of arguments
365 #
366 if (@ARGV > 1) {
367     my $name0=$0;
368     $name0=~s%^.*/%%;
369     die "Usage: $name0 [version]\n";
370 }
371 my $version = $ARGV[0] || "1.1";
372 if ($version eq "1.0") {
373     %norm_categories = %cat_1_0;
374 } elsif ($version eq "1.1") {
375     %norm_categories = %cat_1_1;
376 } elsif ($version eq "1.2") {
377     %norm_categories = %cat_1_2;
378 } elsif ($version eq "1.3") {
379     %norm_categories = %cat_1_3;
380 } elsif ($version eq "1.4") {
381     %norm_categories = %cat_1_4;
382 } elsif ($version eq "1.5") {
383     %norm_categories = %cat_1_5;
384 } else {
385     die "Incorrect OpenGL version.\n";
386 }
387
388 #
389 # Fetch the registry files
390 #
391 -f "gl.spec" || system "wget http://www.opengl.org/registry/api/gl.spec" || die "cannot download gl.spec";
392 -f "gl.tm" || system "wget http://www.opengl.org/registry/api/gl.tm" || die "cannot download gl.tm";
393
394 #
395 # Open the registry files
396 #
397 open(TYPES,    "gl.tm")   || die "Could not open gl.tm";
398 open(REGISTRY, "gl.spec") || die "Could not open gl.spec";
399
400 #
401 # First, create a mapping between the pseudo types used in the spec file
402 # and OpenGL types using the 'gl.tm' file.
403 #
404 my %pseudo_to_opengl = ();
405 while (my $line = <TYPES>) {
406     if ($line !~ /\w*\#/) {
407         my ($pseudo, $opengl) = ($line =~ /(\w*),\*,\*,\s*(.*),\*,\*/);
408         $pseudo_to_opengl{$pseudo} = $opengl;
409     }
410 }
411 # This is to override the 'void' -> '*' bogus conversion
412 $pseudo_to_opengl{"void"} = "void";
413 $pseudo_to_opengl{"sync"} = "GLvoid*";
414 $pseudo_to_opengl{"Int64"} = "INT64";
415 $pseudo_to_opengl{"UInt64"} = "UINT64";
416 $pseudo_to_opengl{"Int64EXT"} = "INT64";
417 $pseudo_to_opengl{"UInt64EXT"} = "UINT64";
418
419 #
420 # Then, create the list of all OpenGL functions using the 'gl.spec'
421 # file. This will create two hash-tables, one with all the function
422 # whose category matches the one listed in '@norm_categories', the other
423 # with all other functions.
424 #
425 # An element of the hash table is a reference to an array with these
426 # elements :
427 #
428 #  - function name
429 #
430 #  - return type
431 #
432 #  - reference to an array giving the list of arguments (an empty array
433 #    for a 'void' function).
434 #
435 # The list of arguments is itself an array of reference to arrays. Each
436 # of these arrays represents the argument type and the argument name.
437 #
438 # An example :
439 #
440 # void glBitmap( GLsizei width, GLsizei height,
441 #                GLfloat xorig, GLfloat yorig,
442 #                GLfloat xmove, GLfloat ymove,
443 #                const GLubyte *bitmap );
444 #
445 # Would give something like that :
446 #
447 # [ "glBitmap",
448 #   "void",
449 #   [ [ "GLsizei", "width" ],
450 #     [ "GLsizei", "height" ],
451 #     [ "GLfloat", "xorig" ],
452 #     [ "GLfloat", "yorig" ],
453 #     [ "GLfloat", "xmove" ],
454 #     [ "GLfloat", "ymove" ],
455 #     [ "GLubyte *", "bitmap"] ] ];
456 #
457 my %norm_functions = ( "glDebugEntry" => [ "glDebugEntry", "GLint", [[ "GLint", "unknown1" ],
458                                                                      [ "GLint", "unknown2" ]] ] );
459
460 #
461 # This stores various extensions NOT part of the GL extension registry but still
462 # implemented by most OpenGL libraries out there...
463 #
464
465 my %ext_functions  =
466     ( "glDeleteBufferRegion" => [ "glDeleteBufferRegion", "void", [ [ "GLenum", "region" ] ], "glDeleteBufferRegion", "GL_KTX_buffer_region" ],
467       "glReadBufferRegion" => [ "glReadBufferRegion", "void", [ [ "GLenum", "region" ],
468                                                                 [ "GLint", "x" ],
469                                                                 [ "GLint", "y" ],
470                                                                 [ "GLsizei", "width" ],
471                                                                 [ "GLsizei", "height" ] ], "glReadBufferRegion", "GL_KTX_buffer_region" ],
472       "glDrawBufferRegion" => [ "glDrawBufferRegion", "void", [ [ "GLenum", "region" ],
473                                                                 [ "GLint", "x" ],
474                                                                 [ "GLint", "y" ],
475                                                                 [ "GLsizei", "width" ],
476                                                                 [ "GLsizei", "height" ],
477                                                                 [ "GLint", "xDest" ],
478                                                                 [ "GLint", "yDest" ] ], "glDrawBufferRegion", "GL_KTX_buffer_region" ],
479       "glBufferRegionEnabled" => [ "glBufferRegionEnabled", "GLuint", [ ], "glBufferRegionEnabled",  "GL_KTX_buffer_region" ],
480       "glNewBufferRegion" => [ "glNewBufferRegion", "GLuint", [ [ "GLenum", "type" ] ], "glNewBufferRegion", "GL_KTX_buffer_region" ],
481       "glMTexCoord2fSGIS" => [ "glMTexCoord2fSGIS", "void", [ [ "GLenum", "target" ],
482                                                               [ "GLfloat", "s" ],
483                                                               [ "GLfloat", "t" ] ], "glMTexCoord2fSGIS", "GL_SGIS_multitexture" ],
484       "glMTexCoord2fvSGIS" => [ "glMTexCoord2fvSGIS", "void", [ [ "GLenum", "target" ],
485                                                                 [ "GLfloat *", "v" ] ], "glMTexCoord2fvSGIS", "GL_SGIS_multitexture" ],
486       "glMultiTexCoord1dSGIS" => [ "glMultiTexCoord1dSGIS", "void", [ [ "GLenum", "target" ],
487                                                                       [ "GLdouble", "s" ] ],  "glMultiTexCoord1dSGIS", "GL_SGIS_multitexture" ],
488       "glMultiTexCoord1dvSGIS" => [ "glMultiTexCoord1dvSGIS", "void", [ [ "GLenum", "target" ],
489                                                                         [ "GLdouble *", "v" ] ], "glMultiTexCoord1dvSGIS", "GL_SGIS_multitexture" ],
490       "glMultiTexCoord1fSGIS" => [ "glMultiTexCoord1fSGIS", "void", [ [ "GLenum", "target" ],
491                                                                       [ "GLfloat", "s" ] ], "glMultiTexCoord1fSGIS", "GL_SGIS_multitexture" ],
492       "glMultiTexCoord1fvSGIS" => [ "glMultiTexCoord1fvSGIS", "void", [ [ "GLenum", "target" ],
493                                                                         [ "const GLfloat *", "v" ] ], "glMultiTexCoord1fvSGIS", "GL_SGIS_multitexture" ],
494       "glMultiTexCoord1iSGIS" => [ "glMultiTexCoord1iSGIS", "void", [ [ "GLenum", "target" ],
495                                                                       [ "GLint", "s" ] ], "glMultiTexCoord1iSGIS", "GL_SGIS_multitexture" ],
496       "glMultiTexCoord1ivSGIS" => [ "glMultiTexCoord1ivSGIS", "void", [ [ "GLenum", "target" ],
497                                                                         [ "GLint *", "v" ] ], "glMultiTexCoord1ivSGIS", "GL_SGIS_multitexture" ],
498       "glMultiTexCoord1sSGIS" => [ "glMultiTexCoord1sSGIS", "void", [ [ "GLenum", "target" ],
499                                                                       [ "GLshort", "s" ] ], "glMultiTexCoord1sSGIS", "GL_SGIS_multitexture" ],
500       "glMultiTexCoord1svSGIS" => [ "glMultiTexCoord1svSGIS", "void", [ [ "GLenum", "target" ],
501                                                                         [ "GLshort *", "v" ] ], "glMultiTexCoord1svSGIS", "GL_SGIS_multitexture" ],
502       "glMultiTexCoord2dSGIS" => [ "glMultiTexCoord2dSGIS", "void", [ [ "GLenum", "target" ],
503                                                                       [ "GLdouble", "s"],
504                                                                       [ "GLdouble", "t" ] ], "glMultiTexCoord2dSGIS", "GL_SGIS_multitexture" ],
505       "glMultiTexCoord2dvSGIS" => [ "glMultiTexCoord2dvSGIS", "void", [ [ "GLenum", "target" ],
506                                                                         [ "GLdouble *", "v" ] ], "glMultiTexCoord2dvSGIS", "GL_SGIS_multitexture" ],
507       "glMultiTexCoord2fSGIS" => [ "glMultiTexCoord2fSGIS", "void", [ [ "GLenum", "target" ],
508                                                                       [ "GLfloat", "s" ],
509                                                                       [ "GLfloat", "t" ] ], "glMultiTexCoord2fSGIS", "GL_SGIS_multitexture" ],
510       "glMultiTexCoord2fvSGIS" => [ "glMultiTexCoord2fvSGIS", "void", [ [ "GLenum", "target" ],
511                                                                         [ "GLfloat *", "v" ] ], "glMultiTexCoord2fvSGIS", "GL_SGIS_multitexture" ],
512       "glMultiTexCoord2iSGIS" => [ "glMultiTexCoord2iSGIS", "void", [ [ "GLenum", "target" ],
513                                                                       [ "GLint", "s" ],
514                                                                       [ "GLint", "t" ] ], "glMultiTexCoord2iSGIS", "GL_SGIS_multitexture" ],
515       "glMultiTexCoord2ivSGIS" => [ "glMultiTexCoord2ivSGIS", "void", [ [ "GLenum", "target" ],
516                                                                         [ "GLint *", "v" ] ], "glMultiTexCoord2ivSGIS", "GL_SGIS_multitexture" ],
517       "glMultiTexCoord2sSGIS" => [ "glMultiTexCoord2sSGIS", "void", [ [ "GLenum", "target" ],
518                                                                       [ "GLshort", "s" ],
519                                                                       [ "GLshort", "t" ] ], "glMultiTexCoord2sSGIS", "GL_SGIS_multitexture" ],
520       "glMultiTexCoord2svSGIS" => [ "glMultiTexCoord2svSGIS", "void", [ [ "GLenum", "target" ],
521                                                                         [ "GLshort *", "v" ] ], "glMultiTexCoord2svSGIS", "GL_SGIS_multitexture" ],
522       "glMultiTexCoord3dSGIS" => [ "glMultiTexCoord3dSGIS", "void", [ [ "GLenum", "target" ],
523                                                                       [ "GLdouble", "s" ],
524                                                                       [ "GLdouble", "t" ],
525                                                                       [ "GLdouble", "r" ] ], "glMultiTexCoord3dSGIS", "GL_SGIS_multitexture" ],
526       "glMultiTexCoord3dvSGIS" => [ "glMultiTexCoord3dvSGIS", "void", [ [ "GLenum", "target" ],
527                                                                         [ "GLdouble *", "v" ] ], "glMultiTexCoord3dvSGIS", "GL_SGIS_multitexture" ],
528       "glMultiTexCoord3fSGIS" => [ "glMultiTexCoord3fSGIS", "void", [ [ "GLenum", "target" ],
529                                                                       [ "GLfloat", "s" ],
530                                                                       [ "GLfloat", "t" ],
531                                                                       [ "GLfloat", "r" ] ], "glMultiTexCoord3fSGIS", "GL_SGIS_multitexture" ],
532       "glMultiTexCoord3fvSGIS" => [ "glMultiTexCoord3fvSGIS", "void", [ [ "GLenum", "target" ],
533                                                                         [ "GLfloat *", "v" ] ], "glMultiTexCoord3fvSGIS", "GL_SGIS_multitexture" ],
534       "glMultiTexCoord3iSGIS" => [ "glMultiTexCoord3iSGIS", "void", [ [ "GLenum", "target" ],
535                                                                       [ "GLint", "s" ],
536                                                                       [ "GLint", "t" ],
537                                                                       [ "GLint", "r" ] ], "glMultiTexCoord3iSGIS", "GL_SGIS_multitexture" ],
538       "glMultiTexCoord3ivSGIS" => [ "glMultiTexCoord3ivSGIS", "void", [ [ "GLenum", "target" ],
539                                                                         [ "GLint *", "v" ] ], "glMultiTexCoord3ivSGIS", "GL_SGIS_multitexture" ],
540       "glMultiTexCoord3sSGIS" => [ "glMultiTexCoord3sSGIS", "void", [ [ "GLenum", "target" ],
541                                                                       [ "GLshort", "s" ],
542                                                                       [ "GLshort", "t" ],
543                                                                       [ "GLshort", "r" ] ], "glMultiTexCoord3sSGIS", "GL_SGIS_multitexture" ],
544       "glMultiTexCoord3svSGIS" => [ "glMultiTexCoord3svSGIS", "void", [ [ "GLenum", "target" ],
545                                                                         [ "GLshort *", "v" ] ], "glMultiTexCoord3svSGIS", "GL_SGIS_multitexture" ],
546       "glMultiTexCoord4dSGIS" => [ "glMultiTexCoord4dSGIS", "void", [ [ "GLenum", "target" ],
547                                                                       [ "GLdouble", "s" ],
548                                                                       [ "GLdouble", "t" ],
549                                                                       [ "GLdouble", "r" ],
550                                                                       [ "GLdouble", "q" ] ], "glMultiTexCoord4dSGIS", "GL_SGIS_multitexture" ],
551       "glMultiTexCoord4dvSGIS" => [ "glMultiTexCoord4dvSGIS", "void", [ [ "GLenum", "target" ],
552                                                                         [ "GLdouble *", "v" ] ], "glMultiTexCoord4dvSGIS", "GL_SGIS_multitexture" ],
553       "glMultiTexCoord4fSGIS" => [ "glMultiTexCoord4fSGIS", "void", [ [ "GLenum", "target" ],
554                                                                       [ "GLfloat", "s" ],
555                                                                       [ "GLfloat", "t" ],
556                                                                       [ "GLfloat", "r" ],
557                                                                       [ "GLfloat", "q" ] ], "glMultiTexCoord4fSGIS", "GL_SGIS_multitexture" ],
558       "glMultiTexCoord4fvSGIS" => [ "glMultiTexCoord4fvSGIS", "void", [ [ "GLenum", "target" ],
559                                                                         [ "GLfloat *", "v" ] ], "glMultiTexCoord4fvSGIS", "GL_SGIS_multitexture" ],
560       "glMultiTexCoord4iSGIS" => [ "glMultiTexCoord4iSGIS", "void", [ [ "GLenum", "target" ],
561                                                                       [ "GLint", "s" ],
562                                                                       [ "GLint", "t" ],
563                                                                       [ "GLint", "r" ],
564                                                                       [ "GLint", "q" ] ], "glMultiTexCoord4iSGIS", "GL_SGIS_multitexture" ],
565       "glMultiTexCoord4ivSGIS" => [ "glMultiTexCoord4ivSGIS", "void", [ [ "GLenum", "target" ],
566                                                                         [ "GLint *", "v" ] ], "glMultiTexCoord4ivSGIS", "GL_SGIS_multitexture" ],
567       "glMultiTexCoord4sSGIS" => [ "glMultiTexCoord4sSGIS", "void", [ [ "GLenum", "target" ],
568                                                                       [ "GLshort", "s" ],
569                                                                       [ "GLshort", "t" ],
570                                                                       [ "GLshort", "r" ],
571                                                                       [ "GLshort", "q" ] ], "glMultiTexCoord4sSGIS", "GL_SGIS_multitexture" ],
572       "glMultiTexCoord4svSGIS" => [ "glMultiTexCoord4svSGIS", "void", [ [ "GLenum", "target" ],
573                                                                         [ "GLshort *", "v" ] ], "glMultiTexCoord4svSGIS", "GL_SGIS_multitexture" ],
574       "glMultiTexCoordPointerSGIS" => [ "glMultiTexCoordPointerSGIS", "void", [ [ "GLenum", "target" ],
575                                                                                 [ "GLint", "size" ],
576                                                                                 [ "GLenum", "type" ],
577                                                                                 [ "GLsizei", "stride" ],
578                                                                                 [ "GLvoid *", "pointer" ] ], "glMultiTexCoordPointerSGIS", "GL_SGIS_multitexture" ],
579       "glSelectTextureSGIS" => [ "glSelectTextureSGIS", "void", [ [ "GLenum", "target" ] ], "glSelectTextureSGIS", "GL_SGIS_multitexture" ],
580       "glSelectTextureCoordSetSGIS" => [ "glSelectTextureCoordSetSGIS", "void", [ [ "GLenum", "target" ] ], "glSelectTextureCoordSetSGIS", "GL_SGIS_multitexture" ],
581       "glDeleteObjectBufferATI" => [ "glDeleteObjectBufferATI", "void", [ [ "GLuint", "buffer" ] ], "glDeleteObjectBufferATI", "GL_ATI_vertex_array_object" ]
582       );
583
584 my @arg_names;
585 my %arg_types;
586 while (my $line = <REGISTRY>) {
587     if ($line =~ /^\w*\(.*\)/) {
588         # Get the function name (NOTE: the 'gl' prefix needs to be added later)
589         my ($funcname, $args) = ($line =~ /^(\w*)\((.*)\)/);
590         # and the argument names
591         @arg_names = split /\s*,\s*/, $args;
592
593         # After get :
594         #  - the return type
595         #  - category (the extension the function is part of)
596         #  - the argument types
597         #  - the category the function belongs
598         %arg_types = ();
599         my $category = "";
600         my $ret_type = "";
601         while (1) {
602             $line = <REGISTRY>;
603             unless (defined($line)) {
604                 last;
605             } elsif ($line =~ /^\s*$/) {
606                 if (($category eq "") || ($ret_type eq "")) {
607                     die "Missing 'category' line in function $funcname.\n";
608                 }
609                 last;
610             } elsif ($line =~ /\t*return\t+(\w*)/) {
611                 ($ret_type) = ($line =~ /\t*return\s*(\w*)/);
612                 $ret_type = $pseudo_to_opengl{$ret_type};
613                 unless (defined($ret_type)) {
614                     die "Unsupported return type in function $funcname\n";
615                 }
616             } elsif ($line =~ /^\t*category/) {
617                 ($category) = ($line =~ /^\t*category\s*([\w-]*)/);
618             } elsif ($line =~ /^\t*param/) {
619                 my ($name, $base_type, $ext) = ($line =~ /\t*param\s*(\w*)\s*(\w*) (.*)/);
620                 my $ptr = 0;
621                 unless (defined($name)) {
622                     chomp $line;
623                     die "Broken spec file line $line in function $funcname\n";
624                 }
625
626                 if ($ext =~ /array/) {
627                     # This is a pointer
628                     $ptr = 1;
629                 } elsif ($ext =~ /reference/) {
630                     # This is a pointer
631                     $ptr = 1;
632                 } elsif ($ext =~ /value/) {
633                     # And this a 'normal' value
634                     $ptr = 0;
635                 } else {
636                     chomp $line;
637                     die "Unsupported type : $line in function $funcname\n";
638                 }
639                 # Get the 'real' type and append a '*' in case of a pointer
640                 my $type = $pseudo_to_opengl{$base_type};
641                 unless (defined($type)) {
642                     chomp $line;
643                     die "Unsupported return type in function $funcname for type $base_type (line $line)\n";
644                 }
645                 if ($ptr) {
646                     $type = "$type*";
647                 }
648
649                 $arg_types{$name} = $type;
650             }
651         }
652
653         # Now, build the argument reference
654         my $arg_ref = [ ];
655         for (my $i = 0; $i < @arg_names; $i++) {
656             unless (defined($arg_types{$arg_names[$i]})) {
657                 print "@arg_names\n";
658                 foreach (sort keys %arg_types) {
659                     print "$_ => $arg_types{$_}\n";
660                 }
661                 die "Undefined type for $arg_names[$i] in function $funcname\n";
662             }
663
664             push @$arg_ref, [ $arg_types{$arg_names[$i]}, $arg_names[$i] ];
665         }
666         my $func_ref = [ "gl$funcname",
667                          $ret_type,
668                          $arg_ref,
669                          "gl$funcname",
670                          "GL_$category" ];
671
672         # Now, put in one or the other hash table
673         if ($norm_categories{$category}) {
674             $norm_functions{"gl$funcname"} = $func_ref;
675         } else {
676             $ext_functions{"gl$funcname"} = $func_ref;
677         }
678     }
679 }
680
681 #
682 # Clean up the input files
683 #
684 close(TYPES);
685 close(REGISTRY);
686
687 #
688 # Get the current wgl_driver.h version
689 #
690 my $wgl_version = 0;
691 open HEADER, "<../../include/wine/wgl_driver.h" or die "cannot open wgl_driver.h";
692 while (<HEADER>)
693 {
694     next unless /^#define WINE_WGL_DRIVER_VERSION (\d+)/;
695     $wgl_version = $1;
696     last;
697 }
698 close HEADER;
699
700 #
701 # Generate the wgl_driver.h file
702 #
703 open HEADER, ">../../include/wine/wgl_driver.h" or die "cannot create wgl_driver.h";
704 print HEADER "/* Automatically generated from http://www.opengl.org/registry/api files; DO NOT EDIT! */\n\n";
705 print HEADER "#ifndef __WINE_WGL_DRIVER_H\n";
706 print HEADER "#define __WINE_WGL_DRIVER_H\n\n";
707 print HEADER "#ifndef WINE_GLAPI\n";
708 print HEADER "#define WINE_GLAPI\n";
709 print HEADER "#endif\n\n";
710
711 printf HEADER "#define WINE_WGL_DRIVER_VERSION %u\n\n", $wgl_version + 1;
712
713 print HEADER "struct opengl_funcs\n{\n";
714 print HEADER "    struct\n    {\n";
715 foreach (sort keys %norm_functions)
716 {
717     next if $_ eq "glDebugEntry";
718     printf HEADER "        %s;\n", get_func_proto($norm_functions{$_});
719 }
720 print HEADER "    } gl;\n\n";
721
722 print HEADER "    struct\n    {\n";
723 foreach (sort keys %ext_functions)
724 {
725     printf HEADER "        %s;\n", get_func_proto($ext_functions{$_});
726 }
727 print HEADER "    } ext;\n";
728 print HEADER "};\n\n";
729
730 print HEADER "#define ALL_WGL_FUNCS";
731 foreach (sort keys %norm_functions)
732 {
733     next if $_ eq "glDebugEntry";
734     printf HEADER " \\\n    USE_GL_FUNC(\%s)", $_;
735 }
736 print HEADER "\n\n";
737
738 print HEADER "#endif /* __WINE_WGL_DRIVER_H */\n";
739 close HEADER;
740
741 #
742 # Now, generate the output files. First, the spec file.
743 #
744 open(SPEC, ">$spec_file");
745
746 foreach (sort keys %norm_functions) {
747     my $func_name = $norm_functions{$_}->[0];
748     print SPEC "@  stdcall $func_name( ";
749     for (my $i = 0; $i < @{$norm_functions{$_}->[2]}; $i++) {
750         my $type = $norm_functions{$_}->[2]->[$i]->[0];
751         if ($type =~ /\*/) {
752             print SPEC "ptr ";
753         } elsif (defined($arg_conv{$type})) {
754             print SPEC "$@$arg_conv{$type}[0] ";
755         } else {
756             die "No conversion for GL type $type...\n";
757         }
758     }
759     print SPEC ") wine_$func_name\n";
760 }
761
762 print SPEC "@  stdcall wglChoosePixelFormat(long ptr)
763 @  stdcall wglCopyContext(long long long)
764 @  stdcall wglCreateContext(long)
765 @  stdcall wglCreateLayerContext(long long)
766 @  stdcall wglDeleteContext(long)
767 @  stdcall wglDescribeLayerPlane(long long long long ptr)
768 @  stdcall wglDescribePixelFormat(long long long ptr)
769 @  stdcall wglGetCurrentContext()
770 @  stdcall wglGetCurrentDC()
771 @  stub    wglGetDefaultProcAddress
772 @  stdcall wglGetLayerPaletteEntries(long long long long ptr)
773 @  stdcall wglGetPixelFormat(long)
774 @  stdcall wglGetProcAddress(str)
775 @  stdcall wglMakeCurrent(long long)
776 @  stdcall wglRealizeLayerPalette(long long long)
777 @  stdcall wglSetLayerPaletteEntries(long long long long ptr)
778 @  stdcall wglSetPixelFormat(long long ptr)
779 @  stdcall wglShareLists(long long)
780 @  stdcall wglSwapBuffers(long)
781 @  stdcall wglSwapLayerBuffers(long long)
782 @  stdcall wglUseFontBitmapsA(long long long long)
783 @  stdcall wglUseFontBitmapsW(long long long long)
784 @  stdcall wglUseFontOutlinesA(long long long long long long long ptr)
785 @  stdcall wglUseFontOutlinesW(long long long long long long long ptr)
786 ";
787
788 close(SPEC);
789
790 #
791 # After the spec file, the opengl_norm.c file
792 #
793 open(NORM, ">$norm_file");
794 print NORM "
795 /* Auto-generated file... Do not edit ! */
796
797 #include \"config.h\"
798 #include <stdarg.h>
799 #include \"opengl_ext.h\"
800 #include \"winternl.h\"
801 #include \"wine/wgl_driver.h\"
802 #include \"wine/debug.h\"
803
804 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
805 ";
806
807 foreach (sort keys %norm_functions) {
808     my $string = GenerateThunk($norm_functions{$_}, 1, "gl");
809     print NORM "\n$string" if $string;
810 }
811
812 print NORM "\n";
813
814 foreach (sort keys %norm_functions) {
815     print NORM generate_null_func($norm_functions{$_});
816 }
817
818 print NORM "\n#define USE_GL_FUNC(name) null_##name,\n";
819 print NORM "struct opengl_funcs null_opengl_funcs = { { ALL_WGL_FUNCS } };\n";
820 print NORM "#undef USE_GL_FUNC\n";
821
822 close(NORM);
823
824 #
825 # Finally, more complex, the opengl_ext.c file
826 #
827 open(EXT, ">$ext_file");
828 print EXT "
829 /* Auto-generated file... Do not edit ! */
830
831 #include \"config.h\"
832 #include <stdarg.h>
833 #include \"opengl_ext.h\"
834 #include \"winternl.h\"
835 #include \"wine/wgl_driver.h\"
836 #include \"wine/debug.h\"
837
838 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
839
840 ";
841
842 # The thunks themselves....
843 my $count = keys %ext_functions;
844 print EXT "const int extension_registry_size = $count;\n";
845 print EXT "\n/* The thunks themselves....*/";
846 foreach (sort keys %ext_functions) {
847     print EXT "\nstatic ", GenerateThunk($ext_functions{$_}, 0, "ext");
848 }
849
850 # Then the table giving the string <-> function correspondence */
851 print EXT "\n\n/* The table giving the correspondence between names and functions */\n";
852 print EXT "const OpenGL_extension extension_registry[$count] = {\n";
853 my $i = 0;
854 foreach (sort keys %ext_functions) {
855     my $func_ref = $ext_functions{$_};
856     if ($func_ref->[0] eq $func_ref->[3])
857     {
858         print EXT "  { \"$func_ref->[0]\", \"$func_ref->[4]\", wine_$func_ref->[0] }";
859     }
860     if ($i != $count-1) {
861         print EXT ",";
862     }
863     $i++;
864     print EXT "\n";
865 }
866 print EXT "};\n";
867
868 close(EXT);