Ogre Vector3 and amd64

Started by
20 comments, last by WitchLord 11 years ago
Due to an obscure issue with Angelscript - because it works in Windows and *nix 32bit - it is nigh impossible to bind an Ogre::Vector3..

Of course, the Vector3 addon works a treat, both passed by value and by reference.

Ogre::Vector3 only works when passed by reference..
When passing it by value, it is lost..

I have this code to bind Ogre::Vector3:
static void Vector3DefaultConstructor(Ogre::Vector3 *self)
{
new(self) Ogre::Vector3(0,0,0);
}

static void Vector3InitConstructor(float x, float y, float z, Ogre::Vector3 *self)
{
new(self) Ogre::Vector3(Ogre::Real(x), Ogre::Real(y), Ogre::Real(z));
}

static void CopyConstructVector3(const Ogre::Vector3 &other, Ogre::Vector3 *thisPointer)
{
new(thisPointer) Ogre::Vector3(other);
}

static void DestructVector3(Ogre::Vector3 *thisPointer)
{
thisPointer->~Vector3();
}

static Ogre::Vector3 &Vector3Assignment(Ogre::Vector3 *other, Ogre::Vector3 *self)
{
return *self = *other;
}

void RegisterScriptOgreVector3(asIScriptEngine *engine)
{
int r;

r = engine->RegisterObjectType("vector3", sizeof(Ogre::Vector3), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK); assert( r >= 0 );
r = engine->RegisterObjectProperty("vector3", "float x", offsetof(Ogre::Vector3, x)); assert( r >= 0 );
r = engine->RegisterObjectProperty("vector3", "float y", offsetof(Ogre::Vector3, y)); assert( r >= 0 );
r = engine->RegisterObjectProperty("vector3", "float z", offsetof(Ogre::Vector3, z)); assert( r >= 0 );


r = engine->RegisterObjectBehaviour("vector3", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Vector3DefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("vector3", asBEHAVE_CONSTRUCT, "void f(const vector3 &in)", asFUNCTION(CopyConstructVector3), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("vector3", asBEHAVE_CONSTRUCT, "void f(float, float, float)", asFUNCTION(Vector3InitConstructor), asCALL_CDECL_OBJLAST); assert(r >= 0);


r = engine->RegisterObjectMethod("vector3", "vector3 &opAssign(vector3&in)", asFUNCTION(Vector3Assignment), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectMethod("vector3", "vector3 crossProduct(const vector3 &in) const", asMETHOD(Ogre::Vector3, crossProduct), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("vector3", "vector3 opAdd(const vector3 &in) const", asMETHODPR(Ogre::Vector3, operator+, (const Ogre::Vector3&) const, Ogre::Vector3), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("vector3", "vector3 opSub(const vector3 &in) const", asMETHODPR(Ogre::Vector3, operator-, (const Ogre::Vector3&) const, Ogre::Vector3), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("vector3", "vector3 opMul(float) const", asMETHODPR(Ogre::Vector3, operator*, (float) const, Ogre::Vector3), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("vector3", "vector3 opNeg() const", asMETHODPR(Ogre::Vector3, operator-, () const, Ogre::Vector3), asCALL_THISCALL); assert(r >= 0);

}

That code is known to work in Windows.

This is the code I use to test it:
RegisterScriptOgreVector3(mEngine);

int r;

r = mEngine->RegisterObjectType("AngelscriptTest", 0, asOBJ_REF | asOBJ_NOHANDLE); assert( r >= 0);
r = mEngine->RegisterObjectMethod("AngelscriptTest", "void quit()", asMETHOD(AngelscriptTest, quit), asCALL_THISCALL); assert( r >= 0);
r = mEngine->RegisterObjectMethod("AngelscriptTest", "void test()", asMETHOD(AngelscriptTest, test), asCALL_THISCALL); assert( r >= 0);
r = mEngine->RegisterObjectMethod("AngelscriptTest", "void setcp(vector3)", asMETHOD(AngelscriptTest, setCameraPosition), asCALL_THISCALL); assert( r >= 0);
r = mEngine->RegisterObjectMethod("AngelscriptTest", "void pv(vector3)", asMETHOD(AngelscriptTest, printVector3), asCALL_THISCALL); assert( r >= 0);
r = mEngine->RegisterObjectMethod("AngelscriptTest", "vector3 getcp()", asMETHOD(AngelscriptTest, getCameraPosition), asCALL_THISCALL); assert( r >= 0);
r = mEngine->RegisterObjectMethod("AngelscriptTest", "vector3 bv()", asMETHOD(AngelscriptTest, byValue), asCALL_THISCALL); assert( r >= 0);

// Register the singleton's address that the script will use to access it
r = mEngine->RegisterGlobalProperty("AngelscriptTest app", this); assert( r >= 0);


And it does not work on amd64.

'getcp' returns garbage.
'setcp(vector3(100,100,100))' does not set the camera position to vector3(100,100,100) but to vector3(0,0,0).

What am I missing?

It works when using references.
But that's not solving anything as I can't return/pass by reference in all places.

Too many projects; too much time

Advertisement
r=en->RegisterObjectBehaviour( "Xml",asBEHAVE_FACTORY,"Xml @f()",asFUNCTION(CXml::Factory),asCALL_CDECL);assert(r>=0);
r=en->RegisterObjectBehaviour( "Xml",asBEHAVE_ADDREF,"void f()",asMETHOD(CXml,AddRef),asCALL_THISCALL);assert(r>=0);
r=en->RegisterObjectBehaviour( "Xml",asBEHAVE_RELEASE,"void f()",asMETHOD(CXml,Release),asCALL_THISCALL);assert(r>=0);

asBEHAVE_FACTORY
asBEHAVE_ADDREF
asBEHAVE_RELEASE

rolleyes.gif
I don't see any real difference between Ogre::vector3 and the vector3 add-on. You really should be able to use them interchangeably. You should in theory even be able to register the vector3 add-on with AngelScript, and still register the methods that use Ogre::vector3 without any wrapping (though this isn't recommended).

I do see a difference in how you registered the Ogre::vector3 type though. You have registered the opAssign() method, whereas with the vector3 add-on this is not done. Since the type is registered with asOBJ_POD this is not necessary. It really shouldn't be the problem, but it might be the cause of your troubles. I suggest you try not registering this method, and see if it works.

Please let me know if doing that works, and I'll investigate why it causes an error when registering the method.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Even if I take that line out, it fails to work. :)

The correct link to Ogre::Vector3 is:
https://bitbucket.org/sinbad/ogre/src/3e643321c782/OgreMain/include/OgreVector3.h
We've moved to Mercurial some time ago.

This is odd because it works really well on Windows (and IIRC *nix 32bit too).

If I use _CA instead of _CAK I get that error that it can't be passed by value (which is correct).

I can't really spot where the difference lies between Ogre::Vector3 and Angelscript::Vector3, but I am not a technical C++ guru (unfortunately).

Too many projects; too much time

Thanks for the correct link.

I don't see the difference between the implementations that is causing the problem either. Perhaps it is the fact that Ogre::Vector3 has everything inlined, maybe the C++ compiler does something differently in this case (though I don't think it should). Are you using GNUC?

I'll see if I can reproduce the problem somehow. Though I don't really have a 64bit Linux platform to debug on. I'll have to rely on the buildbot that Jeremy set up.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

GCC 4.6.1 here.

I noticed that the operators are inlined as well. And explicit.

Maybe I should create a stand-alone Vector3 and take it for a spin with Angelscript.

Too many projects; too much time

I'd appreciate any help in isolating the cause for the problem.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

I could have sworn I saw the copy constructor on the Ogre::Vector3 class. But as I started writing the test case for reproducing the problem I discovered that for some reason Ogre::Vector3 really doesn't have a copy constructor. This means that the real flag to use when registering the type is asOBJ_APP_CLASS_CA, and not asOBJ_APP_CLASS_CAK that you were using.

This is what is causing your problem on Linux/amd64. On Linux/amd64 with GNUC a class is treated very differently if the copy constructor is declared or not. A class with a copy constructor is always passed through a reference even when the function is declared to pass the type by value. When the copy constructor is not declared, the compiler will pass the type in the CPU registers instead, if the class is small enough. The real complicated part is that when the type is passed in the CPU registers, it is split up by the type of each member, so integer members are passed in the general purpose registers, and float members are passed in the floating point registers. This is why AngelScript doesn't allow these types to be passed by value, the implementation to support that in the native calling convention is just too difficult.

You're not seeing this problem on Windows or Linux 32bit because the existence of the copy constructor or not doesn't make a difference on these platforms.



To get things to work, without changing the Ogre::Vector3 class, it is necessary to use the asOBJ_APP_CLASS_CA flag and then also change all your functions that take the Vector3 type by value in any of the parameters to take the type by reference instead. For example 'setCameraPosition(Vector3 cp)' needs to be changed to 'setCameraPosition(const Vector3 &cp)'.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Awesome!
I'll definitely try that and report back. :)

I might even file a request for enhancement in the Ogre issue tracker if they'll accept a copy constructor.
That might save people from this issue on 64bit gcc empowered platforms.

Too many projects; too much time

I added this code to Ogre::Vector3:
inline Vector3(const Vector3& other)
: x(other.x), y(other.y), z(other.z)
{
}


And this issues went away - it works! :lol:

Now I am lobbying to get that into mainstream Ogre3d - wish me luck.

Too many projects; too much time

This topic is closed to new replies.

Advertisement