Home » Community » Forums » AngelCode » Application Registered Classes
  Intel sponsors gamedev.net search:   
[Control Panel] [Register] [Bookmarks] [Who's Online] [Active Topics] [Stats] [FAQ] [Search]

Add Forum to Favorites |  Send Topic To a Friend | View Forum FAQ | Track this topic


 Last Thread Next Thread 
 Application Registered Classes
Post New Topic  Post Reply 
First of all I would like to thank WitchLord for AngelScript. I decided to use AngelScript as the scripting engine for my current project. I certainly don't regret that decision; it was very easy to integrate AngelScript within my project. Unfortunately, it looks like I've run into a problem. Well, it isn't exactly a problem, but rather a feature that I miss. You see, I would like to create classes derived from application registered classes. There are of course other methods to implement similar functionalities, but an implementation based upon inheritance would be much easier and elegant.

Judging from the AngelScript website the idea to inherit from application classes is known, but it isn't a big priority at the moment (correct me, if I'm wrong). That isn't a problem though as I'm willing to look at the problem myself. Whether I'll succeed is another question, but I think it's worth a try.

Now, I've been looking around a little bit to investigate what is preventing application registered classes from being derivable. I came across the next text-fragement:

Quote:

A common super class for all script classes
Maybe a super class for all script classes can be implemented. The super class, won't have any properties or methods. It is only used as a common base, so that all classes can be stored in a common way. It could also be seen as an interface that all classes implement.

Potential drawback: Application registered classes won't always be derived from the super class, thus separating them from the script classes.

Advantage: All script classes will have a common denominator, facilitating the storage of them. An application registered class that derive from an AngelScript class interface, can be registered to have this same common denominator which should make it possible to have script classes inherit from application registered classes.


From this text-fragment I gather that AngelScript uses different classes for classes registered within AngelScript and classes registered by the application. If this assumption is right, then which classes are meant? I already looked at the source code, but I figured out it would be faster if I would ask it.

Thanks in advance.



.simplicity - blog | Sirrf - Simple Irrlicht Framework

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

I'm very pleased to hear that you like AngelScript. I look forward to seeing what you'll do with it. Don't forget to let me know once you're ready to show your product, so that I can add it to the users list.

Allowing script classes to inherit from application classes would indeed be a useful feature and one that intend to look into in the future. But as you already noted, it is a rather low priority for me at the moment as there are so many other features that I believe are far more useful that can be implemented before that.

Another reason why I haven't spent much time investigating this feature, is that I have my doubts about how well it will work, and I do not want to implement a feature that will only work halfway. It would only leave the users wanting more, and I wouldn't be able to give it to them.

Anyway, I'll gladly support your efforts in this regards by helping out where I can. If it works out well it be happy to incorporate it into the library.

Script classes are implemented by the asCScriptObject. This class holds all the behaviours that are common to all script classes, as well as a pointer to the asCObjectType which holds the extra information, such as properties and methods declared by the script. The properties declared for the class by the script are allocated together with the asCScriptObject simply by allocating sizeof(asCScriptObject) + sizeof(properties) number of bytes.

I believe that the easiest way to allow the script class to inherit from the application class, is if the application class first inherits from the asCScriptObject. That way the script engine can treat these classes just as any other script classes.

It would also be possible to pass these script classes back to the application, and having the application treating the class normally (except that the application would be able to to easily call the class methods expecting to call the methods that script class overloads).

Classes registered by the application are just that. The script engine doesn't wrap them in anyway, and accesses the methods and properties directly. It would be possible to implement inheritance for these classes too, if the script engine wrapped them in a special class. This would allow the VM to call methods on the wrapped class and any class that inherits from it the same way, without having to know exactly what class it is working on. The biggest problem with this, is that the wrapped class obviously can't be passed back to the application as if it was the original class. Another problem is that all the application classes would have to be wrapped the same way, which would add a lot of overhead to the scripts.

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


 User Rating: 1702   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

That makes everything definitely a lot more clear.

I think I'm first going to try the option where application classes themselves inherit from asCScriptObject. It sounds indeed like the easiest way to enable inheritance from application registered classes.

Well, it's a starting point; time to work.



.simplicity - blog | Sirrf - Simple Irrlicht Framework

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Depending on your needs you want to try a script side only tactic. Basically, if you have an application registered class Foo that looks like:
class Foo {
  public:
    Foo();
    Foo(int a, int b);

    void bar(void);
    int baz(int a);

    // etc.
};

Register the class with a name like FooInner and then create a script class that looks like:
class Foo {
  FooInner inner;
  Foo() { inner = Foo(); }
  Foo(int a, int b) { inner = Foo(a, b); }

  void bar(void) { inner.bar(); }
  int baz(int a) { return inner.baz(a); }

  // etc.
}

Then you can derive your classes from the script Foo class. It won't work perfectly for all situations, but it might be a "good enough" solution.

 User Rating: 2061   |  Rate This User  Send Private MessageView ProfileView JournalView GD Showcase Entries Report this Post to a Moderator | Link

That is basically what I had in mind when I described how inheritance for arbitrary registered classes might work. If I'm not mistaken this is also called composite inheritance.



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


 User Rating: 1702   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

That's indeed an interesting solution, but I would actually be interested in passing back derived classes to the application. So, I'm afraid the solution is not "good enough". For cases of inheritance where this kind of behaviour is unneeded, I can see this working though.

That being said, I've been studying how AngelScript deals with asCScriptObject and asCScriptType internally. I noticed that when asCScriptEngine::RegisterObjectType is being called, a new instance of asCObjectType is being created. I take that this is needed to the methods of the class? If this is the case, then would that mean that the asCObjectType instance could be "attached" to an application based class derived from asCScriptObject? As script based classes do that too.

Furthermore I noticed that the asOBJ_SCRIPT_OBJECT flag is passed to asCObjectType objects created from script bases classes. I already saw that any objects that don't have this flag, application side classes, can't be inherited from through AngelScript. Would application side classes also have to declare this flag, or should the check for asOBJ_SCRIPT_OBJECT be removed or adapted?

And one more question. I've been looking for the piece of code where asCScriptObject instances are being created. I already looked at asCBuilder::CompileClasses, but I didn't find it. Either I overlooked it or I looked at the wrong place. I figured that it would help me to know this, as application registered classes which are derived from asCScriptObject would have to be created in the same way.

Oh, and if I'm taking unnecessary steps then please tell me.



.simplicity - blog | Sirrf - Simple Irrlicht Framework

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

You can pass objects back to the application with some work:
class FooScript : public Foo {
  public:
    FooScript(asIScriptObject * obj) : obj_(obj) { obj->AddRef(); }
    ~FooScript() { obj_->Release(); }
    
    virtual void bar(void) {
      asIObjectType * type = obj_->GetObjectType();
      int id = type->GetMethodIdByDecl("void bar()");
      asIScriptEngine * engine = obj_->GetEngine();
      asIScriptContext * ctx = engine->CreateContext();
      ctx->Prepare(id);
      ctx->SetObject(obj_);
      ctx->Execute();
      ctx->Release();
    }
    
    virtual int baz(int a) {
      asIObjectType * type = obj_->GetObjectType();
      int id = type->GetMethodIdByDecl("int baz(int)");
      asIScriptEngine * engine = obj_->GetEngine();
      asIScriptContext * ctx = engine->CreateContext();
      ctx->Prepare(id);
      ctx->SetObject(obj_);
      ctx->SetArgDWord(0, a);
      ctx->Execute();
      int to_return = ctx->GetReturnDWord();
      ctx->Release();
      return to_return;
    }

    // etc.
  private:
    FooScript(const FooScript &);
    FooScript & operator=(const FooScript &);
    
    asIScriptObject * obj_;
};

There are, admittedly, still at least three flaws with this. The first is that it doesn't play nicely with member variables, though this can be addressed with get/set property functions. The second is that I'm not sure how to check to make sure the script object actually inherits from the base class. There's a mechanism for checking implemented interfaces, but it doesn't look like there's a way to check for base classes. And, of course, there's a lot of manual boiler plate code.

I've been playing with the idea of using my reflection engine in my .NET project to automagically generate both the script and communication classes, but I haven't had the chance to put a lot of time into the idea.

 User Rating: 2061   |  Rate This User  Send Private MessageView ProfileView JournalView GD Showcase Entries Report this Post to a Moderator | Link

Quote:
Original post by ZCCdark203
That being said, I've been studying how AngelScript deals with asCScriptObject and asCScriptType internally. I noticed that when asCScriptEngine::RegisterObjectType is being called, a new instance of asCObjectType is being created. I take that this is needed to the methods of the class? If this is the case, then would that mean that the asCObjectType instance could be "attached" to an application based class derived from asCScriptObject? As script based classes do that too.


The asCObjectType holds the description of the class, i.e. what behaviours it implements, what properties and members it has, and so on. All non-primitive types have an asCObjectType. Application registered classes don't need the asCObjectType for run-time operation, but script classes do, as they need to dynamically determine the details of the type.

Application classes that derive from asCScriptObject may not have to include a reference to asCObjectType in each instance, but it needs to reserve the space so that script classes that inherit from it can use that space for its own asCObjectType.

Quote:

Furthermore I noticed that the asOBJ_SCRIPT_OBJECT flag is passed to asCObjectType objects created from script bases classes. I already saw that any objects that don't have this flag, application side classes, can't be inherited from through AngelScript. Would application side classes also have to declare this flag, or should the check for asOBJ_SCRIPT_OBJECT be removed or adapted?


The application classes that inherit from asCScriptObject can probably use the asOBJ_SCRIPT_OBJECT flag too. I'm not sure if another flag is necessary to identify these 'hybrid' classes, that depends on you encountering any situation where you need to be able to diferenciate between the types.

Quote:

And one more question. I've been looking for the piece of code where asCScriptObject instances are being created. I already looked at asCBuilder::CompileClasses, but I didn't find it. Either I overlooked it or I looked at the wrong place. I figured that it would help me to know this, as application registered classes which are derived from asCScriptObject would have to be created in the same way.


I'm not sure if application registered classes which are derived from asCScriptObject needs to be instanciated the same way as the script classes. This depends on if the class constructor has everything at compile time, or if you need to pass a asCObjectType to the constructor for extra information at run-time.

Anyway, the script classes are instanciated with asIScriptObject *ScriptObjectFactory(asCObjectType *objType, asCScriptEngine *engine) that you'll find in as_scriptstruct.cpp.

The factory behaviour for the script classes are stubs functions generated by the script compiler to allocate the memory and then call the script class' constructor to initialize it. There is one factory stubs for each script class constructor. These factory stubs are generated in int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)


Quote:
Oh, and if I'm taking unnecessary steps then please tell me.


You seem to be on the right track so far.

Regards,
Andreas

 User Rating: 1702   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Quote:
Original post by SiCrane
You can pass objects back to the application with some work:

class FooScript : public Foo {
  ...



Would the application register the FooScript class instead of Foo then?

Quote:

The second is that I'm not sure how to check to make sure the script object actually inherits from the base class. There's a mechanism for checking implemented interfaces, but it doesn't look like there's a way to check for base classes.


There is the asIObjectType::GetBaseType method.




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


 User Rating: 1702   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Quote:
Original post by WitchLord
Would the application register the FooScript class instead of Foo then?

No, it'd register Foo. And then use the asIScriptObject * for a FooInner script object (or one of the derived classes) to create a new FooScript object to be used wherever pointers or references to Foos would be used. So you'd have something like:
  Foo * get_foo_property(asIScriptObject * obj, int prop) {
    asIScriptObject * foo_inner = static_cast<asIScriptObject *>(obj->GetPropertyPointer(prop));
    return new FooScript(foo_inner);
  }


Quote:
There is the asIObjectType::GetBaseType method.

Ok, I'm blind. Thanks.


 User Rating: 2061   |  Rate This User  Send Private MessageView ProfileView JournalView GD Showcase Entries Report this Post to a Moderator | Link

Again, that's a pretty interesting solution you got there. I could actually imagine AngelScript generating the Foo and FooInner structures internally when a object is registered. Then the end-user would only have to define the FooScript class and the get_foo_property function (which could be passed as a behaviour to AngelScript). But the question is whether this overhead is required for every application registered class. Maybe the end-user could pass a flag (asOBJ_INHERITABLE or something similar) to explicitly say whether an application registered class should be inheritable or not. That way the extra overhead for application registered classes that don't use inheritance could be prevented. Variables remain a tricky part, though.



.simplicity - blog | Sirrf - Simple Irrlicht Framework

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Registering get_foo_property() as a behavior wouldn't make much sense; it's specific just to reading a script object's member variable as a Foo *. You might be able to justify a behavior mapping any asIScriptObject * to a derived type, but I think it'd probably just be confusing with asIScriptObject *'s already being returned as void *'s.

Thinking about it, if Foo has member variables, then I'd create a interface class IFoo and derive Foo from IFoo and derive FooScript from IFoo rather than Foo. That way at least you wouldn't duplicate the variables needlessly. The interface could have getters/setters if necessary. This would probably be more elegant once getter/setters for properties get implemented in AngelScript, which is something I've wanted for a while, but for different reasons. If Foo already only contains pure virtual functions, then creating the FooInner machinery wouldn't be necessary, just the FooScript side along with possibly registering the interface with the existing AngelScript interface mechanisms. It might be worthwhile to put together a template framework to simplify generating FooScript like classes.

Though if I ever need to talk about this technique again, I'll really need to think of better terms than Foo, FooInner, FooScript, etc. I'm starting to confuse myself.

 User Rating: 2061   |  Rate This User  Send Private MessageView ProfileView JournalView GD Showcase Entries Report this Post to a Moderator | Link

Here's some proof of concept code for whole Foo/IFoo/FooScript thing with some template voodoo to reduce the amount of code inside FooScript-like classes.
#include "angelscript.h"
#include "scriptstring.h"

#include <iostream>
#include <cassert>
#include <cstdio>

//------------------------------------------------------------------------------
// Helper framework

template <typename T>
struct CallHelper {
  T element;
  CallHelper(T t) : element(t) {}
};

class ScriptObjectCallBase {
  public:
    ScriptObjectCallBase(const char * decl, asIScriptObject * obj) {
      asIScriptEngine * engine = obj->GetEngine();
      ctx_ = engine->CreateContext();
      asIObjectType * type = obj->GetObjectType();
      int id = type->GetMethodIdByDecl(decl); assert(id >= 0);
      ctx_->Prepare(id);
      ctx_->SetObject(obj);
    }
    
    ScriptObjectCallBase(const ScriptObjectCallBase & other) {
      ctx_->AddRef();
    }
    
    ScriptObjectCallBase & operator=(const ScriptObjectCallBase & other) {
      other.ctx_->AddRef();
      ctx_->Release();
      ctx_ = other.ctx_;
    }
    
    ~ScriptObjectCallBase() {
      ctx_->Release();
    }
  protected:
    void execute(void) {
      int r = ctx_->Execute(); assert(r >= 0);
    }
    void * return_address(void) {
      return ctx_->GetAddressOfReturnValue();
    }
    template <typename T>
    void set_arg(asUINT arg, T t) {
      new (ctx_->GetArgPointer(arg)) CallHelper<T>(t);
    }
   
  private:
    asIScriptContext * ctx_;
};

template <typename Fn>
class ScriptObjectCall {};

template <>
class ScriptObjectCall<void (void)> : ScriptObjectCallBase {
  public:
    ScriptObjectCall(const char * decl, asIScriptObject * obj)
      : ScriptObjectCallBase(decl, obj) {}
      
    void operator()(void) {
      execute();
    }
};

template <typename R>
class ScriptObjectCall<R (void)> : ScriptObjectCallBase {
  public:
    ScriptObjectCall(const char * decl, asIScriptObject * obj)
      : ScriptObjectCallBase(decl, obj) {}
      
    R operator()(void) {
      execute();
      return static_cast<CallHelper<R> *>(return_address())->element;
    }
};

template <typename A0>
class ScriptObjectCall<void (A0)> : ScriptObjectCallBase {
  public:
    ScriptObjectCall(const char * decl, asIScriptObject * obj)
      : ScriptObjectCallBase(decl, obj) {}
      
    void operator()(A0 a0) {
      set_arg<A0>(0, a0);
      execute();
    }
};

template <typename R, typename A0>
class ScriptObjectCall<R (A0)> : ScriptObjectCallBase {
  public:
    ScriptObjectCall(const char * decl, asIScriptObject * obj)
      : ScriptObjectCallBase(decl, obj) {}
      
    R operator()(A0 a0) {
      set_arg<A0>(0, a0);
      execute();
      return static_cast<CallHelper<R> *>(return_address())->element;
    }
};

template <typename A0, typename A1>
class ScriptObjectCall<void (A0, A1)> : ScriptObjectCallBase {
  public:
    ScriptObjectCall(const char * decl, asIScriptObject * obj)
      : ScriptObjectCallBase(decl, obj) {}
      
    void operator()(A0 a0, A1 a1) {
      set_arg<A0>(0, a0);
      set_arg<A1>(1, a1);
      execute();
    }
};

template <typename R, typename A0, typename A1>
class ScriptObjectCall<R (A0, A1)> : ScriptObjectCallBase {
  public:
    ScriptObjectCall(const char * decl, asIScriptObject * obj)
      : ScriptObjectCallBase(decl, obj) {}
      
    R operator()(A0 a0, A1 a1) {
      set_arg<A0>(0, a0);
      set_arg<A1>(1, a1);
      execute();
      return static_cast<CallHelper<R> *>(return_address())->element;
    }
};

class ScriptMarshalHelper {
  public:
    ScriptMarshalHelper(asIScriptObject * obj) : obj_(obj) { obj->AddRef(); }
    ~ScriptMarshalHelper() { obj_->Release(); }
    
    template <typename T>
    ScriptObjectCall<T> call(const char * decl) {
      return ScriptObjectCall<T>(decl, obj_);
    }
  private:
    ScriptMarshalHelper(const ScriptMarshalHelper &);
    ScriptMarshalHelper & operator=(const ScriptMarshalHelper &);
    
    asIScriptObject * obj_;
};

//------------------------------------------------------------------------------
// Involved C++ classes

// Base interface
struct IFoo {
  virtual void bar(void) = 0;
  virtual int  baz(int a, int b) = 0;
  virtual ~IFoo() {}
};

// C++ implementation of interface
struct Foo : IFoo {
  int data;
  
  Foo(void) : data(0) {}
  Foo(int d) : data(d) {}
  Foo(const Foo & other) : data(other.data) {}
  Foo & operator=(const Foo & other) {
    data = other.data;
    return *this;
  }
  ~Foo() {}
  
  void bar(void) { std::cout << "Foo::bar() - " << data << std::endl; }
  int  baz(int a, int b) { return a + b; }
};

// C++ class for accessing script implementation of interface
struct FooScript : IFoo, ScriptMarshalHelper {
  FooScript(asIScriptObject * obj) : ScriptMarshalHelper(obj) {}

  void bar(void) {
    call<void (void)>("void bar()")();
  }
  int baz(int a, int b) {
    return call<int (int, int)>("int baz(int, int)")(a, b);
  }
};

//------------------------------------------------------------------------------
void construct_default(void * location) {
  new (location) Foo();
}

void construct_copy(const Foo & foo, void * location) {
  new (location) Foo(foo);
}

void construct_int(int data, void * location) {
  new (location) Foo(data);
}

void destroy(void * location) {
  static_cast<Foo *>(location)->~Foo();
}
//------------------------------------------------------------------------------

void MessageCallback(const asSMessageInfo *msg, void *param)
{
	const char *type = "ERR ";
	if( msg->type == asMSGTYPE_WARNING ) 
		type = "WARN";
	else if( msg->type == asMSGTYPE_INFORMATION ) 
		type = "INFO";

	printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
}

void PrintString(std::string & str) {
	std::cout << str;
}


int main(int, char **) {
  asIScriptEngine * engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
  engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);
  
  RegisterScriptString(engine);
  int r;
  
  r = engine->RegisterGlobalFunction("void print(string & in)", asFUNCTION(PrintString), asCALL_CDECL); assert( r >= 0 );
  
  // Register FooInner type
  r = engine->RegisterObjectType("FooInner", sizeof(Foo), asOBJ_VALUE | asOBJ_APP_CLASS_CDA); assert(r >= 0);
  r = engine->RegisterObjectBehaviour("FooInner", asBEHAVE_CONSTRUCT,  "void f()", asFUNCTION(construct_default), asCALL_CDECL_OBJLAST); assert(r >= 0);
  r = engine->RegisterObjectBehaviour("FooInner", asBEHAVE_CONSTRUCT,  "void f(const FooInner & in)", asFUNCTION(construct_copy), asCALL_CDECL_OBJLAST); assert(r >= 0);
  r = engine->RegisterObjectBehaviour("FooInner", asBEHAVE_CONSTRUCT,  "void f(int)", asFUNCTION(construct_int), asCALL_CDECL_OBJLAST); assert(r >= 0);
  r = engine->RegisterObjectBehaviour("FooInner", asBEHAVE_DESTRUCT,   "void f()", asFUNCTION(destroy), asCALL_CDECL_OBJLAST); assert(r >= 0);
  r = engine->RegisterObjectBehaviour("FooInner", asBEHAVE_ASSIGNMENT, "FooInner & f(const FooInner & in)", asMETHOD(Foo, operator =), asCALL_THISCALL); assert(r >= 0);
  r = engine->RegisterObjectMethod("FooInner", "void bar()", asMETHOD(Foo, bar), asCALL_THISCALL); assert(r >= 0);
  r = engine->RegisterObjectMethod("FooInner", "int baz(int, int)", asMETHOD(Foo, baz), asCALL_THISCALL); assert(r >= 0);
  r = engine->RegisterObjectProperty("FooInner", "int data", offsetof(Foo, data)); assert(r >= 0);
  
  // Create IFoo script interface
  r = engine->RegisterInterface("IFoo"); assert(r >= 0);
  r = engine->RegisterInterfaceMethod("IFoo", "void bar()"); assert(r >= 0);
  r = engine->RegisterInterfaceMethod("IFoo", "int baz(int, int)"); assert(r >= 0);

  const char script[] =
    // Foo base class for script classes
    "class Foo : IFoo {\n"
    "  FooInner inner;\n"
    "  Foo() {\n"
    "    inner = FooInner();\n"
    "  }\n"
    "  Foo(int data) {\n"
    "    inner = FooInner(data);\n"
    "  }\n"
    "  void bar() {\n"
    "    inner.bar();\n"
    "  }\n"
    "  int baz(int a, int b) {\n"
    "    return inner.baz(a, b);\n"
    "  }\n"
    "  int get_data() { return inner.data; }\n"
    "  void set_data(int data) { inner.data = data; }\n"
    "}\n"

    // Concrete foo class using inheritance from Foo
    "class CFoo1 : Foo {\n"
    "  void bar() {\n"
    "    print(\"CFoo1::bar()\\n\");\n"
    "  }\n"
    "  int baz(int a, int b) {\n"
    "    return Foo::baz(a, b) * 2;\n"
    "  }\n"
    "}\n"

    // Concrete foo class implementing IFoo
    "class CFoo2 : IFoo {\n"
    "  void bar() {\n"
    "    print(\"CFoo2::bar()\\n\");\n"
    "  }\n"
    "  int baz(int a, int b) {\n"
    "    return a * b;\n"
    "  }\n"
    "}\n"
    
    // Test all three in script
    "void main() {\n"

    "  Foo f1(3);\n"
    "  f1.bar();\n"
    "  print(f1.baz(6, 6) + \"\\n\");\n"

    "  CFoo1 f2;\n"
    "  f2.bar();\n"
    "  print(f2.baz(6, 6) + \"\\n\");\n"

    "  CFoo2 f3;\n"
    "  f3.bar();\n"
    "  print(f3.baz(6, 6) + \"\\n\");\n"

    "}\n"
  ;
    
  asIScriptModule * mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
  r = mod->AddScriptSection("script", script, sizeof(script) - 1); assert(r >= 0);
  r = mod->Build(); assert(r >= 0);

  int func_id = mod->GetFunctionIdByDecl("void main()"); assert(func_id >= 0);
  asIScriptContext * ctx = engine->CreateContext();

  r = ctx->Prepare(func_id); assert(r >= 0);
  r = ctx->Execute(); assert(r >= 0);

  ctx->Release();
  
  {
    // get IFoo for CFoo1
    int cfoo1_type_id = mod->GetTypeIdByDecl("CFoo1");
    asIScriptObject * f1 = static_cast<asIScriptObject *>(engine->CreateScriptObject(cfoo1_type_id));
    IFoo * cfoo1 = new FooScript(f1);
    cfoo1->bar();
    std::cout << cfoo1->baz(6, 6) << std::endl;
    delete cfoo1;
    f1->Release();
  } {
    // get IFoo for CFoo2
    int cfoo2_type_id = mod->GetTypeIdByDecl("CFoo2");
    asIScriptObject * f2 = static_cast<asIScriptObject *>(engine->CreateScriptObject(cfoo2_type_id));
    IFoo * cfoo2 = new FooScript(f2);
    cfoo2->bar();
    std::cout << cfoo2->baz(6, 6) << std::endl;
    delete cfoo2;
    f2->Release();
  }  

  engine->Release();
}



 User Rating: 2061   |  Rate This User  Send Private MessageView ProfileView JournalView GD Showcase Entries Report this Post to a Moderator | Link

Don't worry about the Foo abstraction, it wasn't to hard to follow. Although that proof of concept code did clarify the idea very well.

Anyway, I think that I'll stick with SiCrane's solution as it covers all of my needs. I hoped to work on inheritance from application registered classes from within AngelScript, but I think that's beyond the scope of my expertise. This topic wasn't in vain though, as a way for some sort of inheritance from application registered classes has been uncovered thanks to SiCrane.



.simplicity - blog | Sirrf - Simple Irrlicht Framework

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Yes, this thread has indeed given some valuable insights.

I've added a link to this thread on the angelscript.pbworks.com wiki for future reference when I'll put some more energy on investigating inheritance of application classes.


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


 User Rating: 1702   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

All times are ET (US)

Post Reply
 Last Thread Next Thread 
Forum Rules:
You may not post new threads
You may post replies
You may not edit your posts
You may not use HTML in your posts
Jump To:
Administrative Options: