Codebase list libois-perl / HEAD PerlOISJoyStickListener.cpp
HEAD

Tree @HEAD (Download .tar.gz)

PerlOISJoyStickListener.cpp @HEADraw · history · blame

#include "PerlOISJoyStickListener.h"

// class implementing OIS::JoyStickListener interface,
// but using Perl callbacks

PerlOISJoyStickListener::PerlOISJoyStickListener() : mPerlObj((SV *)NULL)
{
}

PerlOISJoyStickListener::~PerlOISJoyStickListener()
{
    if (mPerlObj != (SV *)NULL && SvREFCNT(mPerlObj)) {
        SvREFCNT_dec(mPerlObj);
    }
    mCanMap.clear();
}

bool PerlOISJoyStickListener::buttonPressed(const OIS::JoyStickEvent &evt, int button)
{
    return callPerlCallback("buttonPressed", evt, button);
}

bool PerlOISJoyStickListener::buttonReleased(const OIS::JoyStickEvent &evt, int button)
{
    return callPerlCallback("buttonReleased", evt, button);
}

bool PerlOISJoyStickListener::axisMoved(const OIS::JoyStickEvent &evt, int axis)
{
    return callPerlCallback("axisMoved", evt, axis);
}

bool PerlOISJoyStickListener::sliderMoved(const OIS::JoyStickEvent &evt, int slider)
{
    return callPerlCallback("sliderMoved", evt, slider);
}

bool PerlOISJoyStickListener::povMoved(const OIS::JoyStickEvent &evt, int pov)
{
    return callPerlCallback("povMoved", evt, pov);
}

void PerlOISJoyStickListener::setPerlObject(SV *pobj)
{
    if (pobj != (SV *)NULL && sv_isobject(pobj)) {
        // copy the SV *
        if (mPerlObj == (SV *)NULL) {
            // first time, create new SV *
            mPerlObj = newSVsv(pobj);
        } else {
            // just overwrite existing SV *
            SvSetSV(mPerlObj, pobj);
        }
    } else {
        croak("Argument wasn't an object, so MouseListener wasn't set.\n");
    }

    setCans();
}

void PerlOISJoyStickListener::setCans()
{
    mCanMap["buttonPressed"] = perlCallbackCan("buttonPressed");
    mCanMap["buttonReleased"] = perlCallbackCan("buttonReleased");
    mCanMap["axisMoved"] = perlCallbackCan("axisMoved");
    mCanMap["sliderMoved"] = perlCallbackCan("sliderMoved");
    mCanMap["povMoved"] = perlCallbackCan("povMoved");
}

// check whether the Perl object has a callback method implemented
// (is there a perl API method or something easier than this?)
bool PerlOISJoyStickListener::perlCallbackCan(string const &cbmeth)
{
    int count;
    SV *methret;
    bool can;

    dSP;

    ENTER;
    SAVETMPS;

    // call `can' to see if they implemented the callback
    PUSHMARK(SP);
    XPUSHs(mPerlObj);
    XPUSHs(sv_2mortal(newSVpv(cbmeth.c_str(), 0)));
    PUTBACK;

    count = call_method("can", G_SCALAR);
    SPAGAIN;
    if (count != 1) {
        croak("can (%s) didn't return a single value?", cbmeth.c_str());
    }

    methret = POPs;
    PUTBACK;

    can = SvTRUE(methret);

    FREETMPS;
    LEAVE;

    return can;
}

bool PerlOISJoyStickListener::callPerlCallback(string const &cbmeth, const OIS::JoyStickEvent &evt, int thingID)
{
    int count;
    SV *methret;
    bool retval = true;   // default to returning true

    if (! (mCanMap[cbmeth] == true)) {
        // method not implemented, just return true
        return retval;
    }

    if (mPerlObj != (SV *)NULL) {
        // see `perldoc perlcall`
        dSP;

        ENTER;
        SAVETMPS;

        SV *joyevt = sv_newmortal();
        TMOIS_OUT(joyevt, &evt, JoyStickEvent);  // put C++ object into Perl

        PUSHMARK(SP);
        XPUSHs(mPerlObj);
        XPUSHs(joyevt);
        XPUSHs(sv_2mortal(newSViv(thingID)));
        PUTBACK;

        count = call_method(cbmeth.c_str(), G_SCALAR);
        SPAGAIN;
        if (count != 1) {
            croak("Callbacks must return a single (boolean) value");
        }

        methret = POPs;
        PUTBACK;

        retval = SvTRUE(methret) ? true : false;

        FREETMPS;
        LEAVE;
    }

    return retval;
}