Reimplemented DXGrab with improvements; it no longer depends on
[wine] / dlls / opengl32 / make_opengl
1 #!/usr/bin/perl -w
2
3 # This script is called thus :
4 #
5 #   make_opengl path_to_spec_file opengl_version
6 #
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/
13 #
14 #     - opengl_version is the OpenGL version emulated by the library
15 #       (can be 1.0 to 1.2).
16 #
17 # This script generates the three following files :
18 #
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
23 #       'opengl_version').
24 #
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.
29 #
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).
36 #
37
38 #
39 # Files to generate
40 #
41 $spec_file = "opengl32.spec";
42 $norm_file = "opengl_norm.c";
43 $ext_file  = "opengl_ext.c";
44
45 # Set to 0 for removing the ENTER / LEAVE GL calls
46 $gen_thread_safe = 1;
47 # Prefix used for the local variables
48 $ext_prefix = "func_";
49 # If set to 1, generate TRACEs for each OpenGL function
50 $gen_traces = 1;
51
52 #
53 # List of categories to put in the 'opengl_norm.c' file
54 #
55 %cat_1_0 = ( "display-list" => 1, 
56              "drawing" => 1, 
57              "drawing-control" => 1, 
58              "feedback" => 1, 
59              "framebuf" => 1, 
60              "misc" => 1, 
61              "modeling" => 1, 
62              "pixel-op" => 1, 
63              "pixel-rw" => 1, 
64              "state-req" => 1, 
65              "xform" => 1 );
66 %cat_1_1 = ( %cat_1_0, 
67              "1_1" => 1 );
68 %cat_1_2 = ( %cat_1_1, 
69              "VERSION_1_2" => 1, 
70              "ARB_multitexture" => 1 );
71
72 %norm_categories = ();
73
74 #
75 # This hash table gives the conversion between OpenGL types and what
76 # is used by the TRACE printfs
77 #
78 %debug_conv = 
79     ("GLbitfield" => "%d",
80      "GLboolean" => "%d",
81      "GLbyte" => "%d",
82      "GLclampd" => "%f",
83      "GLclampf" => "%f",
84      "GLdouble" => "%f",
85      "GLenum" => "%d",
86      "GLfloat" => "%f",
87      "GLint" => "%d",
88      "GLshort" => "%d",
89      "GLsizei" => "%d",
90      "GLstring" => "%s",
91      "GLubyte" => "%d",
92      "GLuint" => "%d",
93      "GLushort" => "%d",
94      "GLvoid" => "(void)",
95      "_GLfuncptr" => "%p");
96
97 #
98 # This hash table gives the conversion between OpenGL types and what
99 # is used in the .spec file
100 #
101 %arg_conv = 
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 ]);
119
120 #
121 # This functions generates the thunk for a given function.
122 #
123 sub GenerateThunk {
124     my ($func_ref, $comment, $prefix, $thread_safe) = @_;
125     my ($ret) = ("");
126     my ($call_arg) = ("");
127     my ($trace_arg) = ("");
128
129     # If for opengl_norm.c, generate a nice heading otherwise Patrik won't be happy :-)
130     if ($comment eq 1) {
131         $ret = $ret . "/***********************************************************************\n";
132         $ret = $ret . " *              " . $func_ref->[0] . "\n";
133         $ret = $ret . " */\n";
134     }
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";
141         if ($type =~ /\*/) {
142             $trace_arg = $trace_arg . "%p";
143         } else {
144             $trace_arg = $trace_arg . $debug_conv{$type};
145         }
146         if ($i != $#{@{$func_ref->[2]}}) {
147             $ret = $ret . ", ";
148             $call_arg = $call_arg . ", ";
149             $trace_arg = $trace_arg . ", ";
150         } else {
151             $ret = $ret . " ";
152             $call_arg = $call_arg . " ";
153         }
154     }
155     $ret = $ret . ") {\n";
156     if ($func_ref->[1] ne "void") {
157         $ret = $ret . "  " . $func_ref->[1] . " ret_value;\n";
158     }
159     if ($gen_traces) {
160         $ret = $ret . "  TRACE(\"(" . $trace_arg . ")\\n\"";
161         if ($trace_arg ne "") {
162             $ret = $ret . ", " . $call_arg;
163         }
164         $ret = $ret . ");\n";
165     }
166     if ($thread_safe) {
167         $ret = $ret . "  ENTER_GL();\n";
168     }
169     $ret = $ret . "  ";
170     if ($func_ref->[1] ne "void") {
171         $ret = $ret . "ret_value = ";
172     }
173     $ret = $ret . $prefix . $func_ref->[0] . "( " . $call_arg . ");\n";
174     if ($thread_safe) {
175         $ret = $ret . "  LEAVE_GL();\n";
176     }
177     if ($func_ref->[1] ne "void") {
178         $ret = $ret . "  return ret_value;\n"
179     }
180     $ret = $ret . "}\n";
181
182     # Return this string....
183     $ret;
184 }
185
186 #
187 # Extract and checks the number of arguments
188 #
189 if ($#ARGV != 1) {
190     die "Usage : make_opengl OpenGL_registry_location OpenGL_version.\n";
191 }
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;
200 } else {
201     die "OpenGL version incorrect. Should be one of '1.0', '1.1' or '1.2'.\n";
202 }
203
204 #
205 # Open the registry files
206 #
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";
209
210 #
211 # First, create a mapping between the pseudo types used in the spec file
212 # and OpenGL types using the 'gl.tm' file.
213 #
214 %pseudo_to_opengl = ();
215 while ($line = <TYPES>) {
216     ($pseudo, $opengl) = ($line =~ /(\w*),\*,\*,\s*(.*),\*,\*/);
217     $pseudo_to_opengl{$pseudo} = $opengl;
218 }
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";
226
227 #
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.
232 #
233 # An element of the hash table is a reference to an array with these
234 # elements :
235 #
236 #  - function name
237 #
238 #  - return type
239 #
240 #  - reference to an array giving the list of arguments (an empty array
241 #    for a 'void' function).
242 #
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.
245 #
246 # An example :
247 #
248 # void glBitmap( GLsizei width, GLsizei height,
249 #                GLfloat xorig, GLfloat yorig,
250 #                GLfloat xmove, GLfloat ymove,
251 #                const GLubyte *bitmap );
252 #
253 # Would give something like that :
254 #
255 # [ "glBitmap",
256 #   "void",
257 #   [ [ "GLsizei", "width" ],
258 #     [ "GLsizei", "height" ],
259 #     [ "GLfloat", "xorig" ],
260 #     [ "GLfloat", "yorig" ],
261 #     [ "GLfloat", "xmove" ],
262 #     [ "GLfloat", "ymove" ],
263 #     [ "GLubyte *", "bitmap"] ] ];
264 #
265 %norm_functions = ();
266 %ext_functions  = ();
267
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;
274         
275         # After get :
276         #  - the return type
277         #  - the argument types
278         #  - the category the function belongs
279         %arg_types = ();
280         $category = "";
281         $ret_type = "";
282         while (1) {
283             $line = <REGISTRY>;
284             unless (defined($line)) {
285                 last;
286             } elsif ($line =~ /^\s*$/) {
287                 if (($category eq "") || ($ret_type eq "")) {
288                     die "Missing 'category' line in function $funcname.\n";
289                 }
290                 last;
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";
296                 }
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*) (.*)/);
301                 $ptr = 0;
302                 unless (defined($name)) { 
303                     chomp $line;
304                     die "Broken spec file line $line in function $funcname\n";
305                 }
306
307                 if ($ext =~ /array/) {
308                     # This is a pointer
309                     $ptr = 1;
310                 } elsif ($ext =~ /value/) {
311                     # And this a 'normal' value
312                     $ptr = 0;
313                 } else {
314                     chomp $line;
315                     die "Unsupported type : $line in function $funcname\n";
316                 }
317                 # Get the 'real' type and append a '*' in case of a pointer
318                 $type = $pseudo_to_opengl{$base_type};
319                 unless (defined($type)) {
320                     chomp $line;
321                     die "Unsupported return type in function $funcname for type $base_type (line $line)\n";
322                 }
323                 if ($ptr) {
324                     $type = $type . "*";
325                 }
326                 
327                 $arg_types{$name} = $type;
328             }
329         }
330
331         # Now, build the argument reference
332         $arg_ref = [ ];
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";
338                 }
339                 die "Undefined type for $arg_names[$i] in function $funcname\n";
340             }
341             
342             push @$arg_ref, [ $arg_types{$arg_names[$i]}, $arg_names[$i] ];
343         }
344         $func_ref = [ "gl" . $funcname, 
345                       $ret_type,
346                       $arg_ref ];
347         
348         # Now, put in one or the other hash table
349         if ($norm_categories{$category}) {
350             $norm_functions{$funcname} = $func_ref;
351         } else {
352             $ext_functions{$funcname} = $func_ref;
353         }
354     }
355 }
356
357 #
358 # Clean up the input files
359 #
360 close(TYPES);
361 close(REGISTRY);
362
363 #
364 # Now, generate the output files. First, the spec file.
365 #
366 open(SPEC, ">" . $spec_file);
367
368 print SPEC "
369 name opengl32
370 type win32
371
372 init OpenGL32_Init
373 import x11drv
374 import kernel32
375
376 debug_channels (opengl)
377
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
403 ";
404
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];
410         if ($type =~ /\*/) {
411             print SPEC "ptr ";
412         } elsif (defined($arg_conv{$type})) {
413             print SPEC "$@$arg_conv{$type}[0] ";
414         } else {
415             die "No convertion for GL type $type...\n";
416         }
417     }
418     print SPEC ") wine_$func_name\n";
419 }
420 close(SPEC);
421
422 #
423 # After the spec file, the opengl_norm.c file
424 #
425 open(NORM, ">" . $norm_file);
426 print NORM "
427 /* Auto-generated file... Do not edit ! */
428
429 #include \"config.h\"
430 #include \"wine_gl.h\"
431 #include \"debugtools.h\"
432
433 typedef const GLubyte * GLstring;
434
435 DEFAULT_DEBUG_CHANNEL(opengl);
436
437 ";
438 foreach (sort keys %norm_functions) {
439     $string = GenerateThunk($norm_functions{$_}, 1, "", $gen_thread_safe);
440
441     print NORM "$string\n";
442 }
443 close(NORM);
444
445 #
446 # Finally, more complex, the opengl_ext.c file
447 #
448 open(EXT, ">" . $ext_file);
449 print EXT "
450 /* Auto-generated file... Do not edit ! */
451
452 #include \"config.h\"
453 #include \"wine_gl.h\"
454 #include \"debugtools.h\"
455
456 typedef const GLubyte * GLstring;
457
458 #include \"opengl_ext.h\"
459
460 DEFAULT_DEBUG_CHANNEL(opengl);
461
462 ";
463
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];
470         print EXT "$type";
471         if ($i != $#{@{$func_ref->[2]}}) {
472             print EXT ", ";
473         } else {
474             print EXT " ";
475         }
476     }
477     print EXT ") = (void *) 0xdeadbeef;\n";
478 }
479
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];
487         print EXT "$type";
488         if ($i != $#{@{$func_ref->[2]}}) {
489             print EXT ", ";
490         } else {
491             print EXT " ";
492         }
493     }
494     print EXT ");\n";
495 }
496
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";
502 $i = 0;
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] . ") }";
506     if ($i != $#tmp) {
507         print EXT ",";
508     }
509     $i++;
510     print EXT "\n";
511 }
512 print EXT "};\n";
513
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);
518
519     print EXT "$string\n";
520 }
521 close(EXT);