Fixed first seek on MEM mmio files.
[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 #
12 #     - opengl_version is the OpenGL version emulated by the library
13 #       (can be 1.0 to 1.2).
14 #
15 # This script generates the three following files :
16 #
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
21 #       'opengl_version').
22 #
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.
27 #
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).
34 #
35
36 #
37 # This functions generates the thunk for a given function.
38 #
39 sub GenerateThunk {
40     my ($func_ref, $comment, $prefix, $thread_safe) = @_;
41     my ($ret) = ("");
42     my ($call_arg) = ("");
43
44     # If for opengl_norm.c, generate a nice heading otherwise Patrik won't be happy :-)
45     if ($comment eq 1) {
46         $ret = $ret . "/***********************************************************************\n";
47         $ret = $ret . " *              " . $func_ref->[0] . "\n";
48         $ret = $ret . " */\n";
49     }
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]}}) {
57             $ret = $ret . ", ";
58             $call_arg = $call_arg . ", ";
59         } else {
60             $ret = $ret . " ";
61             $call_arg = $call_arg . " ";
62         }
63     }
64     $ret = $ret . ") {\n";
65     if ($func_ref->[1] ne "void") {
66         $ret = $ret . "  " . $func_ref->[1] . " ret_value;\n";
67     }
68     if ($thread_safe) {
69         $ret = $ret . "  ENTER_GL();\n";
70     }
71     $ret = $ret . "  ";
72     if ($func_ref->[1] ne "void") {
73         $ret = $ret . "ret_value = ";
74     }
75     $ret = $ret . $prefix . $func_ref->[0] . "( " . $call_arg . ");\n";
76     if ($thread_safe) {
77         $ret = $ret . "  LEAVE_GL();\n";
78     }
79     if ($func_ref->[1] ne "void") {
80         $ret = $ret . "  return ret_value;\n"
81     }
82     $ret = $ret . "}\n";
83
84     # Return this string....
85     $ret;
86 }
87
88 #
89 # This hash table gives the conversion between OpenGL types and what
90 # is used in the .spec file
91 #
92 %arg_conv = 
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 ]);
110
111 #
112 # Files to generate
113 #
114 $spec_file = "opengl32.spec";
115 $norm_file = "opengl_norm.c";
116 $ext_file  = "opengl_ext.c";
117
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_";
122
123 #
124 # List of categories to put in the 'opengl_norm.c' file
125 #
126 %cat_1_0 = ( "display-list" => 1, 
127              "drawing" => 1, 
128              "drawing-control" => 1, 
129              "feedback" => 1, 
130              "framebuf" => 1, 
131              "misc" => 1, 
132              "modeling" => 1, 
133              "pixel-op" => 1, 
134              "pixel-rw" => 1, 
135              "state-req" => 1, 
136              "xform" => 1 );
137 %cat_1_1 = ( %cat_1_0, 
138              "1_1" => 1 );
139 %cat_1_2 = ( %cat_1_1, 
140              "VERSION_1_2" => 1, 
141              "ARB_multitexture" => 1 );
142
143 %norm_categories = ();
144
145 #
146 # Extract and checks the number of arguments
147 #
148 if ($#ARGV != 1) {
149     die "Usage : make_opengl OpenGL_registry_location OpenGL_version.\n";
150 }
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;
159 } else {
160     die "OpenGL version incorrect. Should be one of '1.0', '1.1' or '1.2'.\n";
161 }
162
163 #
164 # Open the registry files
165 #
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";
168
169 #
170 # First, create a mapping between the pseudo types used in the spec file
171 # and OpenGL types using the 'gl.tm' file.
172 #
173 %pseudo_to_opengl = ();
174 while ($line = <TYPES>) {
175     ($pseudo, $opengl) = ($line =~ /(\w*),\*,\*,\s*(.*),\*,\*/);
176     $pseudo_to_opengl{$pseudo} = $opengl;
177 }
178 # This is to override the 'void' -> '*' bogus conversion
179 $pseudo_to_opengl{"void"} = "void";
180
181 #
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.
186 #
187 # An element of the hash table is a reference to an array with these
188 # elements :
189 #
190 #  - function name
191 #
192 #  - return type
193 #
194 #  - reference to an array giving the list of arguments (an empty array
195 #    for a 'void' function).
196 #
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.
199 #
200 # An example :
201 #
202 # void glBitmap( GLsizei width, GLsizei height,
203 #                GLfloat xorig, GLfloat yorig,
204 #                GLfloat xmove, GLfloat ymove,
205 #                const GLubyte *bitmap );
206 #
207 # Would give something like that :
208 #
209 # [ "glBitmap",
210 #   "void",
211 #   [ [ "GLsizei", "width" ],
212 #     [ "GLsizei", "height" ],
213 #     [ "GLfloat", "xorig" ],
214 #     [ "GLfloat", "yorig" ],
215 #     [ "GLfloat", "xmove" ],
216 #     [ "GLfloat", "ymove" ],
217 #     [ "GLubyte *", "bitmap"] ] ];
218 #
219 %norm_functions = ();
220 %ext_functions  = ();
221
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;
228         
229         # After get :
230         #  - the return type
231         #  - the argument types
232         #  - the category the function belongs
233         %arg_types = ();
234         $category = "";
235         $ret_type = "";
236         while (1) {
237             $line = <REGISTRY>;
238             unless (defined($line)) {
239                 last;
240             } elsif ($line =~ /^\s*$/) {
241                 if (($category eq "") || ($ret_type eq "")) {
242                     die "Missing 'category' line in function $funcname.\n";
243                 }
244                 last;
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";
250                 }
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*) (.*)/);
255                 $ptr = 0;
256                 unless (defined($name)) { 
257                     chomp $line;
258                     die "Broken spec file line $line in function $funcname\n";
259                 }
260
261                 if ($ext =~ /array/) {
262                     # This is a pointer
263                     $ptr = 1;
264                 } elsif ($ext =~ /value/) {
265                     # And this a 'normal' value
266                     $ptr = 0;
267                 } else {
268                     chomp $line;
269                     die "Unsupported type : $line in function $funcname\n";
270                 }
271                 # Get the 'real' type and append a '*' in case of a pointer
272                 $type = $pseudo_to_opengl{$base_type};
273                 unless (defined($type)) {
274                     chomp $line;
275                     die "Unsupported return type in function $funcname for type $base_type (line $line)\n";
276                 }
277                 if ($ptr) {
278                     $type = $type . "*";
279                 }
280                 
281                 $arg_types{$name} = $type;
282             }
283         }
284
285         # Now, build the argument reference
286         $arg_ref = [ ];
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";
292                 }
293                 die "Undefined type for $arg_names[$i] in function $funcname\n";
294             }
295             
296             push @$arg_ref, [ $arg_types{$arg_names[$i]}, $arg_names[$i] ];
297         }
298         $func_ref = [ "gl" . $funcname, 
299                       $ret_type,
300                       $arg_ref ];
301         
302         # Now, put in one or the other hash table
303         if ($norm_categories{$category}) {
304             $norm_functions{$funcname} = $func_ref;
305         } else {
306             $ext_functions{$funcname} = $func_ref;
307         }
308     }
309 }
310
311 #
312 # Clean up the input files
313 #
314 close(TYPES);
315 close(REGISTRY);
316
317 #
318 # Now, generate the output files. First, the spec file.
319 #
320 open(SPEC, ">" . $spec_file);
321
322 print SPEC "
323 name opengl32
324 type win32
325 init OpenGL32_Init
326 import x11drv
327
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
353 ";
354
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];
360         if ($type =~ /\*/) {
361             print SPEC "ptr ";
362         } elsif (defined($arg_conv{$type})) {
363             print SPEC "$@$arg_conv{$type}[0] ";
364         } else {
365             die "No convertion for GL type $type...\n";
366         }
367     }
368     print SPEC ") wine_$func_name\n";
369 }
370 close(SPEC);
371
372 #
373 # After the spec file, the opengl_norm.c file
374 #
375 open(NORM, ">" . $norm_file);
376 print NORM "
377 /* Auto-generated file... Do not edit ! */
378
379 #include \"config.h\"
380 #include \"wine_gl.h\"
381
382 typedef const GLubyte * GLstring;
383
384 ";
385 foreach (sort keys %norm_functions) {
386     $string = GenerateThunk($norm_functions{$_}, 1, "", $gen_thread_safe);
387
388     print NORM "$string\n";
389 }
390 close(NORM);
391
392 #
393 # Finally, more complex, the opengl_ext.c file
394 #
395 open(EXT, ">" . $ext_file);
396 print EXT "
397 /* Auto-generated file... Do not edit ! */
398
399 #include \"config.h\"
400 #include \"wine_gl.h\"
401
402 typedef const GLubyte * GLstring;
403
404 #include \"opengl_ext.h\"
405
406 ";
407
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];
414         print EXT "$type";
415         if ($i != $#{@{$func_ref->[2]}}) {
416             print EXT ", ";
417         } else {
418             print EXT " ";
419         }
420     }
421     print EXT ") = (void *) 0xdeadbeef;\n";
422 }
423
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];
431         print EXT "$type";
432         if ($i != $#{@{$func_ref->[2]}}) {
433             print EXT ", ";
434         } else {
435             print EXT " ";
436         }
437     }
438     print EXT ");\n";
439 }
440
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";
446 $i = 0;
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] . ") }";
450     if ($i != $#tmp) {
451         print EXT ",";
452     }
453     $i++;
454     print EXT "\n";
455 }
456 print EXT "};\n";
457
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);
462
463     print EXT "$string\n";
464 }
465 close(EXT);