On Wed, 2008-05-28 at 22:54 +0200, Ron Blaschke wrote:
> Geoffrey Broadwell wrote:
> > OK, I know what's causing this (no typemap entry for 'wchar_t*', as the
> > error indicates).  Not sure about best NCI type type to match this to --
> > it really wants to be a native Parrot string with encoding UCS2, I
> > believe, but I don't know how to do that off the top of my head, and I
> > need to run now.
> > 
> > I'll ruminate on this later -- though if you wanted to try skipping over
> > it and see what else goes wrong later on, just put a typemap in
> > config/gen/opengl.pm for wchar_t => 'void', and it will just pretend
> > wchar_t* is a void buffer.
> 
> Workaround looks good.  Build is okay, F<examples/opengl/triangle.pir> 
> runs fine.


OK, attached is a new patch, incorporating both the path glob fix from
earlier today, and the wchar_t => 'void' workaround above.

This one looks like a commit candidate -- please test!


-'f

diff --git a/MANIFEST b/MANIFEST
index b0e3c9d..43c4f52 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -296,7 +296,6 @@ config/auto/warnings/test_c.in                              []
 config/gen/call_list.pm                                     []
 config/gen/call_list/core.in                                []
 config/gen/call_list/misc.in                                []
-config/gen/call_list/opengl.in                              []
 config/gen/config_h.pm                                      []
 config/gen/config_h/config_h.in                             []
 config/gen/config_h/feature_h.in                            []
diff --git a/MANIFEST.generated b/MANIFEST.generated
index 183fe20..ddfe4cf 100644
--- a/MANIFEST.generated
+++ b/MANIFEST.generated
@@ -20,6 +20,7 @@ compilers/tge/TGE/Tree.pbc                        [main]
 compilers/tge/tgc.pir                             [main]
 config/auto/cpu/i386/memcpy_mmx.c                 [main]
 config/auto/cpu/i386/memcpy_sse.c                 [main]
+config/gen/call_list/opengl.in                    [main]
 config/gen/platform/ansi/dl.c                     [main]
 config/gen/platform/ansi/time.c                   [main]
 config/gen/platform/darwin/memalign.c             [main]
@@ -228,6 +229,7 @@ runtime/parrot/library/Getopt/Obj.pbc             [main]
 runtime/parrot/library/MIME/Base64.pbc            [main]
 runtime/parrot/library/NCI/call_toolkit_init.pbc  [main]
 runtime/parrot/library/OpenGL.pbc                 [main]
+runtime/parrot/library/OpenGL_funcs.pir           [main]
 runtime/parrot/library/P6object.pbc               [main]
 runtime/parrot/library/Parrot/Capture_PIR.pbc     [main]
 runtime/parrot/library/Parrot/Coroutine.pbc       [main]
diff --git a/config/auto/opengl.pm b/config/auto/opengl.pm
index 6e69206..eb50b5c 100644
--- a/config/auto/opengl.pm
+++ b/config/auto/opengl.pm
@@ -1,17 +1,123 @@
 # Copyright (C) 2008, The Perl Foundation.
 # $Id $
 
+
 =head1 NAME
 
 config/auto/opengl.pm - Probe for OpenGL, GLU, and GLUT libraries
 
+
 =head1 DESCRIPTION
 
 Determines whether the platform supports OpenGL, GLU and GLUT.  The optimal
 result at this time is to find OpenGL 2.1, GLU 1.3, and GLUT API version 4.
 
+You will typically need to install the headers and libraries required for
+compiling OpenGL/GLU/GLUT applications as a separate step in addition to
+the base development tools for your platform.  The following sections detail
+the steps needed to add OpenGL support for each platform for which we have
+received this information -- details for additional platforms are welcome!
+
+
+=head2 Mac OS X
+
+You will need to install the F<OpenGL Framework> and the F<GLUT Framework>.
+With these in place, everything else should be autodetected.  Mac OS X uses
+a proprietary GLUT variant that supports more functions than standard
+GLUT 3.7, but fewer than F<freeglut>.
+
+
+=head2 Linux
+
+Linux distributions typically use F<freeglut>
+(L<http://freeglut.sourceforge.net/>) for GLUT support, and F<Mesa>
+(L<http://www.mesa3d.org/>) for GLU support.  Either the Mesa headers
+(for open source drivers) or the vendor headers (for closed source drivers)
+can be used for core OpenGL/GLX support.  Here are the package names for
+various distributions; installing each of these will typically pull in a
+number of prerequisites as well:
+
+
+=head3 Debian/Ubuntu/etc.
+
+=over 4
+
+=item GLUT
+
+F<freeglut3-dev>
+
+=item GLU
+
+F<libglu1-mesa-dev>
+
+=item OpenGL/GLX (open source drivers)
+
+F<libgl1-mesa-dev>
+
+=item OpenGL/GLX (NVIDIA drivers)
+
+F<nvidia-glx-dev>
+
+=back
+
+
+=head3 Fedora/RedHat/CentOS/etc.
+
+=over 4
+
+=item GLUT
+
+F<freeglut-devel>
+
+=item GLU
+
+F<mesa-libGLU-devel>
+
+=item OpenGL/GLX (open source drivers)
+
+F<mesa-libGL-devel>
+
+=item OpenGL/GLX (NVIDIA drivers)
+
+F<nvidia-devel> (?)
+
+=back
+
+
+=head2 Windows
+
+On Windows, Parrot supports three different compiler environments, each of
+which has different requirements for OpenGL support:
+
+
+=head3 MSVC
+
+=over 4
+
+=item OpenGL/GLU/WGL
+
+F<Windows SDK for Windows Server 2008 and .NET Framework 3.5>
+
+=item GLUT
+
+F<GLUT for Win32> (L<http://www.xmission.com/~nate/glut.html>)
+
+=back
+
+
+=head3 MinGW
+
+ XXXX: No details yet
+
+
+=head3 cygwin
+
+ XXXX: No details yet
+
+
 =cut
 
+
 package auto::opengl;
 
 use strict;
@@ -58,7 +164,7 @@ sub runstep {
         osname          => $osname,
         cc              => $cc,
         win32_gcc       => '-lglut32 -lglu32 -lopengl32',
-        win32_nongcc    => 'glut.lib glu.lib gl.lib',
+        win32_nongcc    => 'opengl32.lib glu32.lib glut32.lib',
         darwin          => '-framework OpenGL -framework GLUT',
         default         => '-lglut -lGLU -lGL',
     } );
diff --git a/config/gen/call_list/opengl.in b/config/gen/call_list/opengl.in
deleted file mode 100644
index 9c21dbf..0000000
--- a/config/gen/call_list/opengl.in
+++ /dev/null
@@ -1,7 +0,0 @@
-# Used by OpenGL (including GLU and GLUT)
-v    3p
-v    JP
-v    JPi
-v    JPii
-v    fff
-v    ffff
diff --git a/config/gen/makefiles/root.in b/config/gen/makefiles/root.in
index 4028b15..c456163 100644
--- a/config/gen/makefiles/root.in
+++ b/config/gen/makefiles/root.in
@@ -163,6 +163,7 @@ GEN_CONFIGS = \
     runtime/parrot/include/config.fpmc \
     $(SRC_DIR)/platform.c \
 #CONDITIONED_LINE(platform_asm):    $(SRC_DIR)/platform_asm.s \
+#CONDITIONED_LINE(has_opengl):    config/gen/call_list/opengl.in \
 #CONDITIONED_LINE(has_glut):    $(SRC_DIR)/glut_callbacks.c \
     $(SRC_DIR)/core_pmcs.c \
     CFLAGS \
@@ -180,6 +181,7 @@ GEN_CONFIGS = \
 GEN_PASM_INCLUDES = \
     runtime/parrot/include/signal.pasm \
 #CONDITIONED_LINE(has_opengl):    runtime/parrot/include/opengl_defines.pasm \
+#CONDITIONED_LINE(has_opengl):    runtime/parrot/library/OpenGL_funcs.pir \
     @TEMP_gen_pasm_includes@
 
 CONFIGURE_GENERATED_FILES = \
@@ -188,6 +190,7 @@ CONFIGURE_GENERATED_FILES = \
     ext/Parrot-Embed/Makefile.PL \
     myconfig  \
     $(GEN_PASM_INCLUDES) \
+    $(SRC_DIR)/call_list.txt \
     MANIFEST.configure.generated
 
 
@@ -212,7 +215,6 @@ GEN_HEADERS = \
     $(INC_DIR)/pbcversion.h
 
 GEN_SOURCES = \
-    $(SRC_DIR)/call_list.txt \
     $(SRC_DIR)/core_ops.c \
     $(SRC_DIR)/nci.c \
     $(SRC_DIR)/core_ops_switch.c \
@@ -2167,8 +2169,8 @@ $(LIBNCI_TEST_SO): $(SRC_DIR)/nci_test$(O)
 
 # for use by runtime/parrot/library/OpenGL.pir
 $(LIBGLUTCB_SO): $(LIBPARROT) $(SRC_DIR)/glut_callbacks$(O)
-	$(LD) $(LD_LOAD_FLAGS) @ncilib_link_extra@ $(LDFLAGS) \
-    @[EMAIL PROTECTED]@ $(SRC_DIR)/glut_callbacks$(O) $(C_LIBS)
+	$(LD) $(LD_LOAD_FLAGS) $(LDFLAGS) \
+    @[EMAIL PROTECTED]@ $(SRC_DIR)/glut_callbacks$(O) $(ALL_PARROT_LIBS)
 
 # emacs etags
 # this needs exuberant-ctags
diff --git a/config/gen/opengl.pm b/config/gen/opengl.pm
index aae7026..d913325 100644
--- a/config/gen/opengl.pm
+++ b/config/gen/opengl.pm
@@ -13,14 +13,25 @@ Generates several files used by the OpenGL binding.  These include:
 
 =item F<runtime/parrot/include/opengl_defines.pasm>
 
+=item F<runtime/parrot/library/OpenGL_funcs.pir>
+
+=item F<config/gen/call_list/opengl.in>
+
+=item F<src/glut_callbacks.c>
+
 =back
 
+For information about Parrot's OpenGL support on different platforms, and
+system libraries/headers that must be installed to enable OpenGL support,
+see L<config/auto/opengl.pm>, where this support is detected.
+
 =cut
 
 package gen::opengl;
 
 use strict;
 use warnings;
+use File::Glob;
 
 use base qw(Parrot::Configure::Step);
 
@@ -79,7 +90,205 @@ my @FREEGLUT_CALLBACKS = (
     [ 'Mouse Wheel',      'int wheel, int direction, int x, int y' ],
 );
 
+my %C_TYPE = (
+    GLvoid                  => 'void',
+    GLUnurbs                => 'void',
+    GLUquadric              => 'void',
+    GLUtesselator           => 'void',
+    gleGC                   => 'void',
+    muiObject               => 'void',
+    SphereMap               => 'void',
+    Display                 => 'void',
+    XVisualInfo             => 'void',
+    _CGLContextObject       => 'void',
+    GLXHyperpipeConfigSGIX  => 'void',
+    GLXHyperpipeNetworkSGIX => 'void',
+
+    wchar_t                 => 'void',
+
+    GLXContext              => 'void*',
+    GLXFBConfig             => 'void*',
+    GLXFBConfigSGIX         => 'void*',
+    CGLContextObj           => 'void*',
+    CGLPixelFormatObj       => 'void*',
+    CGLRendererInfoObj      => 'void*',
+    CGLPBufferObj           => 'void*',
+
+    GLchar                  => 'char',
+    GLcharARB               => 'char',
+    GLbyte                  => 'signed char',
+    GLubyte                 => 'unsigned char',
+    GLboolean               => 'unsigned char',
+
+    GLshort                 => 'short',
+    GLushort                => 'unsigned short',
+    GLhalfARB               => 'unsigned short',
+    GLhalfNV                => 'unsigned short',
+
+    Bool                    => 'int',
+    Status                  => 'int',
+    GLint                   => 'int',
+    GLsizei                 => 'int',
+    int32_t                 => 'int',
+
+    GLenum                  => 'unsigned int',
+    CGLPixelFormatAttribute => 'unsigned int',
+    CGLRendererProperty     => 'unsigned int',
+    CGLContextEnable        => 'unsigned int',
+    CGLContextParameter     => 'unsigned int',
+    CGLGlobalOption         => 'unsigned int',
+    CGLError                => 'unsigned int',
+    SphereMapFlags          => 'unsigned int',
+
+    GLuint                  => 'unsigned int',
+    GLbitfield              => 'unsigned int',
+    GLhandleARB             => 'unsigned int',
+    GLXVideoDeviceNV        => 'unsigned int',
+
+    XID                     => 'unsigned long',
+    Window                  => 'unsigned long',
+    Drawable                => 'unsigned long',
+    Font                    => 'unsigned long',
+    Pixmap                  => 'unsigned long',
+    Cursor                  => 'unsigned long',
+    Colormap                => 'unsigned long',
+    GContext                => 'unsigned long',
+    KeySym                  => 'unsigned long',
+    GLXContextID            => 'unsigned long',
+    GLXPixmap               => 'unsigned long',
+    GLXDrawable             => 'unsigned long',
+    GLXPbuffer              => 'unsigned long',
+    GLXWindow               => 'unsigned long',
+    GLXFBConfigID           => 'unsigned long',
+    GLXPbufferSGIX          => 'unsigned long',
+    GLXFBConfigIDSGIX       => 'unsigned long',
+    GLXVideoSourceSGIX      => 'unsigned long',
+
+    int64_t                 => 'long long',
+    GLint64EXT              => 'signed long long',
+    GLuint64EXT             => 'unsigned long long',
+
+    GLfloat                 => 'float',
+    GLclampf                => 'float',
+    GLdouble                => 'double',
+    GLclampd                => 'double',
+    gleDouble               => 'double',
+
+    GLintptr                => 'ptrdiff_t',
+    GLsizeiptr              => 'ptrdiff_t',
+    GLintptrARB             => 'ptrdiff_t',
+    GLsizeiptrARB           => 'ptrdiff_t',
+);
+
+my %NCI_TYPE = (
+    void         => 'v',
+    char         => 'c',
+    short        => 's',
+    int          => 'i',
+    long         => 'l',
+    ptrdiff_t    => 'l',
+    # Requires RT 53406
+    # longlong     => 'L',
+    float        => 'f',
+    double       => 'd',
+
+    'char*'      => 't',
+
+    'short*'     => 'p',
+    'int*'       => 'p',
+    'long*'      => 'p',
+    'longlong*'  => 'p',
+    'float*'     => 'p',
+    'double*'    => 'p',
+    'void*'      => 'p',
+
+    'char**'     => 'p',
+    'short**'    => 'p',
+    'int**'      => 'p',
+    'long**'     => 'p',
+    'longlong**' => 'p',
+    'float**'    => 'p',
+    'double**'   => 'p',
+    'void**'     => 'p',
+
+    'double***'  => 'p',
+);
+
+my %OVERRIDE = (
+    'glutInit'  => 'v3p',
+);
+
+my @IGNORE = (
+    # Most of these are limitations of this module or Parrot NCI
+
+    # Don't handle GetProcAddress type functions yet
+    'glutGetProcAddress',
+    'glXGetProcAddress',
+    'glXGetProcAddressARB',
+
+    # Don't handle this odd create/callback register function yet
+    'glutCreateMenu',
+
+    # Don't handle GLU or MUI callbacks yet
+    'gluNurbsCallback',
+    'gluQuadricCallback',
+    'gluTessCallback',
+    'muiSetCallback',
+    'muiSetNonMUIcallback',
+    'handler',
+    'callback',
+
+    # Don't handle functions without "namespace" prefixes matching library
+    'rot_axis',
+    'rot_about_axis',
+    'rot_omega',
+    'rot_prince',
+    'urot_axis',
+    'urot_about_axis',
+    'urot_omega',
+    'urot_prince',
+    'uview_direction',
+    'uviewpoint',
+
+    # Can't handle longlong until RT 53406 is done
+    'glPresentFrameKeyedNV',
+    'glPresentFrameDualFillNV',
+    'glXSwapBuffersMscOML',
+    'glXWaitForMscOML',
+    'glXWaitForSbcOML',
+
+    # Can't handle weird data types specified only in proprietary headers
+    'glXCreateGLXVideoSourceSGIX',
+    'glXAssociateDMPbufferSGIX',
+
+    # Ignore internal GLUT Win32 compatibility hackage
+    'exit',
+);
+
+my @SKIP = (
+    # Apple CGL OpenGL API conversion macros
+    'CGLMacro.h',
+
+    # Internal headers for GLE (OpenGL Extrusions) library
+    'extrude.h',
+    'segment.h',
+
+    # Rotation math utility functions from GLE
+    'gutil.h',
+
+    # Plane math utility functions/macros from GLE
+    'intersect.h',
+
+    # MUI (internal?) headers lacking "namespace" identifier prefixes
+    'browser.h',
+    'gizmo.h',
+    'hslider.h',
+    'vslider.h',
+);
+
 my $MACRO_FILE = 'runtime/parrot/include/opengl_defines.pasm';
+my $FUNCS_FILE = 'runtime/parrot/library/OpenGL_funcs.pir';
+my $SIGS_FILE  = 'config/gen/call_list/opengl.in';
 my $C_FILE     = 'src/glut_callbacks.c';
 
 
@@ -87,37 +296,76 @@ sub _init {
     my $self = shift;
 
     return {
-        description  => q{Generating OpenGL bindings},
-        result       => q{},
+        description => q{Generating OpenGL bindings},
+        result      => q{},
     }
 }
 
 sub runstep {
-    my ( $self, $conf ) = @_;
+    my ($self, $conf) = @_;
 
-    unless ( $conf->data->get('has_opengl') ) {
+    unless ($conf->data->get('has_opengl')) {
         $self->set_result('skipped');
         return 1;
     }
 
+    my $verbose = $conf->options->get('verbose') || 0;
+
+    my @include_paths_win32 = grep /\S/ => split /;/ => ($ENV{INCLUDE} || '');
+
+    s{\\}{/}g foreach @include_paths_win32;
+
     my @header_globs = (
+        # Default location for most UNIX-like platforms
         '/usr/include/GL/*.h',
+
+        # Mac OS X
         '/System/Library/Frameworks/OpenGL.framework/Headers/*.h',
         '/System/Library/Frameworks/GLUT.framework/Headers/*.h',
+
+        # Windows/MSVC
+        (map "$_/gl/*.h" => @include_paths_win32),
+
+#         "$ENV{HOME}/src/osx/headers/GLUT/*.h",
+#         "$ENV{HOME}/src/osx/headers/OpenGL/*.h",
+#         "$ENV{HOME}/src/osx-10.4/GLUT/*.h",
+#         "$ENV{HOME}/src/osx-10.4/OpenGL/*.h",
+#         "$ENV{HOME}/src/cygwin/opengl-1.1.0/GLUI_v2_1_beta/*.h",
+#         "$ENV{HOME}/src/cygwin/opengl-1.1.0/glut-3.7.3/include/GL/*.h",
+#         "$ENV{HOME}/src/cygwin/opengl-1.1.0/glut-3.7.3/include/mui/*.h",
+#         "$ENV{HOME}/src/glut-3.7.6/include/GL/*.h",
+#         "$ENV{HOME}/src/glut-3.7.6/include/mui/*.h",
     );
 
-    my @header_files = sort map {glob} @header_globs;
+    my @header_files = sort map {File::Glob::bsd_glob($_)} @header_globs;
+
+    my %skip = map {($_ => 1)} @SKIP;
+    @header_files = grep {my ($file) = m{([^/]+)$}; !$skip{$file}} @header_files;
 
-    $self->gen_opengl_defines($conf, [EMAIL PROTECTED]);
-    $self->gen_glut_callbacks($conf);
+    die "OpenGL enabled and detected, but no OpenGL headers found!"
+        unless @header_files;
+
+    my $autogen_header = <<'HEADER';
+# DO NOT EDIT THIS FILE.
+#
+# Any changes made here will be lost.
+#
+# This file is generated automatically by config/gen/opengl.pm
+# using the following files:
+#
+HEADER
+
+    $autogen_header .= "# $_\n" foreach @header_files;
+
+    $self->gen_opengl_defines ($conf, [EMAIL PROTECTED], $autogen_header, $verbose);
+    $self->gen_opengl_wrappers($conf, [EMAIL PROTECTED], $autogen_header, $verbose);
+    $self->gen_glut_callbacks ($conf);
 
     return 1;
 }
 
 sub gen_opengl_defines {
-    my ( $self, $conf, $header_files ) = @_;
-
-    my $verbose = $conf->options->get('verbose');
+    my ($self, $conf, $header_files, $autogen_header, $verbose) = @_;
 
     my (%defs, @macros);
     my $max_len = 0;
@@ -129,12 +377,13 @@ sub gen_opengl_defines {
         while (<$header>) {
             my (@F) = split;
             next unless @F > 2 and $F[0] eq '#define';
-            next unless $F[1] =~ /^(GL(?:X|(?:UT?))?)_/;
+            next unless $F[1] =~ /^(AGL|CGL|WGL|GLX|MUI|SMAP|TUBE|GL[A-Z]*)_/;
+            next if     $F[1] =~ /\(/;
 
             $max_len = length $F[1] if $max_len < length $F[1];
 
             my $api = $1;
-            if ($F[2] =~ /^GL/) {
+            if ($F[2] =~ /^(?:[ACW])?GL/) {
                 push @macros, [$api, $F[1], $F[2]];
             }
             elsif (   $F[2] =~ /^0x[0-9a-fA-F]+$/
@@ -149,7 +398,7 @@ sub gen_opengl_defines {
 
     foreach my $macro (@macros) {
         my ($api, $define, $value) = @$macro;
-        my ($val_api) = $value =~ /^(GL[A-Z]*)_/;
+        my ($val_api) = $value =~ /^((?:[ACW])?GL[A-Z]*)_/;
 
         $defs{$api}{$define} = $defs{$val_api}{$value};
 
@@ -160,17 +409,7 @@ sub gen_opengl_defines {
     open my $macros, '>', $MACRO_FILE
         or die "Could not open macro file '$MACRO_FILE' for write: $!";
 
-    print $macros <<"HEADER";
-# DO NOT EDIT THIS FILE.
-#
-# Any changes made here will be lost.
-#
-# This file is generated automatically by config/gen/opengl.pm
-# using the following files:
-#
-HEADER
-
-    print $macros "# $_\n" foreach @$header_files;
+    print $macros $autogen_header;
     print $macros "\n\n";
 
     foreach my $api (sort keys %defs) {
@@ -187,6 +426,308 @@ HEADER
     return 1;
 }
 
+sub gen_opengl_wrappers {
+    my ($self, $conf, $header_files, $autogen_header, $verbose) = @_;
+
+    my %IGNORE = map {($_ => 1)} @IGNORE;
+
+    my (%pass, %fail, %ignore, %sigs, %funcs);
+
+    # PHASE 1: Parse Headers
+    foreach my $file (@$header_files) {
+        open my $header, '<', $file
+            or die "Could not open header '$file': $!";
+
+      PROTO:
+        while (<$header>) {
+            # Get rid of C comments
+            s{/\*.*?\*/}{}g;
+            if (m{/\*}) {
+                chomp;
+                $_ .= <$header>;
+                redo;
+            }
+
+            # Make sure the entire parameter list is on a single line
+            next unless /\(/;
+            unless (/\)/) {
+                chomp;
+                $_ .= <$header>;
+                redo;
+            }
+
+            # We only care about regular function prototypes
+            next unless /API/ or /\bextern\b/ or /\bmui[A-Z]/;
+            next if     /^#/;
+            next if     /\btypedef\b/;
+
+            # Save a (space compressed) copy of the source line
+            # for later error reporting
+            my $orig =  $_;
+               $orig =~ s/\s+/ /g;
+               $orig =~ s/ $/\n/;
+
+            # Get rid of junk needed for C, but not for Parrot NCI;
+            # also do general cleanup to make parsing easier
+            s/\bAVAILABLE_MAC_OS_X_VERSION_\d+_\d+_AND_LATER\b\s*//;
+            s/\b__cdecl\b\s*//;
+            s/\b__stdcall\b\s*//;
+            s/\b_CRTIMP\b\s*//;
+            s/\bextern\b\s*//;
+            s/\bstatic\b\s*//;
+            s/\bconst\b\s*//g;
+            s/\benum\b\s*//g;
+            s/\bstruct\b\s*//g;
+            s/\b[A-Z]*API[A-Z]*\s*//g;
+            s/\s*\*\s*/* /g;
+            s/\* \*/**/g;
+            s/\s*,\s*/, /g;
+            s/\s*\(\s*/(/g;
+            s/\s*\)\s*/)/g;
+            s/\s+/ /g;
+            s/\s+$//;
+            s/^\s+//;
+
+            # Canonicalize types
+            s/\b(\w+)\b/$C_TYPE{$1} ? $C_TYPE{$1} : $1/eg;
+            s/\b(?:un)?signed //g;
+            s/\blong long\b/longlong/g;
+
+            # Parse the function prototype, trying hard to capture name
+            my ($return, $name, $params) = /^(\w+\**) (\w+)\(([^)]*)\);$/;
+            ($name) = /^\w+\(?\** (\w+)\)?/ unless defined $name;
+
+            # Is this a function we're ignoring for now or handling elsewhere?
+            if (defined $name) {
+                # Callback reg functions handled by gen_*_callbacks()
+                $pass  {$file}++, next if /\bglut[A-Z][a-zA-Z]+Func\b/;
+                $ignore{$file}++, next if /\bsmap[A-Z][a-zA-Z]+Func\b/;
+
+                # Ignore all library-internal functions
+                $ignore{$file}++, next if $name =~ /^__/;
+                $ignore{$file}++, next if $name =~ /_ATEXIT_HACK$/;
+
+                # Miscellaneous ignores
+                $ignore{$file}++, next if $IGNORE{$name};
+            }
+
+            # Successful parse?
+            unless (defined $return and defined $name and defined $params) {
+                $fail{$file}++;
+                $name ||= '';
+                warn "In OpenGL header '$file', can't parse canonicalized prototype for '$name':\n  $_\nOriginal prototype:\n  $orig\n";
+                next;
+            }
+
+            # Figure out what group/library this function belongs to
+            my ($group) = $name =~ /^(agl|CGL|wgl|glX|mui|smap|gl[a-z]*)/;
+
+            unless ($group) {
+                $fail{$file}++;
+                warn "In OpenGL header '$file', found a non-OpenGL function: '$name'\n";
+                next;
+            }
+
+            $group = lc $group;
+
+            # Convert return and param types to NCI signature
+            my $nci_sig = $OVERRIDE{$name};
+
+            unless ($nci_sig) {
+                $params = '' if $params eq 'void';
+                my @params = split /, / => $params;
+                unshift @params, $return;
+
+                foreach my $param (@params) {
+                    1 while $param =~ s/(\w+\**) (\w+)\s*\[\d*\]/$1* $2/;
+                    $param =~ s/ \w+$// unless $NCI_TYPE{$param};
+                    unless ($NCI_TYPE{$param}) {
+                        $fail{$file}++;
+                        warn "In OpenGL header '$file', prototype '$name', can't handle type '$param'; original prototype:\n  $orig\n";
+                        next PROTO;
+                    }
+                    $nci_sig .= $NCI_TYPE{$param};
+                }
+
+                if ($nci_sig =~ /.v/) {
+                    $fail{$file}++;
+                    warn "In OpenGL header '$file', prototype '$name', there is a void parameter; original prototype:\n  $orig\n";
+                    next PROTO;
+                }
+            }
+
+            # Success!  Save results.
+            $pass{$file}++;
+            $sigs{$nci_sig}++;
+            push @{$funcs{$group}}, [$name, $nci_sig];
+
+            print "$group\t$nci_sig\t$return $name($params);\n" if $verbose >= 3;
+        }
+    }
+
+    # PHASE 2: Write unique signatures to NCI signatures file
+    my @sigs = sort keys %sigs;
+
+    open my $sigs, '>', $SIGS_FILE
+        or die "Could not open NCI signatures file '$SIGS_FILE' for write: $!";
+
+    print $sigs <<"HEADER";
+# Used by OpenGL (including GLU and GLUT)
+#
+$autogen_header
+
+# GLUT callbacks
+v    JP
+v    JPi
+v    JPii
+
+# Generated signatures
+HEADER
+
+    foreach my $nci_sig (@sigs) {
+        my ($return, $params) = $nci_sig =~ /^(.)(.*)$/;
+
+        print $sigs "$return    $params\n";
+    }
+
+    close $sigs;
+    $conf->append_configure_log($SIGS_FILE);
+
+    # PHASE 3: Write function lists for each OpenGL-related library
+
+    open my $funcs, '>', $FUNCS_FILE
+        or die "Could not open function list file '$FUNCS_FILE' for write: $!";
+
+    print $funcs $autogen_header;
+    print $funcs <<'GLUTCB_FUNCS';
+
+
+.sub _glutcb_func_list
+    .local pmc glutcb_funcs
+    glutcb_funcs = new 'ResizableStringArray'
+    push glutcb_funcs, 'glutcbCloseFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbDisplayFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbIdleFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbMenuDestroyFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbOverlayDisplayFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbWMCloseFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbEntryFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbMenuStateFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbVisibilityFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbWindowStatusFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbButtonBoxFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbDialsFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbMotionFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbPassiveMotionFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbReshapeFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbSpaceballButtonFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbTabletMotionFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbKeyboardFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbKeyboardUpFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbMenuStatusFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbSpaceballMotionFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbSpaceballRotateFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbSpecialFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbSpecialUpFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbMouseFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbMouseWheelFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbTabletButtonFunc'
+    push glutcb_funcs, 'vJP'
+    push glutcb_funcs, 'glutcbTimerFunc'
+    push glutcb_funcs, 'vJPii'
+    push glutcb_funcs, 'glutcbJoystickFunc'
+    push glutcb_funcs, 'vJPi'
+
+    .return (glutcb_funcs)
+.end
+GLUTCB_FUNCS
+
+    foreach my $group (sort keys %funcs) {
+        my $sub_name  = "_${group}_func_list";
+        my $list_name = "${group}_funcs";
+
+        print $funcs <<"SUB_HEADER";
+
+
+.sub $sub_name
+    .local pmc $list_name
+    $list_name = new 'ResizableStringArray'
+
+SUB_HEADER
+
+        my @funcs = sort {$a->[0] cmp $b->[0]} @{$funcs{$group}};
+        foreach my $func (@funcs) {
+            my ($name, $sig) = @$func;
+
+            print $funcs <<"FUNCTION"
+    push $list_name, '$name'
+    push $list_name, '$sig'
+FUNCTION
+        }
+        print $funcs <<"SUB_FOOTER";
+
+    .return ($list_name)
+.end
+SUB_FOOTER
+    }
+
+    close $funcs;
+    $conf->append_configure_log($FUNCS_FILE);
+
+    # PHASE 4: Print statistical info on parse results if verbose
+    if ($verbose) {
+        print "\nPASS  FAIL  IGNORE   HEADER\n";
+        foreach my $file (@$header_files, 'TOTAL') {
+            my $pass   = $pass  {$file} || 0;
+            my $fail   = $fail  {$file} || 0;
+            my $ignore = $ignore{$file} || 0;
+
+            printf "%4d  %4d  %4d     %s\n", $pass, $fail, $ignore, $file;
+
+            $pass  {TOTAL} += $pass;
+            $fail  {TOTAL} += $fail;
+            $ignore{TOTAL} += $ignore;
+        }
+
+        print "\nCOUNT   NCI SIGNATURE\n" if $verbose >= 2;
+        foreach my $nci_sig (@sigs, 'TOTAL') {
+            printf "%5d   %s\n", $sigs{$nci_sig}, $nci_sig if $verbose >= 2;
+            $sigs{TOTAL} += $sigs{$nci_sig};
+        }
+
+        printf "\n===> %d unique signatures successfully translated.\n",
+               scalar @sigs
+    }
+
+    return 1;
+}
+
 sub gen_glut_callbacks {
     my ( $self, $conf ) = @_;
 
@@ -251,11 +792,11 @@ sub gen_glut_callbacks {
 
    foreach (@callbacks) {
         $enums     .= "    $_->{enum},\n";
-        $thunks    .= "           void $_->{thunk}($_->{proto});\n";
-        $reg_funcs .= "PARROT_API void $_->{glutcb}(Parrot_Interp, PMC *);\n";
+        $thunks    .= "                     void $_->{thunk}($_->{proto});\n";
+        $reg_funcs .= "PARROT_DYNEXT_EXPORT void $_->{glutcb}(Parrot_Interp, PMC *);\n";
    }
 
-    my $header = <<HEADER;
+    my $header = <<"HEADER";
 /*
 # DO NOT EDIT THIS FILE.
 #
@@ -283,6 +824,8 @@ cannot be used.
 
 */
 
+#define PARROT_IN_EXTENSION
+
 #include <$glut_header>
 #include "parrot/parrot.h"
 
@@ -306,14 +849,14 @@ typedef struct GLUT_CB_data {
 GLUT_CB_data callback_data[GLUT_NUM_CALLBACKS];
 
 
-           int  is_safe(Parrot_Interp, PMC *);
+                     int  is_safe(Parrot_Interp, PMC *);
 
-           void glut_timer_func(int);
-PARROT_API void glutcbTimerFunc(Parrot_Interp, PMC *, unsigned int, int);
+                     void glut_timer_func(int);
+PARROT_DYNEXT_EXPORT void glutcbTimerFunc(Parrot_Interp, PMC *, unsigned int, int);
 
 #if GLUT_API_VERSION >= 4
-           void glut_joystick_func(unsigned int, int, int, int);
-PARROT_API void glutcbJoystickFunc(Parrot_Interp, PMC *, int);
+                void glut_joystick_func(unsigned int, int, int, int);
+PARROT_DYNEXT_EXPORT void glutcbJoystickFunc(Parrot_Interp, PMC *, int);
 #endif
 
 $thunks
@@ -356,7 +899,7 @@ glut_timer_func(int data)
         Parrot_runops_fromc_args_event(interp, sub, "vi", data);
 }
 
-PARROT_API
+PARROT_DYNEXT_EXPORT
 void
 glutcbTimerFunc(PARROT_INTERP, PMC *sub, unsigned int milliseconds, int data)
 {
@@ -391,7 +934,7 @@ glut_joystick_func(unsigned int buttons, int xaxis, int yaxis, int zaxis)
         Parrot_runops_fromc_args_event(interp, sub, "viiii", buttons, xaxis, yaxis, zaxis);
 }
 
-PARROT_API
+PARROT_DYNEXT_EXPORT
 void
 glutcbJoystickFunc(PARROT_INTERP, PMC *sub, int pollinterval)
 {
@@ -431,7 +974,7 @@ $_->{thunk}($_->{params})
         Parrot_runops_fromc_args_event(interp, sub, "$_->{sig}"$_->{args});
 }
 
-PARROT_API
+PARROT_DYNEXT_EXPORT
 void
 $_->{glutcb}(PARROT_INTERP, PMC *sub)
 {
@@ -447,7 +990,7 @@ IMPLEMENTATION
     }
 
 
-    my $footer = <<FOOTER;
+    my $footer = <<'FOOTER';
 
 /*
 
diff --git a/runtime/parrot/library/OpenGL.pir b/runtime/parrot/library/OpenGL.pir
index a45c310..6a06a10 100644
--- a/runtime/parrot/library/OpenGL.pir
+++ b/runtime/parrot/library/OpenGL.pir
@@ -76,8 +76,7 @@ include:
 
 .namespace ['OpenGL']
 
-.include 'datatypes.pasm'
-.include 'iterator.pasm'
+.include 'library/OpenGL_funcs.pir'
 
 
 =item _opengl_init()
@@ -107,18 +106,21 @@ the known different filenames for each library in turn before giving up.
 
     libnames = new 'ResizableStringArray'
     push libnames, 'libGL'
+    push libnames, 'opengl32'
     push libnames, '/System/Library/Frameworks/OpenGL.framework/OpenGL'
     libgl = _load_lib_with_fallbacks('GL', libnames)
     set_global '_libgl', libgl
 
     libnames = new 'ResizableStringArray'
     push libnames, 'libGLU'
+    push libnames, 'glu32'
     push libnames, '/System/Library/Frameworks/OpenGL.framework/OpenGL'
     libglu = _load_lib_with_fallbacks('GLU', libnames)
     set_global '_libglu', libglu
 
     libnames = new 'ResizableStringArray'
     push libnames, 'libglut'
+    push libnames, 'glut32'
     push libnames, '/System/Library/Frameworks/GLUT.framework/GLUT'
     libglut = _load_lib_with_fallbacks('GLUT', libnames)
     set_global '_libglut', libglut
@@ -148,7 +150,6 @@ match can be found on the system.
 
     .local pmc    list_iter
     list_iter = new 'Iterator', fallback_list
-    list_iter = .ITERATE_FROM_START
 
     .local string libname
     .local pmc    library
@@ -198,120 +199,6 @@ Create NCI wrappers for all GL, GLU, and GLUT functions
     _wrap_nci_list(namespace, libglutcb, glutcb_funcs)
 .end
 
-.sub _gl_func_list
-    .local pmc gl_funcs
-    gl_funcs = new 'ResizableStringArray'
-    push gl_funcs, 'glBegin'
-    push gl_funcs, 'vi'
-    push gl_funcs, 'glClear'
-    push gl_funcs, 'vi'
-    push gl_funcs, 'glColor3f'
-    push gl_funcs, 'vfff'
-    push gl_funcs, 'glEnd'
-    push gl_funcs, 'v'
-    push gl_funcs, 'glFlush'
-    push gl_funcs, 'v'
-    push gl_funcs, 'glVertex3f'
-    push gl_funcs, 'vfff'
-    push gl_funcs, 'glRotatef'
-    push gl_funcs, 'vffff'
-
-    .return (gl_funcs)
-.end
-
-.sub _glu_func_list
-    .local pmc glu_funcs
-    glu_funcs = new 'ResizableStringArray'
-
-    .return (glu_funcs)
-.end
-
-.sub _glut_func_list
-    .local pmc glut_funcs
-    glut_funcs = new 'ResizableStringArray'
-    push glut_funcs, 'glutInit'
-    push glut_funcs, 'v3p'
-    push glut_funcs, 'glutInitDisplayMode'
-    push glut_funcs, 'vi'
-    push glut_funcs, 'glutCreateWindow'
-    push glut_funcs, 'it'
-    push glut_funcs, 'glutDestroyWindow'
-    push glut_funcs, 'vi'
-    push glut_funcs, 'glutMainLoop'
-    push glut_funcs, 'v'
-    push glut_funcs, 'glutPostRedisplay'
-    push glut_funcs, 'v'
-    push glut_funcs, 'glutSwapBuffers'
-    push glut_funcs, 'v'
-
-    .return (glut_funcs)
-.end
-
-.sub _glutcb_func_list
-    .local pmc glutcb_funcs
-    glutcb_funcs = new 'ResizableStringArray'
-    push glutcb_funcs, 'glutcbCloseFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbDisplayFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbIdleFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbMenuDestroyFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbOverlayDisplayFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbWMCloseFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbEntryFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbMenuStateFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbVisibilityFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbWindowStatusFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbButtonBoxFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbDialsFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbMotionFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbPassiveMotionFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbReshapeFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbSpaceballButtonFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbTabletMotionFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbKeyboardFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbKeyboardUpFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbMenuStatusFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbSpaceballMotionFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbSpaceballRotateFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbSpecialFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbSpecialUpFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbMouseFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbMouseWheelFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbTabletButtonFunc'
-    push glutcb_funcs, 'vJP'
-    push glutcb_funcs, 'glutcbTimerFunc'
-    push glutcb_funcs, 'vJPii'
-    push glutcb_funcs, 'glutcbJoystickFunc'
-    push glutcb_funcs, 'vJPi'
-
-    .return (glutcb_funcs)
-.end
-
 
 =item _wrap_nci_list(pmc namespace, pmc library, pmc nci_list)
 
@@ -331,7 +218,6 @@ alternating function names and Parrot NCI signatures.
 
     .local pmc list_iter
     list_iter = new 'Iterator', nci_list
-    list_iter = .ITERATE_FROM_START
 
     .local string func_name, signature
     .local pmc    function

Reply via email to