http://www.perlmonks.org?node_id=328905

flyingmoose has asked for the wisdom of the Perl Monks concerning the following question:

update: somehow I stumbled upon the answer to this. spooky, but I'm still open to suggestions for improvements/further-research.

Original question: I'm writing a toy program using Inline::C (which is awesome, BTW), but I have hit a painful roadblock. I'm calling a C function that will never return, so I need to call Perl code from this C event handler. What is the cleanest way to achieve this? I'm very strong in C, I'm pretty darn good in Perl, but mixing the two is rather new to me. XS, due to similarity to JNI, has scared me until this point, but I am afraid this is where I must go.

details:

Ok, folks, after fighting trying to get OpenGL.pm and SDL's OpenGL tools working on my system (thanks for the help everyone), I've given up on being able to hit 3D graphics from Perl.

My current tactic is to use Inline::C and write simple wrappers to GLUT. Freeglut is actually looking very promising as a library, so there is a lot of merit in trying this.

In a lame attempt to keep my program compiling on most platforms, I'd like to use the stock 1.3 freeglut that comes with Fedora Core 1. That is, a very old version.

As many of you know, glut has a function called "GlutMainLoop" that takes over control of a program and never lets it go. This defeats my goal of being able to script most of my game in Perl with bindings to GLUT.

Bottom line -- is there a method suitable for calling Perl functions from inline C code, or do I need to move to XS? I have been avoiding XS until now due to the annoyances of makefiles and various methods, not being exactly 'fun' for this side project.

Suggestions? For the record, I am enjoying these black arts of llama conjuring, and diving deeper is ok -- I could definitely use some pointers though.

Replies are listed 'Best First'.
Re: Inline::C *back* into Perl
by flyingmoose (Priest) on Feb 14, 2004 at 02:43 UTC
    SUCCESS -- I HAVE STUMBLED ONTO BLACK MAGIC!!! Here's the basics...
    use Inline C => DATA => LIBS => "-lblah..."; perl_calling_c(); sub c_calling_perl() { print "transcendance\n"; } __DATA__ void perl_calling_c() { call_pv('c_calling_perl',G_DISCARD|G_NOARGS); }

    Believe it or not, this works! Awesome! And I have no idea how this ever worked, or what evils it does, but yeeha, I have solved my problem of OpenGL callbacks.

    For those OpenGL folks, consider "perl_calling_c" as a "GlutMainLoop" and "c_calling_perl" as one of the functions such as a registered "glutDisplayFunc", which will later hand back down crossing the boundary one or more times in an attempt to blow everyone's minds away.

    It's going to take me a few days before I get "spinning cube" up and running with this wild method, but I will certaintly post the Code when I have it.

    So far, it's looking a little slow, with a call down and back up (of trivial nature) taking 0.08 real seconds on my 2.4GHz laptop. Printing directly takes 0.003 -- or roughly 25 times slower. I bet, though, for what I want to do this will be good enough.

Re: Inline::C *back* into Perl
by rob_au (Abbot) on Feb 14, 2004 at 08:05 UTC
    You might be interested in taking a look at the SDL development work in Perl which Tels has been doing here - This work has forked from the SDL Perl project and a number of Open GL example screenshots can be found here.

     

    perl -le "print unpack'N', pack'B32', '00000000000000000000001011000001'"

      rob, yeah, I've looked at that. A few comments. First off, OpenGL bindings on Perl (even for SDL) simply don't compile on this platform. If I could fix them, I could. My C OpenGL apps work great. I know -- I have weird requirements. But with the solution I'm working at, I think I'm going to get a reinvented wheel, but one that turns faster and does what I want.
Re: Inline::C *back* into Perl
by BUU (Prior) on Feb 14, 2004 at 01:01 UTC
    As you say, trying to go from glut back to perl is probably futile. I'd rather try something like wxWindows to write the window wrapper and write the main loop in perl.
      Sounds like a very good plan, but wxWindows is C++. Does that complicate the matters of using inline? It seems from CPAN docs that Inline::CPP isn't going to allow me to call instance methods across the Perl/C++ boundary without non OO wrappers (I could be wrong).

      FYI: freeglut 2.20 apparently doesn't have the mainloop requirement, I'm just trying to use packages that are in my apt-repository if possible...just to be sure I'm not the only one who can compile whatever I do...worst case, I can upgrade freeglut.

      Again, it seems as though I would just use wxPerl or GTK perl bindings or even OpenGL.pm -- except that, as I've said, OpenGL doesn't compile. Besides, using Inline is fun and opens up the ability to use a lot of cool libs out there.

        wxWindows also has perl bindings. So theoretically you could just write perl wrappers for opengl commands and then do it all in perl. Thats what I'd try.
Re: Inline::C *back* into Perl
by Corion (Patriarch) on Feb 14, 2004 at 10:44 UTC

    I've had only a few minor problems in getting OpenGL.pm and GLUT working with Perl under Win32, which mostly resulted from weird/bad/unforeseen #defines in the various header files.

    Other than that, I can't remember what problems there were, but after porting the test files to use GLUT instead of the "proprietary" OS/2 stuff, everything was smooth, even the GLUT callbacks into Perl went without a problem. I did not try to interface to SDL though.

Re: Inline::C *back* into Perl
by flyingmoose (Priest) on Feb 15, 2004 at 21:35 UTC
    Came up with a good idea while driving the car home this afternoon listening to ABB's Live At Fillmore East and some Joe Satriani. (Ah, driving, rain and long jam music...both great inspiration...)

    There is no reason why I can't write a C graphics engine and interface the OpenGL program to any program (including Perl) over named-pipes, sockets, or equivalent.

    app ---> commands over pipe --> gfxEngine <--- events over pipe <--- (where the app can be written in *any* language)
    </code>

    This system would be really cool as I would have a graphics engine that is 100% cross-language (if not cross-platform) -- in theory, it might even be able to write OpenGL programs in bash.

    This seems better than the Inline approach (though Inline rocks) since I could pretty much develop a solution usable from any application, standarding on IPC protocols rather than language constructs. The performance tradeoff of using IPC rather than system calls should be neglible, and this would allow me to develop any number of utility functions in C for speed improvements.

    Also, this seems like it might have a bit more community interest as well -- rather than just another way to talk to OpenGL.

    Best of all, I'd have a cross-language graphics engine usuable immediately in all languages I ran across with...even future ones.

    I'll still have to hammer out the protocols and so on, but this is definitely doable and I'm going to give it a shot.

      Alas, I'm still making this too hard. The engine could take command input as STDIN and give events as STDOUT, thus allowing me to avoid pipes altogether and use Expect.pm for the main driving Perl code.
        You consider that making it easy?

        Here are a few issues to think through.

        1. Any decent GUI program needs to handle interrupts well. It was doing X, the user decides not to and interrupts it. The API that you are describing offers no good way to pass interrupts along.
        2. The system that you describe doesn't seem to have a lot of debugging hooks when things go wrong.
        3. A huge problem with Expect is that unusual, unexpected or unanticipated input causes programs to diverge. When the GUI and internal program diverge on what they think is being displayed, you can readily get into deadlocks.
        4. What you are describing sounds like a lot of overhead at all ends.
        If you want a text-based cross-language approach to GUI developlment, I would suggest using httpd instead. No, it is not perfect. But it does a good job of addressing most of the above problems and furthermore has the virtue of already being built.
Re: Inline::C *back* into Perl
by flyingmoose (Priest) on Feb 17, 2004 at 04:24 UTC
    Ok...new findings.

    One. Even with freeglut, using perlcall techniques to hop back in from OpenGL are very unstable (still). It appears to work well for simple things, but inside any sort of loop the memory requirements quickly spiral out of control. My original answer using perlcall doesn't appear to be a good one.

    Two. Looking at examples on the web, using GLX instead of GLUT will allow for Perl to own the event loop and still use Inline. GLX isn't horribly clean, but it is very fast...and all of the event stuff I need is still there. That's what is important. I know GLX doesn't have a loop since the body of the sample app in front of me is coded with a while(1). This is what I want.

    This means the engine approach would not be required, we can go back to using something like Inline::C and mapping into GLX calls.

    Yes, I know, more reinvented wheels...much can be learned from wheel-making though -- especially when all of this is for fun and on your own time.