• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
jacmoe

Ogre Vector3 and amd64

21 posts in this topic

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:
[code] 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);

}
[/code]
That code is known to work in Windows.

This is the code I use to test it:
[code] 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);
[/code]

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.
0

Share this post


Link to post
Share on other sites
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

[img]http://public.gamedev.net/public/style_emoticons/default/rolleyes.gif[/img]
0

Share this post


Link to post
Share on other sites
I don't see any real difference between [url="http://ogre.svn.sourceforge.net/viewvc/ogre/trunk/OgreMain/include/OgreVector3.h?revision=9491&view=markup"]Ogre::vector3[/url] 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
1

Share this post


Link to post
Share on other sites
Even if I take that line out, it fails to work. :)

The correct link to Ogre::Vector3 is:
[url="https://bitbucket.org/sinbad/ogre/src/3e643321c782/OgreMain/include/OgreVector3.h"]https://bitbucket.org/sinbad/ogre/src/3e643321c782/OgreMain/include/OgreVector3.h[/url]
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).
0

Share this post


Link to post
Share on other sites
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.
1

Share this post


Link to post
Share on other sites
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.
0

Share this post


Link to post
Share on other sites
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)'.
1

Share this post


Link to post
Share on other sites
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.
0

Share this post


Link to post
Share on other sites
I added this code to Ogre::Vector3:
[code] inline Vector3(const Vector3& other)
: x(other.x), y(other.y), z(other.z)
{
}
[/code]

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

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

Share this post


Link to post
Share on other sites
Alternatively, I could just cast between Ogre::Vector3 and my own version of it (with an explicit copy constructor), but I'd rather not.

Maybe this could be added to the documentation somewhere?
That a POD needs to have an explicit copy constructor on 64bit *nix?
0

Share this post


Link to post
Share on other sites
They refused to add the explicit copy constructors to Ogre core, so I need to work around it. :)


Passing this flag to GCC will turn off the value to reference optimization trick I think:
[code]-fno-ipa-sra[/code]

[quote]-fipa-sra
Perform interprocedural scalar replacement of aggregates, removal of unused parameters and replacement of parameters passed by reference by parameters passed by value.

Enabled at levels -O2, -O3 and -Os. [/quote]

Don't know if it works, though.

I think I'll just use some ugly casts between Angelic proxy classes and Ogre's POD classes instead.

Do I have to teach Angelscript how to handle that?
0

Share this post


Link to post
Share on other sites
Did the Ogre team by any chance state the reason why they don't want to include the copy constructor? I'm curious as to whether they have a specific reason, or just that don't really see it as a problem in their code (which it isn't).

If you cannot use your own custom version of Ogre::Vector3, or change the methods that take the Vector3 type by value to take them by reference (note, it should still be possible to return the type by value), then the only other solution is to use function wrappers. For this, I believe you can use the auto wrappers, that you'll find in the add-ons.

[source]
// Example

#include "add_on/autowrapper/aswrappedcall.h"

// Implemente a method wrapper for the class method that takes the Ogre::Vector3 type by value in parameter
asDECLARE_METHOD_WRAPPER(AngelScriptTest_setCameraPosition_Wrapper, AngelScriptTest, setCameraPosition);

...

// Register the wrapper, instead of the real method
r = mEngine->RegisterObjectMethod("AngelscriptTest", "void setcp(vector3)", asFUNCTION(AngelscriptTest_setCameraPosition_Wrapper), asCALL_GENERIC); assert( r >= 0);
[/source]

This only needs to be done for the functions and class methods that take the Vector3 by value. Other functions and methods can be registered normally without any wrappers.
1

Share this post


Link to post
Share on other sites
It was deemed not kosher by a team member:
[url="http://www.ogre3d.org/forums/viewtopic.php?f=22&t=65876"]http://www.ogre3d.org/forums/viewtopic.php?f=22&t=65876[/url]

A shame. ;)

I will try your suggestion.
Thanks a lot for your patience. :)
0

Share this post


Link to post
Share on other sites
I read the thread over at Ogre. While I feel it is a pity they didn't want add the copy constructor, I can't really say I blame them. After all, they are not doing anything wrong by leaving it as an implicit copy constructor. And who knows, it may even cause a minor performance impact if the copy constructor is added, as it would prevent the GCC compiler from passing the type in the CPU registers.

If possible I'll add support for these kind of types in AngelScript. After all, it is quite common structure (i.e. all members are float).
1

Share this post


Link to post
Share on other sites
[quote name='jacmoe' timestamp='1311956678' post='4842214']
It was deemed not kosher by a team member:
[url="http://www.ogre3d.org/forums/viewtopic.php?f=22&t=65876"]http://www.ogre3d.or...hp?f=22&t=65876[/url]

A shame. ;)

I will try your suggestion.
Thanks a lot for your patience. :)
[/quote]

Wow. Their acerbic response is a little bit distasteful for a fix that is so simple, but provides so much to some of their user-base. Not to mention, it wouldn't be the first time they disregarded standards-compliant behavior for a non-standard compiler implementation. Has anyone in that topic seen[u] [/u][url="http://www.ogre3d.org/docs/api/html/OgreSingleton_8h_source.html"]OgreSingleton.h[/url]?

[code]

Singleton( void )
{
assert( !ms_Singleton );
#if defined( _MSC_VER ) && _MSC_VER < 1200
int offset = (int)(T*)1 - (int)(Singleton <T>*)(T*)1;
ms_Singleton = (T*)((int)this + offset);
#else
ms_Singleton = static_cast< T* >( this );
#endif
}
[/code]

In fact, it's a simple as implementing the following code in any offending classes:
[code]

//
// Provide an explict copy-constructor for GCC 4.6.1 on 64-bit Linux architectures
// (in-depth explanation here)
//
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX && \
OGRE_ARCH_TYPE == OGRE_ARCHITECTURE_64 && \
OGRE_COMPILTER == OGRE_COMPILER_GCC && \
OGRE_COMP_VER > 461 // (assume version greater than 4.6.1 exhibit the same behavior
inline Vector3(const Vector3& other)
: x(other.x), y(other.y), z(other.z)
{
}
#endif
[/code]
There they go. A standards-compliant version of the class for standard-compliant compilers, and a non-standard-compliant version for non-standard versions. It's really quite simple. This small fix wouldn't decrease maintainability in the least, and the increase in line count is hardly noticeable.That entire thread put a bad taste in my mouth. But hey, I guess I'm not on the Ogre development team for a reason.
1

Share this post


Link to post
Share on other sites
Thanks a lot for that post, Halifax2.
My thoughts exactly. :wink:
1

Share this post


Link to post
Share on other sites
[quote name='WitchLord' timestamp='1311961326' post='4842245']
I read the thread over at Ogre. While I feel it is a pity they didn't want add the copy constructor, I can't really say I blame them. After all, they are not doing anything wrong by leaving it as an implicit copy constructor. And who knows, it may even cause a minor performance impact if the copy constructor is added, as it would prevent the GCC compiler from passing the type in the CPU registers.[/quote]
*Them* is one team member. Don't expect a reply from anyone else.
And, yes: it is a pity.

I am aware of the possible performance impact, of course..

[quote name='WitchLord' timestamp='1311961326' post='4842245']If possible I'll add support for these kind of types in AngelScript. After all, it is quite common structure (i.e. all members are float).
[/quote]
That would be lovely. :)
0

Share this post


Link to post
Share on other sites
Using the autowrapper works! :lol:

I'll let you know when I'm done modifying the real code, but it does work a treat in my test project. :)

Thank you Andreas - you're the best. :P

<edit>
[code]asDECLARE_METHOD_WRAPPER(AngelscriptTest_getCameraPosition_Wrapper, AngelscriptTest, getCameraPosition); [/code]
and
[code] // Register the wrapper, instead of the real method
r = mEngine->RegisterObjectMethod("AngelscriptTest", "vector3 getcp()",
asFUNCTION(AngelscriptTest_getCameraPosition_Wrapper),
asCALL_GENERIC); assert( r >= 0);[/code]
0

Share this post


Link to post
Share on other sites
I've added an additional flag asOBJ_APP_ALLFLOATS that when used with the registration of the Ogre::Vector3 should allow you to use this type in native functions without wrappers. It tells AngelScript that the class consists only of floats, and will thus allow AngelScript to know that the type is returned in the XMM registers instead of the general purpose registers.
1

Share this post


Link to post
Share on other sites

I know it's late, but after fighting with Angelscript and Ogre on 64-bit Linux for way too long, I hereby report that the issue has been fixed! biggrin.png

 

 

 

        r = engine->RegisterObjectType("Vector3", sizeof(Ogre::Vector3), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CA | asOBJ_APP_CLASS_ALLFLOATS); assert( r >= 0 );

 

the all floats flag did indeed fix the issues smile.png

Instead of just asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK.

 

Had to do the same thing to Quaternion.

 

 

I never thought I'd live to see it work..

 

Thanks a bunch Andreas Jonsson!

Edited by jacmoe
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0