#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "defines.h" #include "helper.h" #ifndef aTHX_ #define aTHX_ #endif #include "SDLx/Controller/Interface.h" AV *acceleration_cb( SDLx_Interface *obj, float t ) { SV *tmpsv; if( !(SvROK(obj->acceleration) && (tmpsv = obj->acceleration) ) ) croak( "Interface doesn't not contain an acceleration callback" ); dSP; AV *array = newAV(); int i; int count; SDLx_State *copyState = (SDLx_State *)safemalloc( sizeof(SDLx_State) ); copy_state( copyState, obj->current ); copyState->owned = 0; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs( sv_2mortal(newSVnv(t)) ); XPUSHs( sv_2mortal( obj2bag( sizeof(SDLx_State *), (void *)copyState, "SDLx::Controller::State" ) ) ); PUTBACK; count = call_sv( obj->acceleration, G_ARRAY ); SPAGAIN; /* warn( "state %p, state->x %f", copyState, ((SDLx_State *)copyState)->x ); */ for( i = 0; i < count; i++ ) av_push( array, newSVnv(POPn) ); /* warn ("before obj->current->x %f", obj->current->x); */ copy_state( obj->current, copyState ); /* warn ("after obj->current->x %f", obj->current->x); */ PUTBACK; FREETMPS; LEAVE; return array; } void evaluate(SDLx_Interface *obj, SDLx_Derivative *out, SDLx_State *initial, float t) { out->dx = initial->v_x; out->dy = initial->v_y; out->drotation = initial->ang_v; AV *accel = acceleration_cb(obj, t); SV *temp; temp = av_pop(accel); out->dv_x = sv_nv(temp); SvREFCNT_dec(temp); temp = av_pop(accel); out->dv_y = sv_nv(temp); SvREFCNT_dec(temp); temp = av_pop(accel); out->dang_v = sv_nv(temp); SvREFCNT_dec(temp); SvREFCNT_dec((SV *)accel); } void evaluate_dt(SDLx_Interface *obj, SDLx_Derivative *out, SDLx_State *initial, float t, float dt, SDLx_Derivative *d) { SDLx_State state; state.x = initial->x + d->dx * dt; state.y = initial->y + d->dy * dt; state.rotation = initial->rotation + d->drotation * dt; state.v_x = initial->v_x + d->dv_x * dt; state.v_y = initial->v_y + d->dv_y * dt; state.ang_v = initial->ang_v + d->dang_v * dt; out->dx = state.v_x; out->dy = state.v_y; out->drotation = state.ang_v; AV *accel = acceleration_cb(obj, t+dt); SV *temp; temp = av_pop(accel); out->dv_x = sv_nv(temp); SvREFCNT_dec(temp); temp = av_pop(accel); out->dv_y = sv_nv(temp); SvREFCNT_dec(temp); temp = av_pop(accel); out->dang_v = sv_nv(temp); SvREFCNT_dec(temp); SvREFCNT_dec((SV *)accel); } void integrate( SDLx_Interface *object, float t, float dt) { SDLx_State *state = object->current; SDLx_Derivative *a = (SDLx_Derivative *)safemalloc( sizeof(SDLx_Derivative) ); SDLx_Derivative *b = (SDLx_Derivative *)safemalloc( sizeof(SDLx_Derivative) ); SDLx_Derivative *c = (SDLx_Derivative *)safemalloc( sizeof(SDLx_Derivative) ); SDLx_Derivative *d = (SDLx_Derivative *)safemalloc( sizeof(SDLx_Derivative) ); evaluate(object, a, state, t); evaluate_dt(object, b, state, t, dt*0.5f, a); evaluate_dt(object, c, state, t, dt*0.5f, b); evaluate_dt(object, d, state, t, dt, c); const float dxdt = 1.0f/6.0f * (a->dx + 2.0f * (b->dx + c->dx) + d->dx); const float dv_xdt = 1.0f/6.0f * (a->dv_x + 2.0f * (b->dv_x + c->dv_x) + d->dv_x); const float dydt = 1.0f/6.0f * (a->dy + 2.0f * (b->dy + c->dy) + d->dy); const float dv_ydt = 1.0f/6.0f * (a->dv_y + 2.0f * (b->dv_y + c->dv_y) + d->dv_y); const float drotationdt = 1.0f/6.0f * (a->drotation + 2.0f * (b->drotation + c->drotation) + d->drotation); const float dv_angdt = 1.0f/6.0f * (a->dang_v + 2.0f * (b->dang_v + c->dang_v) + d->dang_v); state->x = state->x + dxdt * dt; state->v_x = state->v_x + dv_xdt * dt; state->y = state->y + dydt * dt; state->v_y = state->v_y + dv_ydt * dt; state->rotation = state->rotation + drotationdt * dt; state->ang_v = state->ang_v + dv_angdt * dt; safefree(a); safefree(b); safefree(c); safefree(d); } MODULE = SDLx::Controller::Interface PACKAGE = SDLx::Controller::Interface PREFIX = objx_ SDLx_Interface * objx_make( CLASS, ... ) char *CLASS CODE: RETVAL = (SDLx_Interface *)safemalloc( sizeof(SDLx_Interface) ); RETVAL->previous = (SDLx_State *)safemalloc( sizeof(SDLx_State) ); RETVAL->current = (SDLx_State *)safemalloc( sizeof(SDLx_State) ); RETVAL->acceleration = newSViv(-1); RETVAL->current->x = 0; RETVAL->current->y = 0; RETVAL->current->v_x = 0; RETVAL->current->v_y = 0; RETVAL->current->rotation = 0; RETVAL->current->ang_v = 0; RETVAL->current->owned = 1; RETVAL->previous->owned = 1; if(items > 1) (RETVAL->current)->x = SvIV(ST(1)); if(items > 2) (RETVAL->current)->y = SvIV(ST(2)); if(items > 3) (RETVAL->current)->v_x = SvIV(ST(3)); if(items > 4) (RETVAL->current)->v_y = SvIV(ST(4)); if(items > 5) (RETVAL->current)->rotation = SvIV(ST(5)); if(items > 6) (RETVAL->current)->ang_v = SvIV(ST(6)); copy_state(RETVAL->previous, RETVAL->current); OUTPUT: RETVAL void objx_set_acceleration(obj, callback) SDLx_Interface *obj SV *callback CODE: SV *tmpsv = NULL; if( !(SvROK(callback) && (tmpsv = (SV*)SvRV(callback)) && SvTYPE(tmpsv) == SVt_PVCV ) ) croak( "Acceleration callback needs to be a code ref, %p", callback ); obj->acceleration = SvRV( newRV_inc(callback) ); AV * objx_acceleration(obj, t) SDLx_Interface* obj float t CODE: RETVAL = acceleration_cb(obj, t); sv_2mortal((SV*)RETVAL); OUTPUT: RETVAL SDLx_State * objx_interpolate(obj, alpha) SDLx_Interface *obj float alpha PREINIT: char *CLASS = "SDLx::Controller::State"; CODE: SDLx_State *out = (SDLx_State *)safemalloc(sizeof(SDLx_State )); interpolate( obj,out, alpha); out->owned = 0; /* condition free */ RETVAL = out; OUTPUT: RETVAL SDLx_State * objx_current ( obj, ... ) SDLx_Interface *obj PREINIT: char * CLASS = "SDLx::Controller::State"; CODE: RETVAL = obj->current; OUTPUT: RETVAL SDLx_State * objx_previous ( obj, ... ) SDLx_Interface *obj PREINIT: char *CLASS = "SDLx::Controller::State"; CODE: RETVAL = obj->previous; OUTPUT: RETVAL void objx_update(obj, t, dt) SDLx_Interface *obj float t float dt CODE: copy_state( obj->previous, obj->current); integrate( obj, t, dt ); void objx_DESTROY( obj ) SDLx_Interface *obj CODE: SvREFCNT_dec(obj->acceleration); safefree(obj->previous); safefree(obj->current); safefree(obj);