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.
11 # You can find them on the web at the following URL :
12 # http://oss.sgi.com/cgi-bin/cvsweb.cgi/projects/ogl-sample/main/doc/registry/specs/
14 # - opengl_version is the OpenGL version emulated by the library
15 # (can be 1.0 to 1.2).
17 # This script generates the three following files :
19 # - opengl32.spec : the spec file giving all the exported functions
20 # of the OpenGL32.DLL library. These functions are the one an
21 # application can directly link to (and are all the functions
22 # defined in the OpenGL core for the version defined by
25 # - opengl_norm.c : this file contains the thunks for all OpenGL
26 # functions that are defined in 'opengl32.spec'. The corresponding
27 # functions NEED to be defined in Linux's libGL or the library
28 # won't be able to be linked in.
30 # - opengl_ext.c : in this file are stored thunks for ALL possible
31 # OpenGL extensions (at least, all the extensions that are defined
32 # in the OpenGL extension registry). Contrary to 'opengl_norm.c',
33 # you do not need to have these extensions in your libGL to have
34 # OpenGL work (as they are resolved at run-time using
35 # glXGetProcAddressARB).
41 $spec_file = "opengl32.spec";
42 $norm_file = "opengl_norm.c";
43 $ext_file = "opengl_ext.c";
45 # Set to 0 for removing the ENTER / LEAVE GL calls
47 # Prefix used for the local variables
48 $ext_prefix = "func_";
49 # If set to 1, generate TRACEs for each OpenGL function
53 # List of categories to put in the 'opengl_norm.c' file
55 %cat_1_0 = ( "display-list" => 1,
57 "drawing-control" => 1,
66 %cat_1_1 = ( %cat_1_0,
68 %cat_1_2 = ( %cat_1_1,
70 "ARB_multitexture" => 1 );
72 %norm_categories = ();
75 # This hash table gives the conversion between OpenGL types and what
76 # is used by the TRACE printfs
79 ("GLbitfield" => "%d",
95 "_GLfuncptr" => "%p");
98 # This hash table gives the conversion between OpenGL types and what
99 # is used in the .spec file
102 ("GLbitfield" => [ "long", 4 ],
103 "GLboolean" => [ "long", 4 ],
104 "GLbyte" => [ "long", 4 ],
105 "GLclampd" => [ "double", 8 ],
106 "GLclampf" => [ "long", 4 ],
107 "GLdouble" => [ "double", 8 ],
108 "GLenum" => [ "long", 4 ],
109 "GLfloat" => [ "long", 4 ],
110 "GLint" => [ "long", 4 ],
111 "GLshort" => [ "long", 4 ],
112 "GLsizei" => [ "long", 4 ],
113 "GLstring" => [ "str", 4 ],
114 "GLubyte" => [ "long", 4 ],
115 "GLuint" => [ "long", 4 ],
116 "GLushort" => [ "long", 4 ],
117 "GLvoid" => [ "void", 4 ],
118 "_GLfuncptr" => [ "ptr", 4 ]);
121 # This functions generates the thunk for a given function.
124 my ($func_ref, $comment, $prefix, $thread_safe) = @_;
126 my ($call_arg) = ("");
127 my ($trace_arg) = ("");
129 # If for opengl_norm.c, generate a nice heading otherwise Patrik won't be happy :-)
131 $ret = $ret . "/***********************************************************************\n";
132 $ret = $ret . " * " . $func_ref->[0] . "\n";
133 $ret = $ret . " */\n";
135 $ret = $ret . $func_ref->[1] . " WINAPI wine_" . $func_ref->[0] . "( ";
136 for ($i = 0; $i <= $#{@{$func_ref->[2]}}; $i++) {
137 $type = $func_ref->[2]->[$i]->[0];
138 $name = $func_ref->[2]->[$i]->[1];
139 $ret = $ret . "$type $name";
140 $call_arg = $call_arg . "$name";
142 $trace_arg = $trace_arg . "%p";
144 $trace_arg = $trace_arg . $debug_conv{$type};
146 if ($i != $#{@{$func_ref->[2]}}) {
148 $call_arg = $call_arg . ", ";
149 $trace_arg = $trace_arg . ", ";
152 $call_arg = $call_arg . " ";
155 $ret = $ret . ") {\n";
156 if ($func_ref->[1] ne "void") {
157 $ret = $ret . " " . $func_ref->[1] . " ret_value;\n";
160 $ret = $ret . " TRACE(\"(" . $trace_arg . ")\\n\"";
161 if ($trace_arg ne "") {
162 $ret = $ret . ", " . $call_arg;
164 $ret = $ret . ");\n";
167 $ret = $ret . " ENTER_GL();\n";
170 if ($func_ref->[1] ne "void") {
171 $ret = $ret . "ret_value = ";
173 $ret = $ret . $prefix . $func_ref->[0] . "( " . $call_arg . ");\n";
175 $ret = $ret . " LEAVE_GL();\n";
177 if ($func_ref->[1] ne "void") {
178 $ret = $ret . " return ret_value;\n"
182 # Return this string....
187 # Extract and checks the number of arguments
190 die "Usage : make_opengl OpenGL_registry_location OpenGL_version.\n";
192 $registry_path = shift @ARGV;
193 $version = shift @ARGV;
194 if ($version eq "1.0") {
195 %norm_categories = %cat_1_0;
196 } elsif ($version eq "1.1") {
197 %norm_categories = %cat_1_1;
198 } elsif ($version eq "1.2") {
199 %norm_categories = %cat_1_2;
201 die "OpenGL version incorrect. Should be one of '1.0', '1.1' or '1.2'.\n";
205 # Open the registry files
207 open(TYPES, $registry_path . "/gl.tm") || die "Could not open 'gl.tm'. Please check your path the the registry files.\n";
208 open(REGISTRY, $registry_path . "/gl.spec") || die "Could not open 'gl.spec'. Please check your path the the registry files.\n";
211 # First, create a mapping between the pseudo types used in the spec file
212 # and OpenGL types using the 'gl.tm' file.
214 %pseudo_to_opengl = ();
215 while ($line = <TYPES>) {
216 ($pseudo, $opengl) = ($line =~ /(\w*),\*,\*,\s*(.*),\*,\*/);
217 $pseudo_to_opengl{$pseudo} = $opengl;
219 # This is to override the 'void' -> '*' bogus conversion
220 $pseudo_to_opengl{"void"} = "void";
221 # This is a bug in the spec file...
222 $pseudo_to_opengl{"FfdTargetSGIX"} = "GLint";
223 $pseudo_to_opengl{"FfdMaskSGIX"} = "GLint";
224 $pseudo_to_opengl{"IglooFunctionSelectSGIX"} = "GLint";
225 $pseudo_to_opengl{"IglooParameterSGIX"} = "GLint";
228 # Then, create the list of all OpenGL functions using the 'gl.spec'
229 # file. This will create two hash-tables, one with all the function
230 # whose category matches the one listed in '@norm_categories', the other
231 # with all other functions.
233 # An element of the hash table is a reference to an array with these
240 # - reference to an array giving the list of arguments (an empty array
241 # for a 'void' function).
243 # The list of arguments is itself an array of reference to arrays. Each
244 # of these arrays represents the argument type and the argument name.
248 # void glBitmap( GLsizei width, GLsizei height,
249 # GLfloat xorig, GLfloat yorig,
250 # GLfloat xmove, GLfloat ymove,
251 # const GLubyte *bitmap );
253 # Would give something like that :
257 # [ [ "GLsizei", "width" ],
258 # [ "GLsizei", "height" ],
259 # [ "GLfloat", "xorig" ],
260 # [ "GLfloat", "yorig" ],
261 # [ "GLfloat", "xmove" ],
262 # [ "GLfloat", "ymove" ],
263 # [ "GLubyte *", "bitmap"] ] ];
265 %norm_functions = ();
268 while ($line = <REGISTRY>) {
269 if ($line =~ /^\w*\(.*\)/) {
270 # Get the function name (NOTE: the 'gl' prefix needs to be added later)
271 ($funcname, $args) = ($line =~ /^(\w*)\((.*)\)/);
272 # and the argument names
273 @arg_names = split /\s*,\s*/, $args;
277 # - the argument types
278 # - the category the function belongs
284 unless (defined($line)) {
286 } elsif ($line =~ /^\s*$/) {
287 if (($category eq "") || ($ret_type eq "")) {
288 die "Missing 'category' line in function $funcname.\n";
291 } elsif ($line =~ /\t*return\t*(\w*)/) {
292 ($ret_type) = ($line =~ /\t*return\s*(\w*)/);
293 $ret_type = $pseudo_to_opengl{$ret_type};
294 unless (defined($ret_type)) {
295 die "Unsupported return type in function $funcname\n";
297 } elsif ($line =~ /^\t*category/) {
298 ($category) = ($line =~ /^\t*category\s*([\w-]*)/);
299 } elsif ($line =~ /^\t*param/) {
300 ($name, $base_type, $ext) = ($line =~ /\t*param\s*(\w*)\s*(\w*) (.*)/);
302 unless (defined($name)) {
304 die "Broken spec file line $line in function $funcname\n";
307 if ($ext =~ /array/) {
310 } elsif ($ext =~ /value/) {
311 # And this a 'normal' value
315 die "Unsupported type : $line in function $funcname\n";
317 # Get the 'real' type and append a '*' in case of a pointer
318 $type = $pseudo_to_opengl{$base_type};
319 unless (defined($type)) {
321 die "Unsupported return type in function $funcname for type $base_type (line $line)\n";
327 $arg_types{$name} = $type;
331 # Now, build the argument reference
333 for ($i = 0; $i <= $#arg_names; $i++) {
334 unless (defined($arg_types{$arg_names[$i]})) {
335 print "@arg_names\n";
336 foreach (sort keys %arg_types) {
337 print "$_ => $arg_types{$_}\n";
339 die "Undefined type for $arg_names[$i] in function $funcname\n";
342 push @$arg_ref, [ $arg_types{$arg_names[$i]}, $arg_names[$i] ];
344 $func_ref = [ "gl" . $funcname,
348 # Now, put in one or the other hash table
349 if ($norm_categories{$category}) {
350 $norm_functions{$funcname} = $func_ref;
352 $ext_functions{$funcname} = $func_ref;
358 # Clean up the input files
364 # Now, generate the output files. First, the spec file.
366 open(SPEC, ">" . $spec_file);
376 debug_channels (opengl)
378 @ stdcall wglCreateContext(long) wglCreateContext
379 @ stdcall wglCreateLayerContext(long long) wglCreateLayerContext
380 @ stdcall wglCopyContext(long long long) wglCopyContext
381 @ stdcall wglDeleteContext(long) wglDeleteContext
382 @ stdcall wglDescribeLayerPlane(long long long long ptr) wglDescribeLayerPlane
383 @ stdcall wglGetCurrentContext() wglGetCurrentContext
384 @ stdcall wglGetCurrentDC() wglGetCurrentDC
385 @ stdcall wglGetLayerPaletteEntries(long long long long ptr) wglGetLayerPaletteEntries
386 @ stdcall wglGetProcAddress(str) wglGetProcAddress
387 @ stdcall wglMakeCurrent(long long) wglMakeCurrent
388 @ stdcall wglRealizeLayerPalette(long long long) wglRealizeLayerPalette
389 @ stdcall wglSetLayerPaletteEntries(long long long long ptr) wglSetLayerPaletteEntries
390 @ stdcall wglShareLists(long long) wglShareLists
391 @ stdcall wglSwapLayerBuffers(long long) wglSwapLayerBuffers
392 @ stdcall wglUseFontBitmapsA(long long long long) wglUseFontBitmapsA
393 @ stdcall wglUseFontOutlinesA(long long long long long long long ptr) wglUseFontOutlinesA
394 @ stub glGetLevelParameterfv
395 @ stub glGetLevelParameteriv
396 @ stub wglUseFontBitmapsW
397 @ stub wglUseFontOutlinesW
398 @ forward wglChoosePixelFormat GDI32.ChoosePixelFormat
399 @ forward wglDescribePixelFormat GDI32.DescribePixelFormat
400 @ forward wglGetPixelFormat GDI32.GetPixelFormat
401 @ forward wglSetPixelFormat GDI32.SetPixelFormat
402 @ forward wglSwapBuffers GDI32.SwapBuffers
405 foreach (sort keys %norm_functions) {
406 $func_name = $norm_functions{$_}->[0];
407 print SPEC "@ stdcall $func_name( ";
408 for ($i = 0; $i <= $#{@{$norm_functions{$_}->[2]}}; $i++) {
409 $type = $norm_functions{$_}->[2]->[$i]->[0];
412 } elsif (defined($arg_conv{$type})) {
413 print SPEC "$@$arg_conv{$type}[0] ";
415 die "No convertion for GL type $type...\n";
418 print SPEC ") wine_$func_name\n";
423 # After the spec file, the opengl_norm.c file
425 open(NORM, ">" . $norm_file);
427 /* Auto-generated file... Do not edit ! */
429 #include \"config.h\"
430 #include \"wine_gl.h\"
431 #include \"debugtools.h\"
433 typedef const GLubyte * GLstring;
435 DEFAULT_DEBUG_CHANNEL(opengl);
438 foreach (sort keys %norm_functions) {
439 $string = GenerateThunk($norm_functions{$_}, 1, "", $gen_thread_safe);
441 print NORM "$string\n";
446 # Finally, more complex, the opengl_ext.c file
448 open(EXT, ">" . $ext_file);
450 /* Auto-generated file... Do not edit ! */
452 #include \"config.h\"
453 #include \"wine_gl.h\"
454 #include \"debugtools.h\"
456 typedef const GLubyte * GLstring;
458 #include \"opengl_ext.h\"
460 DEFAULT_DEBUG_CHANNEL(opengl);
464 # First, generate the function pointers
465 foreach (sort keys %ext_functions) {
466 $func_ref = $ext_functions{$_};
467 print EXT $func_ref->[1] . " (*" . $ext_prefix . $func_ref->[0] . ")( ";
468 for ($i = 0; $i <= $#{@{$func_ref->[2]}}; $i++) {
469 $type = $func_ref->[2]->[$i]->[0];
471 if ($i != $#{@{$func_ref->[2]}}) {
477 print EXT ") = (void *) 0xdeadbeef;\n";
480 # Then, the function prototypes
481 print EXT "\n\n/* The function prototypes */\n";
482 foreach (sort keys %ext_functions) {
483 $func_ref = $ext_functions{$_};
484 print EXT $func_ref->[1] . " WINAPI " . "wine_" . $func_ref->[0] . "( ";
485 for ($i = 0; $i <= $#{@{$func_ref->[2]}}; $i++) {
486 $type = $func_ref->[2]->[$i]->[0];
488 if ($i != $#{@{$func_ref->[2]}}) {
497 # Then the table giving the string <-> function correspondance */
498 print EXT "\n\n/* The table giving the correspondance between names and functions */\n";
499 @tmp = keys %ext_functions;
500 print EXT "int extension_registry_size = " . ($#tmp + 1) . ";\n";
501 print EXT "OpenGL_extension extension_registry[" . ($#tmp + 1) . "] = {\n";
503 foreach (sort keys %ext_functions) {
504 $func_ref = $ext_functions{$_};
505 print EXT " { \"" . $func_ref->[0] . "\", (void *) wine_" . $func_ref->[0] . ", (void **) (&" . $ext_prefix . $func_ref->[0] . ") }";
514 # And, finally, the thunks themselves....
515 print EXT "\n/* The thunks themselves....*/\n";
516 foreach (sort keys %ext_functions) {
517 $string = GenerateThunk($ext_functions{$_}, 0, $ext_prefix, $gen_thread_safe);
519 print EXT "$string\n";