3 # This script is called thus :
5 # make_opengl path_to_spec_file opengl_version
7 # - path_to_spec_file is the path to the directory where the OpenGL
8 # spec files are located. These files are part of the OpenGL
9 # sample implementation CVS tree and are located in
10 # CVS_ROOT/projects/ogl-sample/main/doc/registry/specs.
12 # - opengl_version is the OpenGL version emulated by the library
13 # (can be 1.0 to 1.2).
15 # This script generates the three following files :
17 # - opengl32.spec : the spec file giving all the exported functions
18 # of the OpenGL32.DLL library. These functions are the one an
19 # application can directly link to (and are all the functions
20 # defined in the OpenGL core for the version defined by
23 # - opengl_norm.c : this file contains the thunks for all OpenGL
24 # functions that are defined in 'opengl32.spec'. The corresponding
25 # functions NEED to be defined in Linux's libGL or the library
26 # won't be able to be linked in.
28 # - opengl_ext.c : in this file are stored thunks for ALL possible
29 # OpenGL extensions (at least, all the extensions that are defined
30 # in the OpenGL extension registry). Contrary to 'opengl_norm.c',
31 # you do not need to have these extensions in your libGL to have
32 # OpenGL work (as they are resolved at run-time using
33 # glXGetProcAddressARB).
37 # This functions generates the thunk for a given function.
40 my ($func_ref, $comment, $prefix, $thread_safe) = @_;
42 my ($call_arg) = ("");
44 # If for opengl_norm.c, generate a nice heading otherwise Patrik won't be happy :-)
46 $ret = $ret . "/***********************************************************************\n";
47 $ret = $ret . " * " . $func_ref->[0] . "\n";
48 $ret = $ret . " */\n";
50 $ret = $ret . $func_ref->[1] . " WINAPI wine_" . $func_ref->[0] . "( ";
51 for ($i = 0; $i <= $#{@{$func_ref->[2]}}; $i++) {
52 $type = $func_ref->[2]->[$i]->[0];
53 $name = $func_ref->[2]->[$i]->[1];
54 $ret = $ret . "$type $name";
55 $call_arg = $call_arg . "$name";
56 if ($i != $#{@{$func_ref->[2]}}) {
58 $call_arg = $call_arg . ", ";
61 $call_arg = $call_arg . " ";
64 $ret = $ret . ") {\n";
65 if ($func_ref->[1] ne "void") {
66 $ret = $ret . " " . $func_ref->[1] . " ret_value;\n";
69 $ret = $ret . " ENTER_GL();\n";
72 if ($func_ref->[1] ne "void") {
73 $ret = $ret . "ret_value = ";
75 $ret = $ret . $prefix . $func_ref->[0] . "( " . $call_arg . ");\n";
77 $ret = $ret . " LEAVE_GL();\n";
79 if ($func_ref->[1] ne "void") {
80 $ret = $ret . " return ret_value;\n"
84 # Return this string....
89 # This hash table gives the conversion between OpenGL types and what
90 # is used in the .spec file
93 ("GLbitfield" => [ "long", 4 ],
94 "GLboolean" => [ "long", 4 ],
95 "GLbyte" => [ "long", 4 ],
96 "GLclampd" => [ "double", 8 ],
97 "GLclampf" => [ "long", 4 ],
98 "GLdouble" => [ "double", 8 ],
99 "GLenum" => [ "long", 4 ],
100 "GLfloat" => [ "long", 4 ],
101 "GLint" => [ "long", 4 ],
102 "GLshort" => [ "long", 4 ],
103 "GLsizei" => [ "long", 4 ],
104 "GLstring" => [ "str", 4 ],
105 "GLubyte" => [ "long", 4 ],
106 "GLuint" => [ "long", 4 ],
107 "GLushort" => [ "long", 4 ],
108 "GLvoid" => [ "void", 4 ],
109 "_GLfuncptr" => [ "ptr", 4 ]);
114 $spec_file = "opengl32.spec";
115 $norm_file = "opengl_norm.c";
116 $ext_file = "opengl_ext.c";
118 # Set to 0 for removing the ENTER / LEAVE GL calls
119 $gen_thread_safe = 1;
120 # Prefix used for the local variables
121 $ext_prefix = "func_";
124 # List of categories to put in the 'opengl_norm.c' file
126 %cat_1_0 = ( "display-list" => 1,
128 "drawing-control" => 1,
137 %cat_1_1 = ( %cat_1_0,
139 %cat_1_2 = ( %cat_1_1,
141 "ARB_multitexture" => 1 );
143 %norm_categories = ();
146 # Extract and checks the number of arguments
149 die "Usage : make_opengl OpenGL_registry_location OpenGL_version.\n";
151 $registry_path = shift @ARGV;
152 $version = shift @ARGV;
153 if ($version eq "1.0") {
154 %norm_categories = %cat_1_0;
155 } elsif ($version eq "1.1") {
156 %norm_categories = %cat_1_1;
157 } elsif ($version eq "1.2") {
158 %norm_categories = %cat_1_2;
160 die "OpenGL version incorrect. Should be one of '1.0', '1.1' or '1.2'.\n";
164 # Open the registry files
166 open(TYPES
, $registry_path . "/gl.tm") || die "Could not open 'gl.tm'. Please check your path the the registry files.\n";
167 open(REGISTRY
, $registry_path . "/gl.spec") || die "Could not open 'gl.spec'. Please check your path the the registry files.\n";
170 # First, create a mapping between the pseudo types used in the spec file
171 # and OpenGL types using the 'gl.tm' file.
173 %pseudo_to_opengl = ();
174 while ($line = <TYPES
>) {
175 ($pseudo, $opengl) = ($line =~ /(\w*),\*,\*,\s*(.*),\*,\*/);
176 $pseudo_to_opengl{$pseudo} = $opengl;
178 # This is to override the 'void' -> '*' bogus conversion
179 $pseudo_to_opengl{"void"} = "void";
182 # Then, create the list of all OpenGL functions using the 'gl.spec'
183 # file. This will create two hash-tables, one with all the function
184 # whose category matches the one listed in '@norm_categories', the other
185 # with all other functions.
187 # An element of the hash table is a reference to an array with these
194 # - reference to an array giving the list of arguments (an empty array
195 # for a 'void' function).
197 # The list of arguments is itself an array of reference to arrays. Each
198 # of these arrays represents the argument type and the argument name.
202 # void glBitmap( GLsizei width, GLsizei height,
203 # GLfloat xorig, GLfloat yorig,
204 # GLfloat xmove, GLfloat ymove,
205 # const GLubyte *bitmap );
207 # Would give something like that :
211 # [ [ "GLsizei", "width" ],
212 # [ "GLsizei", "height" ],
213 # [ "GLfloat", "xorig" ],
214 # [ "GLfloat", "yorig" ],
215 # [ "GLfloat", "xmove" ],
216 # [ "GLfloat", "ymove" ],
217 # [ "GLubyte *", "bitmap"] ] ];
219 %norm_functions = ();
222 while ($line = <REGISTRY
>) {
223 if ($line =~ /^\w*\(.*\)/) {
224 # Get the function name (NOTE: the 'gl' prefix needs to be added later)
225 ($funcname, $args) = ($line =~ /^(\w*)\((.*)\)/);
226 # and the argument names
227 @arg_names = split /\s*,\s*/, $args;
231 # - the argument types
232 # - the category the function belongs
238 unless (defined($line)) {
240 } elsif ($line =~ /^\s*$/) {
241 if (($category eq "") || ($ret_type eq "")) {
242 die "Missing 'category' line in function $funcname.\n";
245 } elsif ($line =~ /\t*return\t*(\w*)/) {
246 ($ret_type) = ($line =~ /\t*return\s*(\w*)/);
247 $ret_type = $pseudo_to_opengl{$ret_type};
248 unless (defined($ret_type)) {
249 die "Unsupported return type in function $funcname\n";
251 } elsif ($line =~ /^\t*category/) {
252 ($category) = ($line =~ /^\t*category\s*([\w-]*)/);
253 } elsif ($line =~ /^\t*param/) {
254 ($name, $base_type, $ext) = ($line =~ /\t*param\s*(\w*)\s*(\w*) (.*)/);
256 unless (defined($name)) {
258 die "Broken spec file line $line in function $funcname\n";
261 if ($ext =~ /array/) {
264 } elsif ($ext =~ /value/) {
265 # And this a 'normal' value
269 die "Unsupported type : $line in function $funcname\n";
271 # Get the 'real' type and append a '*' in case of a pointer
272 $type = $pseudo_to_opengl{$base_type};
273 unless (defined($type)) {
275 die "Unsupported return type in function $funcname for type $base_type (line $line)\n";
281 $arg_types{$name} = $type;
285 # Now, build the argument reference
287 for ($i = 0; $i <= $#arg_names; $i++) {
288 unless (defined($arg_types{$arg_names[$i]})) {
289 print "@arg_names\n";
290 foreach (sort keys %arg_types) {
291 print "$_ => $arg_types{$_}\n";
293 die "Undefined type for $arg_names[$i] in function $funcname\n";
296 push @
$arg_ref, [ $arg_types{$arg_names[$i]}, $arg_names[$i] ];
298 $func_ref = [ "gl" . $funcname,
302 # Now, put in one or the other hash table
303 if ($norm_categories{$category}) {
304 $norm_functions{$funcname} = $func_ref;
306 $ext_functions{$funcname} = $func_ref;
312 # Clean up the input files
318 # Now, generate the output files. First, the spec file.
320 open(SPEC
, ">" . $spec_file);
328 @ stdcall wglCreateContext(long) wglCreateContext
329 @ stdcall wglCreateLayerContext(long long) wglCreateLayerContext
330 @ stdcall wglCopyContext(long long long) wglCopyContext
331 @ stdcall wglDeleteContext(long) wglDeleteContext
332 @ stdcall wglDescribeLayerPlane(long long long long ptr) wglDescribeLayerPlane
333 @ stdcall wglGetCurrentContext() wglGetCurrentContext
334 @ stdcall wglGetCurrentDC() wglGetCurrentDC
335 @ stdcall wglGetLayerPaletteEntries(long long long long ptr) wglGetLayerPaletteEntries
336 @ stdcall wglGetProcAddress(str) wglGetProcAddress
337 @ stdcall wglMakeCurrent(long long) wglMakeCurrent
338 @ stdcall wglRealizeLayerPalette(long long long) wglRealizeLayerPalette
339 @ stdcall wglSetLayerPaletteEntries(long long long long ptr) wglSetLayerPaletteEntries
340 @ stdcall wglShareLists(long long) wglShareLists
341 @ stdcall wglSwapLayerBuffers(long long) wglSwapLayerBuffers
342 @ stdcall wglUseFontBitmapsA(long long long long) wglUseFontBitmapsA
343 @ stdcall wglUseFontOutlinesA(long long long long long long long ptr) wglUseFontOutlinesA
344 @ stub glGetLevelParameterfv
345 @ stub glGetLevelParameteriv
346 @ stub wglUseFontBitmapsW
347 @ stub wglUseFontOutlinesW
348 @ forward wglChoosePixelFormat GDI32.ChoosePixelFormat
349 @ forward wglDescribePixelFormat GDI32.DescribePixelFormat
350 @ forward wglGetPixelFormat GDI32.GetPixelFormat
351 @ forward wglSetPixelFormat GDI32.SetPixelFormat
352 @ forward wglSwapBuffers GDI32.SwapBuffers
355 foreach (sort keys %norm_functions) {
356 $func_name = $norm_functions{$_}->[0];
357 print SPEC
"@ stdcall $func_name( ";
358 for ($i = 0; $i <= $#{@{$norm_functions{$_}->[2]}}; $i++) {
359 $type = $norm_functions{$_}->[2]->[$i]->[0];
362 } elsif (defined($arg_conv{$type})) {
363 print SPEC
"$@$arg_conv{$type}[0] ";
365 die "No convertion for GL type $type...\n";
368 print SPEC
") wine_$func_name\n";
373 # After the spec file, the opengl_norm.c file
375 open(NORM
, ">" . $norm_file);
377 /* Auto-generated file... Do not edit ! */
379 #include \"config.h\"
380 #include \"wine_gl.h\"
382 typedef const GLubyte * GLstring;
385 foreach (sort keys %norm_functions) {
386 $string = GenerateThunk
($norm_functions{$_}, 1, "", $gen_thread_safe);
388 print NORM
"$string\n";
393 # Finally, more complex, the opengl_ext.c file
395 open(EXT
, ">" . $ext_file);
397 /* Auto-generated file... Do not edit ! */
399 #include \"config.h\"
400 #include \"wine_gl.h\"
402 typedef const GLubyte * GLstring;
404 #include \"opengl_ext.h\"
408 # First, generate the function pointers
409 foreach (sort keys %ext_functions) {
410 $func_ref = $ext_functions{$_};
411 print EXT
$func_ref->[1] . " (*" . $ext_prefix . $func_ref->[0] . ")( ";
412 for ($i = 0; $i <= $#{@{$func_ref->[2]}}; $i++) {
413 $type = $func_ref->[2]->[$i]->[0];
415 if ($i != $#{@{$func_ref->[2]}}) {
421 print EXT
") = (void *) 0xdeadbeef;\n";
424 # Then, the function prototypes
425 print EXT
"\n\n/* The function prototypes */\n";
426 foreach (sort keys %ext_functions) {
427 $func_ref = $ext_functions{$_};
428 print EXT
$func_ref->[1] . " WINAPI " . "wine_" . $func_ref->[0] . "( ";
429 for ($i = 0; $i <= $#{@{$func_ref->[2]}}; $i++) {
430 $type = $func_ref->[2]->[$i]->[0];
432 if ($i != $#{@{$func_ref->[2]}}) {
441 # Then the table giving the string <-> function correspondance */
442 print EXT
"\n\n/* The table giving the correspondance between names and functions */\n";
443 @tmp = keys %ext_functions;
444 print EXT
"int extension_registry_size = " . ($#tmp + 1) . ";\n";
445 print EXT
"OpenGL_extension extension_registry[" . ($#tmp + 1) . "] = {\n";
447 foreach (sort keys %ext_functions) {
448 $func_ref = $ext_functions{$_};
449 print EXT
" { \"" . $func_ref->[0] . "\", (void *) wine_" . $func_ref->[0] . ", (void **) (&" . $ext_prefix . $func_ref->[0] . ") }";
458 # And, finally, the thunks themselves....
459 print EXT
"\n/* The thunks themselves....*/\n";
460 foreach (sort keys %ext_functions) {
461 $string = GenerateThunk
($ext_functions{$_}, 0, $ext_prefix, $gen_thread_safe);
463 print EXT
"$string\n";