make_opengl 26.5 KB
Newer Older
1
#!/usr/bin/perl -w
2
use strict;
3 4 5

# This script is called thus :
#
6 7 8 9 10
#   make_opengl [opengl_version]
#
#     - It needs the gl.spec and gl.tm files in the current directory.
#       These files are hosted in the OpenGL extension registry at
#       opengl.org:
11
#
12 13 14
#       http://www.opengl.org/registry/api/gl.spec
#       http://www.opengl.org/registry/api/gl.tm
#
15 16 17
#       If they are not found in the current directory the script will
#       attempt to download them from there.
#
18 19
#       The files used to be hosted and maintained by SGI. You can still find
#       find them in the sample implementation CVS tree which is located at
20
#       CVS_ROOT/projects/ogl-sample/main/doc/registry/specs.
21
#       You can also find them on the web at the following URL :
22
#         http://oss.sgi.com/cgi-bin/cvsweb.cgi/projects/ogl-sample/main/doc/registry/specs/
23 24
#
#     - opengl_version is the OpenGL version emulated by the library
25
#       (can be 1.0 to 1.5). The default is 1.2.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
#
# This script generates the three following files :
#
#     - opengl32.spec : the spec file giving all the exported functions
#       of the OpenGL32.DLL library. These functions are the one an
#       application can directly link to (and are all the functions
#       defined in the OpenGL core for the version defined by
#       'opengl_version').
#
#     - opengl_norm.c : this file contains the thunks for all OpenGL
#       functions that are defined in 'opengl32.spec'. The corresponding
#       functions NEED to be defined in Linux's libGL or the library
#       won't be able to be linked in.
#
#     - opengl_ext.c : in this file are stored thunks for ALL possible
#       OpenGL extensions (at least, all the extensions that are defined
#       in the OpenGL extension registry). Contrary to 'opengl_norm.c',
#       you do not need to have these extensions in your libGL to have
#       OpenGL work (as they are resolved at run-time using
#       glXGetProcAddressARB).
#
47 48 49 50 51 52 53 54 55 56 57 58 59 60
# Copyright 2000 Lionel Ulmer
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
61
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
62
#
63

64 65 66
#
# Files to generate
#
67 68 69
my $spec_file = "opengl32.spec";
my $norm_file = "opengl_norm.c";
my $ext_file  = "opengl_ext.c";
70 71

# Set to 0 for removing the ENTER / LEAVE GL calls
72
my $gen_thread_safe = 1;
73
# Prefix used for the local variables
74
my $ext_prefix = "func_";
75
# If set to 1, generate TRACEs for each OpenGL function
76
my $gen_traces = 1;
77 78 79 80

#
# List of categories to put in the 'opengl_norm.c' file
#
81
my %cat_1_0 = ( "display-list" => 1,
82 83 84 85 86 87 88 89 90
	     "drawing" => 1,
	     "drawing-control" => 1,
	     "feedback" => 1,
	     "framebuf" => 1,
	     "misc" => 1,
	     "modeling" => 1,
	     "pixel-op" => 1,
	     "pixel-rw" => 1,
	     "state-req" => 1,
91
	     "xform" => 1 );
92
my %cat_1_1 = ( %cat_1_0,
93
	     "1_1" => 1 );
94
my %cat_1_2 = ( %cat_1_1,
95
	     "VERSION_1_2" => 1 );
96
my %cat_1_3 = ( %cat_1_2,
97
	     "VERSION_1_3" => 1 );
98
my %cat_1_4 = ( %cat_1_3,
99
	     "VERSION_1_4" => 1 );
100
my %cat_1_5 = ( %cat_1_4,
101
	     "VERSION_1_5" => 1 );
102

103
my %norm_categories = ();
104 105 106 107 108

#
# This hash table gives the conversion between OpenGL types and what
# is used by the TRACE printfs
#
109
my %debug_conv =
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    ("GLbitfield" => "%d",
     "GLboolean" => "%d",
     "GLbyte" => "%d",
     "GLclampd" => "%f",
     "GLclampf" => "%f",
     "GLdouble" => "%f",
     "GLenum" => "%d",
     "GLfloat" => "%f",
     "GLint" => "%d",
     "GLshort" => "%d",
     "GLsizei" => "%d",
     "GLstring" => "%s",
     "GLubyte" => "%d",
     "GLuint" => "%d",
     "GLushort" => "%d",
125
     "GLhalfNV" => "%d",
126 127 128 129
     "GLintptrARB" => "%ld",
     "GLsizeiptrARB" => "%ld",
     "GLintptr" => "%ld",
     "GLsizeiptr" => "%ld",
130 131
     "GLhandleARB" => "%d",
     "GLcharARB" => "%c",
132 133 134 135 136 137 138
     "GLvoid" => "(void)",
     "_GLfuncptr" => "%p");

#
# This hash table gives the conversion between OpenGL types and what
# is used in the .spec file
#
139
my %arg_conv =
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    ("GLbitfield" => [ "long", 4 ],
     "GLboolean" => [ "long", 4 ],
     "GLbyte" => [ "long", 4 ],
     "GLclampd" => [ "double", 8 ],
     "GLclampf" => [ "long", 4 ],
     "GLdouble" => [ "double", 8 ],
     "GLenum" => [ "long", 4 ],
     "GLfloat" => [ "long", 4 ],
     "GLint" => [ "long", 4 ],
     "GLshort" => [ "long", 4 ],
     "GLsizei" => [ "long", 4 ],
     "GLstring" => [ "str", 4 ],
     "GLubyte" => [ "long", 4 ],
     "GLuint" => [ "long", 4 ],
     "GLushort" => [ "long", 4 ],
155 156 157
     "GLhalfNV" => [ "long", 4 ],
     "GLintptrARB" => [ "long", 4 ],
     "GLsizeiptrARB" => [ "long", 4 ],
158 159 160 161
     "GLhandleARB" => [ "long", 4 ],
     "GLcharARB" => [ "long", 4 ],
     "GLintptr" => [ "long", 4 ],
     "GLsizeiptr" => [ "long", 4 ],
162 163 164
     "GLvoid" => [ "void", 4 ],
     "_GLfuncptr" => [ "ptr", 4 ]);

165 166 167
#
# Used to convert some types
#
168 169
sub ConvertType($)
{
170 171
    my ($type) = @_;

172
    my %hash = ( "GLstring" => "const GLubyte *",
173 174 175 176
	      "GLintptrARB" => "INT_PTR",
	      "GLsizeiptrARB" => "INT_PTR",
	      "GLintptr" => "INT_PTR",
	      "GLsizeiptr" => "INT_PTR",
177 178
	      "GLhandleARB" => "unsigned int",
	      "GLcharARB" => "char",
179
	      "GLchar" => "char",
180 181
	      "GLhalfNV" => "unsigned short" );

182
    foreach my $org (reverse sort keys %hash) {
183
	if ($type =~ /$org/) {
184
	    my ($before, $after) = ($type =~ /^(.*)$org(.*)$/);
185 186 187 188 189 190
	    return "$before$hash{$org}$after";
	}
    }
    return $type;
}

191 192 193
#
# Used to convert some variable names
#
194 195
sub ConvertVarName($)
{
196 197
    my ($type) = @_;

198 199
    my %hash = ( "near" => "nearParam",
                 "far"  => "farParam" );
200

201
    foreach my $org (keys %hash) {
202
	if ($type =~ /$org/) {
203
	    my ($before, $after) = ($type =~ /^(.*)$org(.*)$/);
204 205 206 207 208 209
	    return "$before$hash{$org}$after";
	}
    }
    return $type;
}

210 211 212
#
# This functions generates the thunk for a given function.
#
213
sub GenerateThunk($$$$$)
214
{
215
    my ($func_ref, $comment, $prefix, $thread_safe, $local_var) = @_;
216 217 218
    my $ret = "";
    my $call_arg = "";
    my $trace_arg = "";
219 220 221

    return "" if $func_ref->[0] eq "glGetString";
    return "" if $func_ref->[0] eq "glGetIntegerv";
222 223
    return "" if $func_ref->[0] eq "glFinish";
    return "" if $func_ref->[0] eq "glFlush";
224 225

    # If for opengl_norm.c, generate a nice heading otherwise Patrik won't be happy :-)
226
    # Patrik says: Well I would be even happier if a (OPENGL32.@) was added as well. Done. :-)
227
    if ($comment eq 1) {
228 229 230
	$ret = "$ret/***********************************************************************\n";
	$ret = "$ret *              $func_ref->[0] (OPENGL32.\@)\n";
	$ret = "$ret */\n";
231
    }
232
    $ret = $ret . ConvertType($func_ref->[1]) . " WINAPI wine_$func_ref->[0]( ";
233
    for (my $i = 0; $i < @{$func_ref->[2]}; $i++) {
234 235
	## Quick debug code :-)
	## print $func_ref->[2]->[$i]->[1] . "\n";
236 237
	my $type = $func_ref->[2]->[$i]->[0];
	my $name = ConvertVarName($func_ref->[2]->[$i]->[1]);
238
	$ret = $ret . ConvertType($type) . " $name";
239
	$call_arg = "$call_arg$name";
240
	if ($type =~ /\*/) {
241
	    $trace_arg = "$trace_arg\%p";
242
	} else {
243
	    $trace_arg = "$trace_arg$debug_conv{$type}";
244
	}
245
	if ($i+1 < @{$func_ref->[2]}) {
246 247 248
	    $ret = "$ret, ";
	    $call_arg = "$call_arg, ";
	    $trace_arg = "$trace_arg, ";
249
	} else {
250 251
	    $ret = "$ret ";
	    $call_arg = "$call_arg ";
252 253
	}
    }
254
    $ret .= 'void ' if (!@{$func_ref->[2]});
255
    $ret = "$ret) {\n";
256
    if ($func_ref->[1] ne "void") {
257
	$ret = "$ret  " . ConvertType($func_ref->[1]) . " ret_value;\n";
258
    }
259
    $ret .= $local_var;
260
    if ($gen_traces) {
261
	$ret = "$ret  TRACE(\"($trace_arg)\\n\"";
262
	if ($trace_arg ne "") {
263
	    $ret = "$ret, $call_arg";
264
	}
265
	$ret = "$ret);\n";
266
    }
267
    if ($thread_safe) {
268
	$ret = "$ret  ENTER_GL();\n";
269
    }
270
    $ret = "$ret  ";
271 272 273
    if ($func_ref->[1] ne "void") {
	$ret = $ret . "ret_value = ";
    }
274
    $ret = "$ret$prefix$func_ref->[0]( $call_arg);\n";
275
    if ($thread_safe) {
276
	$ret = "$ret  LEAVE_GL();\n";
277 278
    }
    if ($func_ref->[1] ne "void") {
279
	$ret = "$ret  return ret_value;\n"
280
    }
281
    $ret = "$ret}\n";
282 283

    # Return this string....
284
    return $ret;
285 286 287 288 289
}

#
# Extract and checks the number of arguments
#
290
if (@ARGV > 1) {
291 292
    my $name0=$0;
    $name0=~s%^.*/%%;
293
    die "Usage: $name0 [version]\n";
294
}
295
my $version = $ARGV[0] || "1.2";
296 297 298 299 300 301
if ($version eq "1.0") {
    %norm_categories = %cat_1_0;
} elsif ($version eq "1.1") {
    %norm_categories = %cat_1_1;
} elsif ($version eq "1.2") {
    %norm_categories = %cat_1_2;
302 303 304 305 306 307
} elsif ($version eq "1.3") {
    %norm_categories = %cat_1_3;
} elsif ($version eq "1.4") {
    %norm_categories = %cat_1_4;
} elsif ($version eq "1.5") {
    %norm_categories = %cat_1_5;
308
} else {
309
    die "Incorrect OpenGL version.\n";
310 311
}

312 313 314 315 316 317
#
# Fetch the registry files
#
-f "gl.spec" || system "wget http://www.opengl.org/registry/api/gl.spec" || die "cannot download gl.spec";
-f "gl.tm" || system "wget http://www.opengl.org/registry/api/gl.tm" || die "cannot download gl.tm";

318 319 320
#
# Open the registry files
#
321 322
open(TYPES,    "gl.tm")   || die "Could not open gl.tm";
open(REGISTRY, "gl.spec") || die "Could not open gl.spec";
323 324 325 326 327

#
# First, create a mapping between the pseudo types used in the spec file
# and OpenGL types using the 'gl.tm' file.
#
328 329
my %pseudo_to_opengl = ();
while (my $line = <TYPES>) {
330
    if ($line !~ /\w*\#/) {
331
	my ($pseudo, $opengl) = ($line =~ /(\w*),\*,\*,\s*(.*),\*,\*/);
332 333
	$pseudo_to_opengl{$pseudo} = $opengl;
    }
334 335 336
}
# This is to override the 'void' -> '*' bogus conversion
$pseudo_to_opengl{"void"} = "void";
337 338
$pseudo_to_opengl{"Int64EXT"} = "INT64";
$pseudo_to_opengl{"UInt64EXT"} = "UINT64";
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377

#
# Then, create the list of all OpenGL functions using the 'gl.spec'
# file. This will create two hash-tables, one with all the function
# whose category matches the one listed in '@norm_categories', the other
# with all other functions.
#
# An element of the hash table is a reference to an array with these
# elements :
#
#  - function name
#
#  - return type
#
#  - reference to an array giving the list of arguments (an empty array
#    for a 'void' function).
#
# The list of arguments is itself an array of reference to arrays. Each
# of these arrays represents the argument type and the argument name.
#
# An example :
#
# void glBitmap( GLsizei width, GLsizei height,
#                GLfloat xorig, GLfloat yorig,
#                GLfloat xmove, GLfloat ymove,
#                const GLubyte *bitmap );
#
# Would give something like that :
#
# [ "glBitmap",
#   "void",
#   [ [ "GLsizei", "width" ],
#     [ "GLsizei", "height" ],
#     [ "GLfloat", "xorig" ],
#     [ "GLfloat", "yorig" ],
#     [ "GLfloat", "xmove" ],
#     [ "GLfloat", "ymove" ],
#     [ "GLubyte *", "bitmap"] ] ];
#
378
my %norm_functions = ();
379 380 381 382 383

#
# This stores various extensions NOT part of the GL extension registry but still
# implemented by most OpenGL libraries out there...
#
384 385

my %ext_functions  =
386
    ( "glDeleteBufferRegion" => [ "glDeleteBufferRegion", "void", [ [ "GLenum", "region" ] ], "glDeleteBufferRegion", "GL_KTX_buffer_region" ],
387 388 389 390
      "glReadBufferRegion" => [ "glReadBufferRegion", "void", [ [ "GLenum", "region" ],
								[ "GLint", "x" ],
								[ "GLint", "y" ],
								[ "GLsizei", "width" ],
391
								[ "GLsizei", "height" ] ], "glReadBufferRegion", "GL_KTX_buffer_region" ],
392 393 394 395 396 397
      "glDrawBufferRegion" => [ "glDrawBufferRegion", "void", [ [ "GLenum", "region" ],
								[ "GLint", "x" ],
								[ "GLint", "y" ],
								[ "GLsizei", "width" ],
								[ "GLsizei", "height" ],
								[ "GLint", "xDest" ],
398 399 400
								[ "GLint", "yDest" ] ], "glDrawBufferRegion", "GL_KTX_buffer_region" ],
      "glBufferRegionEnabled" => [ "glBufferRegionEnabled", "GLuint", [ ], "glBufferRegionEnabled",  "GL_KTX_buffer_region" ],
      "glNewBufferRegion" => [ "glNewBufferRegion", "GLuint", [ [ "GLenum", "type" ] ], "glNewBufferRegion", "GL_KTX_buffer_region" ],
401
      "glMTexCoord2fSGIS" => [ "glMTexCoord2fSGIS", "void", [ [ "GLenum", "target" ],
402
							      [ "GLfloat", "s" ],
403
							      [ "GLfloat", "t" ] ], "glMTexCoord2fSGIS", "GL_SGIS_multitexture" ],
404
      "glMTexCoord2fvSGIS" => [ "glMTexCoord2fvSGIS", "void", [ [ "GLenum", "target" ],
405
								[ "GLfloat *", "v" ] ], "glMTexCoord2fvSGIS", "GL_SGIS_multitexture" ],
406
      "glMultiTexCoord1dSGIS" => [ "glMultiTexCoord1dSGIS", "void", [ [ "GLenum", "target" ],
407
								      [ "GLdouble", "s" ] ],  "glMultiTexCoord1dSGIS", "GL_SGIS_multitexture" ],
408
      "glMultiTexCoord1dvSGIS" => [ "glMultiTexCoord1dvSGIS", "void", [ [ "GLenum", "target" ],
409
									[ "GLdouble *", "v" ] ], "glMultiTexCoord1dvSGIS", "GL_SGIS_multitexture" ],
410
      "glMultiTexCoord1fSGIS" => [ "glMultiTexCoord1fSGIS", "void", [ [ "GLenum", "target" ],
411
								      [ "GLfloat", "s" ] ], "glMultiTexCoord1fSGIS", "GL_SGIS_multitexture" ],
412
      "glMultiTexCoord1fvSGIS" => [ "glMultiTexCoord1fvSGIS", "void", [ [ "GLenum", "target" ],
413
									[ "const GLfloat *", "v" ] ], "glMultiTexCoord1fvSGIS", "GL_SGIS_multitexture" ],
414
      "glMultiTexCoord1iSGIS" => [ "glMultiTexCoord1iSGIS", "void", [ [ "GLenum", "target" ],
415
								      [ "GLint", "s" ] ], "glMultiTexCoord1iSGIS", "GL_SGIS_multitexture" ],
416
      "glMultiTexCoord1ivSGIS" => [ "glMultiTexCoord1ivSGIS", "void", [ [ "GLenum", "target" ],
417
									[ "GLint *", "v" ] ], "glMultiTexCoord1ivSGIS", "GL_SGIS_multitexture" ],
418
      "glMultiTexCoord1sSGIS" => [ "glMultiTexCoord1sSGIS", "void", [ [ "GLenum", "target" ],
419
								      [ "GLshort", "s" ] ], "glMultiTexCoord1sSGIS", "GL_SGIS_multitexture" ],
420
      "glMultiTexCoord1svSGIS" => [ "glMultiTexCoord1svSGIS", "void", [ [ "GLenum", "target" ],
421
									[ "GLshort *", "v" ] ], "glMultiTexCoord1svSGIS", "GL_SGIS_multitexture" ],
422 423
      "glMultiTexCoord2dSGIS" => [ "glMultiTexCoord2dSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLdouble", "s"],
424
								      [ "GLdouble", "t" ] ], "glMultiTexCoord2dSGIS", "GL_SGIS_multitexture" ],
425
      "glMultiTexCoord2dvSGIS" => [ "glMultiTexCoord2dvSGIS", "void", [ [ "GLenum", "target" ],
426
									[ "GLdouble *", "v" ] ], "glMultiTexCoord2dvSGIS", "GL_SGIS_multitexture" ],
427 428
      "glMultiTexCoord2fSGIS" => [ "glMultiTexCoord2fSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLfloat", "s" ],
429
								      [ "GLfloat", "t" ] ], "glMultiTexCoord2fSGIS", "GL_SGIS_multitexture" ],
430
      "glMultiTexCoord2fvSGIS" => [ "glMultiTexCoord2fvSGIS", "void", [ [ "GLenum", "target" ],
431
									[ "GLfloat *", "v" ] ], "glMultiTexCoord2fvSGIS", "GL_SGIS_multitexture" ],
432 433
      "glMultiTexCoord2iSGIS" => [ "glMultiTexCoord2iSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLint", "s" ],
434
								      [ "GLint", "t" ] ], "glMultiTexCoord2iSGIS", "GL_SGIS_multitexture" ],
435
      "glMultiTexCoord2ivSGIS" => [ "glMultiTexCoord2ivSGIS", "void", [ [ "GLenum", "target" ],
436
									[ "GLint *", "v" ] ], "glMultiTexCoord2ivSGIS", "GL_SGIS_multitexture" ],
437 438
      "glMultiTexCoord2sSGIS" => [ "glMultiTexCoord2sSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLshort", "s" ],
439
								      [ "GLshort", "t" ] ], "glMultiTexCoord2sSGIS", "GL_SGIS_multitexture" ],
440
      "glMultiTexCoord2svSGIS" => [ "glMultiTexCoord2svSGIS", "void", [ [ "GLenum", "target" ],
441
									[ "GLshort *", "v" ] ], "glMultiTexCoord2svSGIS", "GL_SGIS_multitexture" ],
442 443 444
      "glMultiTexCoord3dSGIS" => [ "glMultiTexCoord3dSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLdouble", "s" ],
								      [ "GLdouble", "t" ],
445
								      [ "GLdouble", "r" ] ], "glMultiTexCoord3dSGIS", "GL_SGIS_multitexture" ],
446
      "glMultiTexCoord3dvSGIS" => [ "glMultiTexCoord3dvSGIS", "void", [ [ "GLenum", "target" ],
447
									[ "GLdouble *", "v" ] ], "glMultiTexCoord3dvSGIS", "GL_SGIS_multitexture" ],
448 449 450
      "glMultiTexCoord3fSGIS" => [ "glMultiTexCoord3fSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLfloat", "s" ],
								      [ "GLfloat", "t" ],
451
								      [ "GLfloat", "r" ] ], "glMultiTexCoord3fSGIS", "GL_SGIS_multitexture" ],
452
      "glMultiTexCoord3fvSGIS" => [ "glMultiTexCoord3fvSGIS", "void", [ [ "GLenum", "target" ],
453
									[ "GLfloat *", "v" ] ], "glMultiTexCoord3fvSGIS", "GL_SGIS_multitexture" ],
454 455 456
      "glMultiTexCoord3iSGIS" => [ "glMultiTexCoord3iSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLint", "s" ],
								      [ "GLint", "t" ],
457
								      [ "GLint", "r" ] ], "glMultiTexCoord3iSGIS", "GL_SGIS_multitexture" ],
458
      "glMultiTexCoord3ivSGIS" => [ "glMultiTexCoord3ivSGIS", "void", [ [ "GLenum", "target" ],
459
									[ "GLint *", "v" ] ], "glMultiTexCoord3ivSGIS", "GL_SGIS_multitexture" ],
460 461 462
      "glMultiTexCoord3sSGIS" => [ "glMultiTexCoord3sSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLshort", "s" ],
								      [ "GLshort", "t" ],
463
								      [ "GLshort", "r" ] ], "glMultiTexCoord3sSGIS", "GL_SGIS_multitexture" ],
464
      "glMultiTexCoord3svSGIS" => [ "glMultiTexCoord3svSGIS", "void", [ [ "GLenum", "target" ],
465
									[ "GLshort *", "v" ] ], "glMultiTexCoord3svSGIS", "GL_SGIS_multitexture" ],
466 467 468 469
      "glMultiTexCoord4dSGIS" => [ "glMultiTexCoord4dSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLdouble", "s" ],
								      [ "GLdouble", "t" ],
								      [ "GLdouble", "r" ],
470
								      [ "GLdouble", "q" ] ], "glMultiTexCoord4dSGIS", "GL_SGIS_multitexture" ],
471
      "glMultiTexCoord4dvSGIS" => [ "glMultiTexCoord4dvSGIS", "void", [ [ "GLenum", "target" ],
472
									[ "GLdouble *", "v" ] ], "glMultiTexCoord4dvSGIS", "GL_SGIS_multitexture" ],
473 474 475 476
      "glMultiTexCoord4fSGIS" => [ "glMultiTexCoord4fSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLfloat", "s" ],
								      [ "GLfloat", "t" ],
								      [ "GLfloat", "r" ],
477
								      [ "GLfloat", "q" ] ], "glMultiTexCoord4fSGIS", "GL_SGIS_multitexture" ],
478
      "glMultiTexCoord4fvSGIS" => [ "glMultiTexCoord4fvSGIS", "void", [ [ "GLenum", "target" ],
479
									[ "GLfloat *", "v" ] ], "glMultiTexCoord4fvSGIS", "GL_SGIS_multitexture" ],
480 481 482 483
      "glMultiTexCoord4iSGIS" => [ "glMultiTexCoord4iSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLint", "s" ],
								      [ "GLint", "t" ],
								      [ "GLint", "r" ],
484
								      [ "GLint", "q" ] ], "glMultiTexCoord4iSGIS", "GL_SGIS_multitexture" ],
485
      "glMultiTexCoord4ivSGIS" => [ "glMultiTexCoord4ivSGIS", "void", [ [ "GLenum", "target" ],
486
									[ "GLint *", "v" ] ], "glMultiTexCoord4ivSGIS", "GL_SGIS_multitexture" ],
487 488 489 490
      "glMultiTexCoord4sSGIS" => [ "glMultiTexCoord4sSGIS", "void", [ [ "GLenum", "target" ],
								      [ "GLshort", "s" ],
								      [ "GLshort", "t" ],
								      [ "GLshort", "r" ],
491
								      [ "GLshort", "q" ] ], "glMultiTexCoord4sSGIS", "GL_SGIS_multitexture" ],
492
      "glMultiTexCoord4svSGIS" => [ "glMultiTexCoord4svSGIS", "void", [ [ "GLenum", "target" ],
493
									[ "GLshort *", "v" ] ], "glMultiTexCoord4svSGIS", "GL_SGIS_multitexture" ],
494 495
      "glMultiTexCoordPointerSGIS" => [ "glMultiTexCoordPointerSGIS", "void", [ [ "GLenum", "target" ],
										[ "GLint", "size" ],
496
										[ "GLenum", "type" ],
497
										[ "GLsizei", "stride" ],
498 499 500 501
										[ "GLvoid *", "pointer" ] ], "glMultiTexCoordPointerSGIS", "GL_SGIS_multitexture" ],
      "glSelectTextureSGIS" => [ "glSelectTextureSGIS", "void", [ [ "GLenum", "target" ] ], "glSelectTextureSGIS", "GL_SGIS_multitexture" ],
      "glSelectTextureCoordSetSGIS" => [ "glSelectTextureCoordSetSGIS", "void", [ [ "GLenum", "target" ] ], "glSelectTextureCoordSetSGIS", "GL_SGIS_multitexture" ],
      "glDeleteObjectBufferATI" => [ "glDeleteObjectBufferATI", "void", [ [ "GLuint", "buffer" ] ], "glDeleteObjectBufferATI", "GL_ATI_vertex_array_object" ]
502
      );
503

504 505 506
my @arg_names;
my %arg_types;
while (my $line = <REGISTRY>) {
507 508
    if ($line =~ /^\w*\(.*\)/) {
	# Get the function name (NOTE: the 'gl' prefix needs to be added later)
509
	my ($funcname, $args) = ($line =~ /^(\w*)\((.*)\)/);
510 511
	# and the argument names
	@arg_names = split /\s*,\s*/, $args;
512

513 514
	# After get :
	#  - the return type
515
	#  - category (the extension the function is part of)
516 517 518
	#  - the argument types
	#  - the category the function belongs
	%arg_types = ();
519 520
	my $category = "";
	my $ret_type = "";
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
	while (1) {
	    $line = <REGISTRY>;
	    unless (defined($line)) {
		last;
	    } elsif ($line =~ /^\s*$/) {
		if (($category eq "") || ($ret_type eq "")) {
		    die "Missing 'category' line in function $funcname.\n";
		}
		last;
	    } elsif ($line =~ /\t*return\t*(\w*)/) {
		($ret_type) = ($line =~ /\t*return\s*(\w*)/);
		$ret_type = $pseudo_to_opengl{$ret_type};
		unless (defined($ret_type)) {
		    die "Unsupported return type in function $funcname\n";
		}
	    } elsif ($line =~ /^\t*category/) {
		($category) = ($line =~ /^\t*category\s*([\w-]*)/);
	    } elsif ($line =~ /^\t*param/) {
539 540
		my ($name, $base_type, $ext) = ($line =~ /\t*param\s*(\w*)\s*(\w*) (.*)/);
		my $ptr = 0;
541
		unless (defined($name)) {
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
		    chomp $line;
		    die "Broken spec file line $line in function $funcname\n";
		}

		if ($ext =~ /array/) {
		    # This is a pointer
		    $ptr = 1;
		} elsif ($ext =~ /value/) {
		    # And this a 'normal' value
		    $ptr = 0;
		} else {
		    chomp $line;
		    die "Unsupported type : $line in function $funcname\n";
		}
		# Get the 'real' type and append a '*' in case of a pointer
557
		my $type = $pseudo_to_opengl{$base_type};
558 559 560 561 562
		unless (defined($type)) {
		    chomp $line;
		    die "Unsupported return type in function $funcname for type $base_type (line $line)\n";
		}
		if ($ptr) {
563
		    $type = "$type*";
564
		}
565

566 567 568 569 570
		$arg_types{$name} = $type;
	    }
	}

	# Now, build the argument reference
571
	my $arg_ref = [ ];
572
	for (my $i = 0; $i < @arg_names; $i++) {
573 574 575 576 577 578 579
	    unless (defined($arg_types{$arg_names[$i]})) {
		print "@arg_names\n";
		foreach (sort keys %arg_types) {
		    print "$_ => $arg_types{$_}\n";
		}
		die "Undefined type for $arg_names[$i] in function $funcname\n";
	    }
580

581 582
	    push @$arg_ref, [ $arg_types{$arg_names[$i]}, $arg_names[$i] ];
	}
583 584 585
	my $func_ref = [ "gl$funcname",
                         $ret_type,
                         $arg_ref,
586 587
                         "gl$funcname",
                         "GL_$category" ];
588

589 590
	# Now, put in one or the other hash table
	if ($norm_categories{$category}) {
591
	    $norm_functions{"gl$funcname"} = $func_ref;
592
	} else {
593
	    $ext_functions{"gl$funcname"} = $func_ref;
594 595 596 597 598 599 600 601 602 603 604 605 606
	}
    }
}

#
# Clean up the input files
#
close(TYPES);
close(REGISTRY);

#
# Now, generate the output files. First, the spec file.
#
607
open(SPEC, ">$spec_file");
608 609

foreach (sort keys %norm_functions) {
610
    my $func_name = $norm_functions{$_}->[0];
611
    print SPEC "@  stdcall $func_name( ";
612
    for (my $i = 0; $i < @{$norm_functions{$_}->[2]}; $i++) {
613
	my $type = $norm_functions{$_}->[2]->[$i]->[0];
614 615 616 617 618
	if ($type =~ /\*/) {
	    print SPEC "ptr ";
	} elsif (defined($arg_conv{$type})) {
	    print SPEC "$@$arg_conv{$type}[0] ";
	} else {
619
	    die "No conversion for GL type $type...\n";
620 621 622 623
	}
    }
    print SPEC ") wine_$func_name\n";
}
624 625 626 627

print SPEC "@  stub    glGetLevelParameterfv
@  stub    glGetLevelParameteriv
@  stdcall wglChoosePixelFormat(long ptr) gdi32.ChoosePixelFormat
628
@  stdcall wglCopyContext(long long long) gdi32.wglCopyContext
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
@  stdcall wglCreateContext(long) gdi32.wglCreateContext
@  stdcall wglCreateLayerContext(long long)
@  stdcall wglDeleteContext(long) gdi32.wglDeleteContext
@  stdcall wglDescribeLayerPlane(long long long long ptr)
@  stdcall wglDescribePixelFormat(long long long ptr) gdi32.DescribePixelFormat
@  stdcall wglGetCurrentContext() gdi32.wglGetCurrentContext
@  stdcall wglGetCurrentDC() gdi32.wglGetCurrentDC
@  stub    wglGetDefaultProcAddress
@  stdcall wglGetLayerPaletteEntries(long long long long ptr)
@  stdcall wglGetPixelFormat(long) gdi32.GetPixelFormat
@  stdcall wglGetProcAddress(str)
@  stdcall wglMakeCurrent(long long) gdi32.wglMakeCurrent
@  stdcall wglRealizeLayerPalette(long long long)
@  stdcall wglSetLayerPaletteEntries(long long long long ptr)
@  stdcall wglSetPixelFormat(long long ptr) gdi32.SetPixelFormat
@  stdcall wglShareLists(long long) gdi32.wglShareLists
@  stdcall wglSwapBuffers(long) gdi32.SwapBuffers
@  stdcall wglSwapLayerBuffers(long long)
@  stdcall wglUseFontBitmapsA(long long long long) gdi32.wglUseFontBitmapsA
@  stdcall wglUseFontBitmapsW(long long long long) gdi32.wglUseFontBitmapsW
@  stdcall wglUseFontOutlinesA(long long long long long long long ptr)
@  stdcall wglUseFontOutlinesW(long long long long long long long ptr)
";

653 654 655 656 657
close(SPEC);

#
# After the spec file, the opengl_norm.c file
#
658
open(NORM, ">$norm_file");
659 660 661 662
print NORM "
/* Auto-generated file... Do not edit ! */

#include \"config.h\"
663
#include \"opengl_ext.h\"
664
#include \"wine/debug.h\"
665

666
WINE_DEFAULT_DEBUG_CHANNEL(opengl);
667 668
";
foreach (sort keys %norm_functions) {
669
    my $string = GenerateThunk($norm_functions{$_}, 1, "", $gen_thread_safe, "");
670

671
    print NORM "\n$string" if $string;
672 673 674 675 676 677
}
close(NORM);

#
# Finally, more complex, the opengl_ext.c file
#
678
open(EXT, ">$ext_file");
679 680 681 682
print EXT "
/* Auto-generated file... Do not edit ! */

#include \"config.h\"
683
#include \"opengl_ext.h\"
684
#include \"wine/debug.h\"
685

686
WINE_DEFAULT_DEBUG_CHANNEL(opengl);
687

688 689
";

690 691
# The thunks themselves....
my $count = keys %ext_functions;
692 693 694 695 696 697 698 699
print EXT "enum extensions\n{\n";
foreach (sort keys %ext_functions) {
    my $func_ref = $ext_functions{$_};
    print EXT "    EXT_$func_ref->[0],\n";
}
print EXT "    NB_EXTENSIONS\n};\n\n";
print EXT "const int extension_registry_size = NB_EXTENSIONS;\n";
print EXT "void *extension_funcs[NB_EXTENSIONS];\n";
700
print EXT "\n/* The thunks themselves....*/";
701
foreach (sort keys %ext_functions) {
702
    my $func_ref = $ext_functions{$_};
703
    my $local_var = "  " . ConvertType($func_ref->[1]) . " (*$ext_prefix$func_ref->[0])( ";
704
    for (my $i = 0; $i < @{$func_ref->[2]}; $i++) {
705
	my $type = ConvertType($func_ref->[2]->[$i]->[0]);
706
	$local_var .= "$type";
707
	if ($i+1 < @{$func_ref->[2]}) {
708
	    $local_var .= ", ";
709
	} else {
710
	    $local_var .= " ";
711 712
	}
    }
713
    $local_var .= 'void ' if (!@{$func_ref->[2]});
714
    $local_var .= ") = extension_funcs[EXT_$func_ref->[0]];\n";
715
    print EXT "\nstatic ", GenerateThunk($ext_functions{$_}, 0, $ext_prefix, $gen_thread_safe, $local_var);
716 717
}

718 719
# Then the table giving the string <-> function correspondence */
print EXT "\n\n/* The table giving the correspondence between names and functions */\n";
720
print EXT "const OpenGL_extension extension_registry[NB_EXTENSIONS] = {\n";
721
my $i = 0;
722
foreach (sort keys %ext_functions) {
723
    my $func_ref = $ext_functions{$_};
724 725
    if ($func_ref->[0] eq $func_ref->[3])
    {
726
        print EXT "  { \"$func_ref->[0]\", \"$func_ref->[4]\", wine_$func_ref->[0] }";
727
    }
728
    if ($i != $count-1) {
729 730 731 732 733 734 735 736
	print EXT ",";
    }
    $i++;
    print EXT "\n";
}
print EXT "};\n";

close(EXT);