Advertisement

Registrating one's Superclass

Started by June 10, 2009 06:32 AM
17 comments, last by _matthias_ 15 years, 5 months ago
Quote: Original post by _matthias_
But this double registrating would be autmatically made by your template construction, doesn't it?


Actually not. If you look carefully, you'll see that the registering the derived class first calls the function for registering the base class' methods, and then only register the new methods introduced by the derived class. It doesn't register the methods it inherits more than once.



Quote: Original post by _matthias_
Are you of the opinion, that all these could be possible with Angelscript ?


Yes, definitely. And also quite easily. SiCrane already showed how to enumerate the properties of a class, and I'll also help you clear up any questions you might have.

Be sure to let me know if you need some feature that is not available in AngelScript, and I'll see what I can do to add it in a future release.



Quote: Original post by _matthias_
By the way another question to Angelscipt:
How fast could Angelscript be in calling highly frequently a simple function like "float wave(float x, float y) { return sin(sqrt(x^2+y^2)); }" , which is used in this sample ( by the Scriptlanguage Lua):

Makes it sense to animate this with angelscript ?



Lua has more people working on it, and has also been around for a much longer time, but I'm willing to bet that even if AS is not currently as fast or faster than Lua in this example, I can easily optimize it to be so. I'm not saying this because I think I'm better than the developers of Lua (which would probably not be true), but rather that AS allows it to be executed much faster due to being statically typed, rather than dynamically typed. There are just less things to do at run time. (LuaJIT is another matter though, as it will produce machine code rather than byte code)

Please let me know if you find that AngelScript is slower, and I'll put in an effort to add some more optimizations.

I look forward to seeing more on your work with AngelScript.

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

After some stressfull days I' m in touch now.

I' tried to do a benchmarktest with Lua and AngelScript.

The Code for the while-loop is as the follow (AngelScript only):
// Initialize Values	QueryPerformanceCounter((LARGE_INTEGER*)&LastCount);	QueryPerformanceCounter((LARGE_INTEGER*)&CurCount);	curFrame = 0;	// This while loop will be run until one second is over	while(CurCount - LastCount < Frequency) {		curFrame++;		// Every 10000th time look, if one second is over		if(curFrame % 10000 == 0) QueryPerformanceCounter((LARGE_INTEGER*)&CurCount);		r = ctx->Prepare(funcId);		// Now we need to pass the parameters to the script function. 		ctx->SetArgFloat(0, value_1);		ctx->SetArgFloat(1, value_2);		ctx->SetArgFloat(2, value_3);		// Execute		r = ctx->Execute();		if( r != asEXECUTION_FINISHED )		{			// The execution didn't finish as we had planned. Determine why.			if( r == asEXECUTION_ABORTED )				cout << "The script was aborted before it could finish. Probably it timed out." << endl;			else if( r == asEXECUTION_EXCEPTION )			{				cout << "The script ended with an exception." << endl;				// Write some information about the script exception				int funcID = ctx->GetExceptionFunction();				asIScriptFunction *func = engine->GetFunctionDescriptorById(funcID);				cout << "func: " << func->GetDeclaration() << endl;				cout << "modl: " << func->GetModuleName() << endl;				cout << "sect: " << func->GetScriptSectionName() << endl;				cout << "line: " << ctx->GetExceptionLineNumber() << endl;				cout << "desc: " << ctx->GetExceptionString() << endl;			}			else				cout << "The script ended for some unforeseen reason (" << r << ")." << endl;		}	}

The most of the Lines are copied from the documentation.

But the results are, as far as I made no mistakes, quite good for AngelScript.
This function in AngelCode:
float wave(float x, float y, float t) {   return sin(sqrt(x*x+y*y));}

was called 460 000 times per second.

A similar function in Lua was called 260 000 times per socond.

The results are rounded by 10 000.( See in the Code^^)

Another usue:

I'm writing an German articel about AngelScript in Wikipedia.org, do you allow me to use code-samples and images from your website therefor ?





Advertisement
I'm pleased to see that AngelScript is really faster than Lua. From what I can tell, you're doing everything correctly. *(float*)ctx->GetArgPointer(0) = value; is slightly faster than using ctx->SetArgFloat(0, value);, but I don't think changing this will show any noticeable difference.

However, if you build the AngelScript library without multithread support you'll get an extra boost in performance. If you also set the engine property asEP_BUILD_WITHOUT_LINE_CUES you can get even more speed. Obviously, you need to evaluate if you don't need the stuff you disable by this.

If you really need it, I'm sure I can optimize the library even further.


As for the question about Wikipedia, yes, you may use samples and images from my site if you wish.

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

After a little practice with Angelscript I came to one problem:

I tried to registrate a class, heritated from a base class, as you have shown at in the documantation:

I' m not sure what Flags I should use for registrating the Object-Types so I wrote these lines of code:
void RegisterTypes(asIScriptEngine *engine){  int r;  // Register the base type  r = engine->RegisterObjectType("base", sizeof(Base), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CA); assert( r >= 0 );  RegisterBaseMembers<Base>(engine, "base");  // Register the derived type  r = engine->RegisterObjectType("derived", sizeof(Derived), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CA); assert( r >= 0 );  RegisterDerivedMembers<Derived>(engine, "derived");}


Registrations:
template <class T>void RegisterBaseMembers(asIScriptEngine *engine, const char *type) {	int r;	r = engine->RegisterObjectMethod(type, "void IncreasePropertys()", asMETHOD(T, IncreasePropertys), asCALL_THISCALL); assert( r >= 0 );	r = engine->RegisterObjectProperty(type, "int BaseProperty", offsetof(T, BaseProperty)); assert( r >= 0 );	r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(BaseDefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );	r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f(const base &in)", asFUNCTION(BaseCopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );	r = engine->RegisterObjectBehaviour(type, asBEHAVE_DESTRUCT, "void f()", asFUNCTION(BaseDestructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );}
''And for the derived class''
template <class T>void RegisterDerivedMembers(asIScriptEngine *engine, const char *type) {	int r;	RegisterBaseMembers<T>(engine, type);	r = engine->RegisterObjectProperty(type, "int DerivedProperty", offsetof(T, DerivedProperty)); assert( r >= 0 );	r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(DerivedDefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );	r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f(const derived &in)", asFUNCTION(DerivedCopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );	r = engine->RegisterObjectBehaviour(type, asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DerivedDestructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );}


Everythig works but registrating derives destructer makes assertion failing.
Registrating constructers twice does not matters, but destructer does.^^
How can I solve this problem ?
I'm not sure what you're trying to do is supported by AngelScript. According to the documentation page you linked to:
Quote: Hierarchies can currently only be registered for reference types, not for value types.

You can't register the behaviours inside the RegisterBaseMembers and RegisterDerivedMembers. It doesn't make sense to register the Base class' constructors and destructor for the Derived class.

If you don't want to split the registration in two functions, then you could pass a flag to the function to tell if the behaviours should be registered or not.

template <class T>void RegisterBaseMembers(asIScriptEngine *engine, const char *type, bool registerDerived) {	int r;	r = engine->RegisterObjectMethod(type, "void IncreasePropertys()", asMETHOD(T, IncreasePropertys), asCALL_THISCALL); assert( r >= 0 );	r = engine->RegisterObjectProperty(type, "int BaseProperty", offsetof(T, BaseProperty)); assert( r >= 0 );	if( !registerDerived )	{		r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(BaseDefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );		r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f(const base ∈)", asFUNCTION(BaseCopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );		r = engine->RegisterObjectBehaviour(type, asBEHAVE_DESTRUCT, "void f()", asFUNCTION(BaseDestructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );	}}


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

Advertisement
But what if I don't know whether a method or behaviour should be overload.

How can I registrate the following classse in the shortest and dynamicly way ?

[source lang=cpp]class base{public:   base() : valueBase(23) {}   ~base() {}   virtual int GetSumOfAllProperties() {return valueBase; }   protected:   int valueBase;};class derived_1 : base{public:   derived_1() : base(),valueDerived(12)  {}   ~derived_1() {}   virtual int GetSumOfAllProperties() {return valueBase+valueDerived; }protected:   int valueDerived;};class derived_2 : base{public:   derived_2() : base()  {}   ~derived_2() {}   virtual int GetSumOfAllProperties() {return valueBase; }   void SetBaseProperty(int value) { valueBase = value; }};


Of curse this Code deos not make real sense, but it shows what I need.

In my case I get the Error Message: "Multiple matching signatures to ...".
I would be glad, if AngelScript would only use the last registrated method.
This would make some things easier.

You don't need to know if a method is being overloaded or not. You just need to know what class implements the function first.

The following ought to work:

template <class T>void Constructor(void *memory){  // Initialize the pre-allocated memory by calling the  // object constructor with the placement-new operator  new(memory) T();}template <class T>void Destructor(void *memory){  // Uninitialize the memory by calling the object destructor  ((T*)memory)->~T();}template <class T>void RegisterCommonBase(asIScriptEngine *engine, const char *type) {	int r;        // If the constructor and destructor behaviours are implemented         // through a templated wrapper, we can actually register them        // with one common function.	r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCTOR, "void f()", asFUNCTION((Constructor<T>)), asCALL_CDECL_OBJLAST);	r = engine->RegisterObjectBehaviour(type, asBEHAVE_DESTRUCTOR, "void f()", asFUNCTION((Destructor<T>)), asCALL_CDECL_OBJLAST);        	r = engine->RegisterObjectMethod(type, "int GetSumOfAllProperties()", asMETHOD(T, GetSumOfAllProperties), asCALL_THISCALL); assert( r >= 0 );}void RegisterBase(asIScriptEngine *engine){  int r;  r = engine->RegisterObjectType("base", sizeof(base), asOBJ_VALUE | asOBJ_APP_CLASS_CD);  RegisterCommonBase<base>(engine, "base");}void RegisterDerived_1(asIScriptEngine *engine){  int r;  r = engine->RegisterObjectType("derived_1", sizeof(derived_1), asOBJ_VALUE | asOBJ_APP_CLASS_CD);  RegisterCommonBase<derived_1>(engine, "derived_1");  // derived_1 doesn't implement any new methods/behaviours, so there's nothing more to do}void RegisterDerived_2(asIScriptEngine *engine){  int r;  r = engine->RegisterObjectType("derived_2", sizeof(derived_2), asOBJ_VALUE | asOBJ_APP_CLASS_CD);  RegisterCommonBase<derived_2>(engine, "derived_2");  // Register the new methods that derived_2 implements  r = engine->RegisterObjectMethod(type, "void SetBaseProperty(int)", asMETHOD(derived_2, SetBaseProperty), asCALL_THISCALL); assert( r >= 0 );}


Since C++ doesn't let you take the address of the constructor or destructor these need a wrapper function. By implementing the wrapper with a template you can actually reuse the registration code for these as well as seen above. I know, this contradicts what I said in the earlier post. ;)

It is an error to register the same method twice. AngelScript really should give an error when this is done, but I haven't implemented that check yet. I can't remove the compiler error in this case, because there is really no way of knowing that the error is caused because you knowingly registered the same function twice (which you shouldn't have done, in the first place). In your case, it would have worked, but consider the case when the registration is done from dynamically loaded plugins that you don't have much control over. In this case it might be disastrous to allow the multiple functions, since the two function may actually do completely different things.

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

Ah now I see what you mean. I agree with you - sorry I'm not as familiar with template-coding as you ;)

Thank you for this hint !

This topic is closed to new replies.

Advertisement