Jump to content
  • Advertisement
Sign in to follow this  
_Vicious_

Calling function by pointer

This topic is 2523 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello!
I have the following question: how can an application call script function by pointer? Imagine there's an app-registered class with funcdef property and an object, which is shared both by the script and the application. The scripts sets funcdef property for this object. Now I want to be able to call that function from an application. How do I do that?

Share this post


Link to post
Share on other sites
Advertisement
Exactly the same way any other script function is called. :)

The handle to a function in the script is an asIScriptFunction* in C++, so it is just a matter of preparing the context with this pointer and then calling it normally.

I use it like this in my own game engine:



class CGuiElement



{
public:
...
// Event handlers
asIScriptFunction *onClickHandler;
asIScriptFunction *onMouseOverHandler;
asIScriptFunction *onTimerHandler;
...
};



int CScriptMgr::Init()
{
...
// Register a funcdef to allow script to set callback functions

r = engine->RegisterObjectType("CGuiElement", 0, asOBJ_REF); assert( r >= 0 );
...
r = engine->RegisterFuncdef("void OnTimerHandler(int, CGuiElement @)"); assert( r >= 0 );

r = engine->RegisterObjectProperty("CGuiElement", "OnTimerHandler @onTimer", offsetof(CGuiElement, onTimerHandler)); assert( r >= 0 );
...
}

// Call the callback function

void CScriptMgr::CallGuiOnTimerHandler(asIScriptFunction *onTimerHandler, int timerId, CGuiElement *el)
{
int r;
asIScriptContext *ctx = PrepareContext(onTimerHandler->GetId());
if( ctx )
{
r = ctx->SetArgDWord(0, timerId); assert( r >= 0 );
r = ctx->SetArgObject(1, el); assert( r >= 0 );
ExecuteCall(ctx);
ReturnContextToPool(ctx);
}
}


In the script it looks like this:



void onTimer(int id, CGuiElement @el)
{
if( id == 1 && el.scale.x < 1.1 )
{
el.scale += vector2(0.05, 0.05);
el.SetTimer(0.01, 1);
if( el.scale.x > 1.1 )
el.scale = vector2(1.1, 1.1);
}
else if( id == 0 && el.scale.x > 1.0 )
{
el.scale -= vector2(0.025, 0.025);
el.SetTimer(0.01, 0);
if( el.scale.x < 1.0 )
el.scale = vector2(1.0, 1.0);
}
}


CGuiElement @CreateButton(float x, float y, const string &in text, OnClickHandler @handler)
{
CGuiElement @bt = gui.CreateElement(vector2(x,y), vector2(50,50), null);
bt.fontIndex = gui.LoadFont("menu.fnt");
bt.text = text;
@bt.onClick = handler;
@bt.onMouseOver = onMouseOver;
@bt.onTimer = onTimer;
return @bt;
}


Regards,
Andreas

Share this post


Link to post
Share on other sites
Thanks, Andreas!

This is exactly what I was thinking. It's a bit unfortunate that the asIScriptFunction *[font=monospace] [/font]pointer is passed instead of functon id is passed though since we're not exporting the asIScriptFunction class to our game library which is written in C. I'll have to think how I can workaround this.

Share this post


Link to post
Share on other sites
Observe that the asIScriptContext::Prepare() method accepts the asIScriptFunction pointer directly since version 2.22.0. With this it is actually better to store the asIScriptFunction pointer rather than the function id. The function ids will be retired in some future release.

Even though your game library is written in C there is no need to expose the full asIScriptFunction interface. You can just expose it as


typedef struct asIScriptFunction asIScriptFunction;


This is how I do it in the C interface for AngelScript (you'll find it in the add-ons).

Share this post


Link to post
Share on other sites
Hello Andreas,

yes, this is exactly what I did: export raw pointer to asIScriptFunction * to the C library and use reinterpret_cast in the wrapper library.

Thanks for the tip on asIScriptContext::Prepare(), I think I'll rename our API entry that takes function Id as an argument to PrepareById() then.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!