[C++] Returning a float from a plugin. (SOLVED)

Started by Scavenger, Sun 20/12/2015 03:53:21

Previous topic - Next topic

Scavenger

I got a faster sine function that I want to use in AGS (gotta keep up the speed wherever I can), that I've already used internally in my plugin elsewhere, but I don't seem to be able to get AGS to recognize the floating point number as a floating point number. Here's the relevant code:

Code: C++

const char *ourScriptHeader =
  "struct PALInternal {\r\n"
  "///Polynomial Sine Approximation.\r\n"
  "import static float FastSin (float x);// $AUTOCOMPLETESTATICONLY$\r\n"
  "///Polynomial Cosine Approximation.\r\n"
  "import static float FastCos (float x);// $AUTOCOMPLETESTATICONLY$\r\n"
  "int dummy; //$AUTOCOMPLETEIGNORE$\r\n"
  "};\r\n";

float FastSin(float x)
{
  // wrap x within [0, TWO_PI)
  const float a = x * twopi_inv;
  x -= static_cast<int>(a) * twopi;
  if (x < 0.0f)
    x += twopi;

  // 4 pieces of hills
  if (x < halfpi)
    return Hill(halfpi - x);
  else if (x < PI)
    return Hill(x - halfpi);
  else if (x < 3.0f * halfpi)
    return -Hill(3.0f * halfpi - x);
  else
    return -Hill(x - 3.0f * halfpi);
}

float FastCos(float x)
{
  return FastSin(x + halfpi);
}

//later on....
  engine->RegisterScriptFunction ("PALInternal::FastSin^1", FastSin);
  engine->RegisterScriptFunction ("PALInternal::FastCos^1", FastCos);


I dunno what I have to return to get AGS to recognize this float as a float. I read through AGS' source code a bit earlier, and it... looked like floats might not actually be literally floats? What do I have to cast the result as in order for AGS to recognize it as a float? I've seen a couple of other plugins returning floats (like the AGSSteam stub), so it's gotta be possible somehow, but I'm not sure how. The code for the AGS float type is a bit intimidating.

(Also I learned today that you can declare enums in a plugin, so that's amazing)

EDIT: Whoops, sorry, I delved further into the code and managed to come up with a solution. Hopefully this can help other people as well:

Code: ags

//Add this at the top
#define SCRIPT_FLOAT(x) signed int __script_float##x
#define INIT_SCRIPT_FLOAT(x) float x; memcpy(&x, &__script_float##x, sizeof(float))
#define FLOAT_RETURN_TYPE signed int
#define RETURN_FLOAT(x) signed int __ret##x; memcpy(&__ret##x, &x, sizeof(float)); return __ret##x


//Wrap functions so that they return a "float".
FLOAT_RETURN_TYPE AGSFastSin (SCRIPT_FLOAT(x))
{
	INIT_SCRIPT_FLOAT (x);
	x = FastSin (x);
	RETURN_FLOAT (x);
}

FLOAT_RETURN_TYPE AGSFastCos (SCRIPT_FLOAT(x))
{
	INIT_SCRIPT_FLOAT (x);
	x = FastSin (x+halfpi);
	RETURN_FLOAT (x);
}

Wyz

This is how I've done it in the past:
Code: ags

#define RETURN_AGS_FLOAT(x) return *((int32 *) &(x))
#define AGS_FLOAT(x) (*((float *) &(x)))

// Somewhere else:
int32 AGSFastSin(int32 x)
{
    RETURN_ARGS_FLOAT(FastSin(AGS_FLOAT(x)));
}


There are however a few caveats. Note that int32 is defined in the plugin header as long; in AGS script all primitives are passed as longs. This assumes that a float takes up 32 bits on a 32-bit system; this will cause problems on 64-bit system probably so this is something to think about. It is hard to advise something here since it will depend on the target platform.
Btw, it might be a better idea to use static casts in de macros for C++, or not use macros at all ;).
Life is like an adventure without the pixel hunts.

Crimson Wizard

Quote from: Wyz on Mon 21/12/2015 16:20:22
There are however a few caveats. Note that int32 is defined in the plugin header as long; in AGS script all primitives are passed as longs. This assumes that a float takes up 32 bits on a 32-bit system; this will cause problems on 64-bit system probably so this is something to think about. It is hard to advise something here since it will depend on the target platform.
Btw, it might be a better idea to use static casts in de macros for C++, or not use macros at all ;).

"Long" is 32-bit on all Windows systems, but has varied size on Linux systems.

Better change it to
Code: cpp

typedef int32 int;


The script engine only lets 32-bit values through anyway.

The presence of "long" in the code is an old mistake, and we removed most of longs from engine code long (pun) ago.

Wyz

Hmm I see; well that is not really a problem then on windows systems. It might be a good idea to switch to int32_t at some point actually if it must be 32-bit; support is about there these days. I'll keep this in mind for my plugins in the future. :)
Life is like an adventure without the pixel hunts.

monkey0506

#4
I wasn't aware that this was an issue! 8-0

I will no go ahead and replace all of the floats in the AGSteam, AGSteamStub, and AGSGalaxy plugins. ;)

EDIT: Done! (This AGS2Client interface is making this process so much easier!)

Btw, you also should never use bool in any function you are registering with RegisterScriptFunction. I learned that the hard way.

SMF spam blocked by CleanTalk